├── JSONSerializers.py ├── LICENSE ├── MANIFEST.in ├── README.md ├── README.rst ├── __init__.py ├── admin.py ├── auth.py ├── cms_plugins.py ├── docs ├── Makefile ├── Screenshots │ └── about.gif ├── architecture.rst ├── conf.py ├── features.rst ├── fields.rst ├── index.rst ├── make.bat ├── starting.rst └── surveys.rst ├── fields.py ├── fieldtypes ├── CIField.py ├── CheckboxField.py ├── EmailField.py ├── Field.py ├── FieldFactory.py ├── FileField.py ├── GeoField.py ├── ListField.py ├── ModelField.py ├── NumberField.py ├── SelectField.py ├── TextAreaField.py ├── TextField.py ├── __init__.py ├── __pycache__ │ ├── CIField.cpython-34.pyc │ ├── CheckboxField.cpython-34.pyc │ ├── EmailField.cpython-34.pyc │ ├── Field.cpython-34.pyc │ ├── FieldFactory.cpython-34.pyc │ ├── FileField.cpython-34.pyc │ ├── GeoField.cpython-34.pyc │ ├── ListField.cpython-34.pyc │ ├── ModelField.cpython-34.pyc │ ├── NumberField.cpython-34.pyc │ ├── SelectField.cpython-34.pyc │ ├── TextAreaField.cpython-34.pyc │ ├── TextField.cpython-34.pyc │ ├── __init__.cpython-34.pyc │ └── field_type.cpython-34.pyc └── field_type.py ├── middlets.py ├── migrations ├── 0001_initial.py └── __init__.py ├── models.py ├── my.conf.js ├── permissions.py ├── serializers.py ├── setup.py ├── signals.py ├── static ├── __init__.py ├── angular │ ├── FileSaver.js │ ├── __init__.py │ ├── angular-charts.js │ ├── angular-charts.min.js │ ├── angular-file-upload-shim.js │ ├── angular-file-upload.js │ ├── angular-growl-notifications.min.js │ ├── angular-load.min.js │ ├── angular-mocks.js │ ├── angular-resource.min.js │ ├── angular-resource.min.js.map │ ├── angular-route.min.js │ ├── angular-sanitize.js │ ├── angular.js │ ├── angular.min.js │ ├── angular.min.js.map │ ├── bluebird.js │ ├── captcha.js │ ├── checklist-model.js │ ├── d3.js │ ├── d3.min.js │ ├── lodash.min.js │ ├── ng-csv.js │ └── sortable.js ├── bootstrap │ ├── __init__.py │ ├── css │ │ ├── __init__.py │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── sb-admin.css │ ├── fonts │ │ ├── __init__.py │ │ ├── font-awesome-4.1.0 │ │ │ ├── __init__.py │ │ │ ├── css │ │ │ │ ├── __init__.py │ │ │ │ ├── font-awesome.css │ │ │ │ └── font-awesome.min.css │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── __init__.py │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ └── fontawesome-webfont.woff │ │ │ ├── less │ │ │ │ ├── __init__.py │ │ │ │ ├── bordered-pulled.less │ │ │ │ ├── core.less │ │ │ │ ├── fixed-width.less │ │ │ │ ├── font-awesome.less │ │ │ │ ├── icons.less │ │ │ │ ├── larger.less │ │ │ │ ├── list.less │ │ │ │ ├── mixins.less │ │ │ │ ├── path.less │ │ │ │ ├── rotated-flipped.less │ │ │ │ ├── spinning.less │ │ │ │ ├── stacked.less │ │ │ │ └── variables.less │ │ │ └── scss │ │ │ │ ├── __init__.py │ │ │ │ ├── _bordered-pulled.scss │ │ │ │ ├── _core.scss │ │ │ │ ├── _fixed-width.scss │ │ │ │ ├── _icons.scss │ │ │ │ ├── _larger.scss │ │ │ │ ├── _list.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _path.scss │ │ │ │ ├── _rotated-flipped.scss │ │ │ │ ├── _spinning.scss │ │ │ │ ├── _stacked.scss │ │ │ │ ├── _variables.scss │ │ │ │ └── font-awesome.scss │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ │ ├── __init__.py │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── ui-bootstrap.min.js ├── css │ ├── __init__.py │ ├── fields │ │ ├── CIField.css │ │ ├── CheckboxField.css │ │ ├── EmailField.css │ │ ├── GeoField.css │ │ ├── NumberField.css │ │ ├── SelectField.css │ │ ├── TextAreaField.css │ │ ├── TextField.css │ │ └── __init__.py │ └── style.css ├── jquery │ ├── __init__.py │ ├── css │ │ ├── __init__.py │ │ └── jquery-ui.min.css │ └── js │ │ ├── __init__.py │ │ ├── jquery-2.1.3.min.js │ │ ├── jquery-2.1.3.min.map │ │ └── jquery-ui.min.js └── js │ ├── __init__.py │ ├── app.js │ ├── appVisor.js │ ├── editorCtrl.js │ ├── editorCtrl.js~ │ ├── fields │ ├── CIField.js │ ├── CheckboxField.js │ ├── EmailField.js │ ├── FieldBase.js │ ├── FieldFactory.js │ ├── FileField.js │ ├── GeoField.js │ ├── Matricula.js │ ├── ModelField.js │ ├── NumberField.js │ ├── SelectField.js │ ├── TextAreaField.js │ ├── TextField.js │ └── __init__.py │ ├── mainpageCtrl.js │ ├── operators │ ├── __init__.py │ ├── operatorChecks.js │ ├── operatorFactory.js │ ├── operatorField.js │ ├── operatorList.js │ └── operatorNumber.js │ ├── previewCtrl.js │ ├── responsesCtrl.js │ ├── services │ ├── resources.js │ └── visorResources.js │ ├── statisticsCtrl.js │ ├── validators │ ├── TextField.js │ ├── __init__.py │ └── validatorFactory.js │ ├── visorCtrl.js │ └── visorCtrl.js~ ├── statistics ├── CheckboxStatistics.py ├── ListStatistics.py ├── NumericStatistics.py ├── PieChart.py ├── StatisticsCtrl.py ├── StatisticsPdf.py ├── __init__.py ├── __pycache__ │ ├── CheckboxStatistics.cpython-34.pyc │ ├── ListStatistics.cpython-34.pyc │ ├── NumericStatistics.cpython-34.pyc │ ├── PieChart.cpython-34.pyc │ ├── StatisticsCtrl.cpython-34.pyc │ ├── StatisticsPdf.cpython-34.pyc │ ├── __init__.cpython-34.pyc │ └── serializers.cpython-34.pyc └── serializers.py ├── templates ├── 404.html ├── 500.html ├── __init__.py ├── asset_block_template.html ├── base.html ├── captcha_template.html ├── cms_base.html ├── cms_template.html ├── editor.html ├── field_condition.html ├── fields │ ├── __init__.py │ ├── checkbox │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ ├── template_edit.html │ │ └── template_statistic.html │ ├── combobox │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ ├── template_edit.html │ │ └── template_statistic.html │ ├── email │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html │ ├── field_edit_template_base.html │ ├── field_properties_base.html │ ├── field_template_base.html │ ├── file │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html │ ├── geolocation │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html │ ├── identity_doc │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html │ ├── number │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ ├── template_edit.html │ │ └── template_statistic.html │ ├── text │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html │ └── text_area │ │ ├── __init__.py │ │ ├── properties.html │ │ ├── template.html │ │ └── template_edit.html ├── form_submitted.html ├── hello_plugin.html ├── logic_modal.html ├── logic_page_modal.html ├── login.html ├── mainPage.html ├── mainPage.html~ ├── modifyInput.html ├── palette.html ├── post_submit_modal.html ├── preview.html ├── preview_template.html ├── responses.html ├── select_modal.html ├── statistics.html ├── tooltip_modal.html ├── versions.html ├── visor.html ├── visor_cms.html └── visor_template.html ├── templatetags ├── __init__.py ├── load_fields_assets.py └── visor_tag.py ├── testing ├── editor_test.js ├── mainPage_test.js ├── statisticsCntlTest.js └── visor_tests.js ├── urls.py └── views.py /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | global-include *.py 4 | recursive-include pulpo_forms/static * 5 | recursive-include pulpo_forms/templates * 6 | recursive-include pulpo_forms/testing * -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Pulpo Forms 3 | =========== 4 | 5 | Pulpo Forms is a Django app capable of creating powerful surveys with many different field types, multi path logic for fields and pages and statistical analysis of responses. 6 | 7 | Quick Start 8 | ----------- 9 | 10 | 1. Add ``'pulpo_forms'`` to the ``INSTALLED_APPS`` of your project's settings:: 11 | 12 | INSTALLED_APPS = ( 13 | # other apps 14 | 'pulpo_forms', 15 | ) 16 | 17 | Add the ``FIELD_FILES`` to your project's settings to include the provided fields, plus any other field defined in another app:: 18 | 19 | FIELD_FILES = ( 20 | 'pulpo_forms.fieldtypes.TextField', 21 | 'pulpo_forms.fieldtypes.TextAreaField', 22 | 'pulpo_forms.fieldtypes.EmailField', 23 | 'pulpo_forms.fieldtypes.CheckboxField', 24 | 'pulpo_forms.fieldtypes.SelectField', 25 | 'pulpo_forms.fieldtypes.GeoField', 26 | 'pulpo_forms.fieldtypes.NumberField', 27 | 'pulpo_forms.fieldtypes.CIField', 28 | 'pulpo_forms.fieldtypes.FileField', 29 | 'other_app.fields', 30 | ) 31 | 32 | * Add ``'pulpo_forms.middlets.ValidationErrorToHttpErrorMiddleware'`` to the ``MIDDLEWARE_CLASSES`` of your project's settings:: 33 | 34 | MIDDLEWARE_CLASSES = ( 35 | # other 36 | 'pulpo_forms.middlets.ValidationErrorToHttpErrorMiddleware', 37 | ) 38 | 39 | * Define the base url you want and add it to your project's settings:: 40 | 41 | FORMS_BASE_URL = '' 42 | 43 | * To configure the mail service the following variables must be defined in your settings file as well:: 44 | 45 | EMAIL_HOST = <'MAIL_SERVER'> 46 | EMAIL_HOST_USER = <'MAIL_ACCOUNT'> 47 | EMAIL_HOST_PASSWORD = <'MAIL_PASSWORD'> 48 | EMAIL_PORT = 49 | EMAIL_USE_TLS = True 50 | 51 | * In your project's ``urls.py`` add:: 52 | 53 | urlpatterns = patterns('', 54 | # other patterns 55 | url(r'^/', include('pulpo_forms.urls'), name='base'), 56 | ) 57 | 58 | * Run `python manage.py migrate` to create the app models -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/__init__.py -------------------------------------------------------------------------------- /admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from pulpo_forms.models import Form, FieldEntry, FormEntry, Version 4 | 5 | 6 | # Register your models here. 7 | admin.site.register(Form) 8 | admin.site.register(FieldEntry) 9 | admin.site.register(FormEntry) 10 | admin.site.register(Version) 11 | -------------------------------------------------------------------------------- /auth.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse, HttpResponseRedirect 2 | from django.contrib.auth import authenticate, login, logout 3 | from django.shortcuts import render_to_response 4 | from django.template.context import RequestContext 5 | from django.contrib.auth.decorators import login_required 6 | from django.conf import settings 7 | 8 | 9 | def user_login(request): 10 | # Get context for the user's request 11 | context = RequestContext(request) 12 | 13 | if request.user.is_authenticated(): 14 | return HttpResponseRedirect(settings.FORMS_BASE_URL + "main/") 15 | if request.method == 'POST': 16 | # Get data from login form 17 | username = request.POST['username'] 18 | password = request.POST['password'] 19 | # Check if user is valid 20 | _user = authenticate(username=username, password=password) 21 | 22 | # If there is a user object, its correct 23 | # If None, no user with matching data was found 24 | if _user: 25 | if _user.is_active: 26 | # Login and send user to mainpage 27 | login(request, _user) 28 | return HttpResponseRedirect(settings.FORMS_BASE_URL + "main/") 29 | else: 30 | # An inactive account was used- no login in. 31 | return HttpResponse("Your account is disabled.") 32 | else: 33 | # Bad login 34 | return render_to_response('login.html', {'error': True}, context) 35 | else: 36 | # Method wasnt POST 37 | return render_to_response('login.html', {"error": False}, context) 38 | 39 | 40 | @login_required 41 | def user_logout(request): 42 | # Since we know the user is logged in, we can now just log them out. 43 | logout(request) 44 | 45 | # Take the user back to the homepage. 46 | return HttpResponseRedirect(settings.FORMS_BASE_URL + 'login/') 47 | -------------------------------------------------------------------------------- /cms_plugins.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | from cms.plugin_pool import plugin_pool 5 | from cms.plugin_base import CMSPluginBase 6 | 7 | from .models import Survey 8 | 9 | class SurveyPlugin(CMSPluginBase): 10 | model = Survey 11 | name = _("Survey Plugin") 12 | render_template = "visor_cms.html" 13 | 14 | def render(self, context, instance, placeholder): 15 | context['instance'] = instance 16 | context['base_url'] = settings.FORMS_BASE_URL 17 | return context 18 | 19 | plugin_pool.register_plugin(SurveyPlugin) 20 | -------------------------------------------------------------------------------- /docs/Screenshots/about.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/docs/Screenshots/about.gif -------------------------------------------------------------------------------- /docs/architecture.rst: -------------------------------------------------------------------------------- 1 | Architecture 2 | ============ 3 | 4 | General description 5 | ------------------- 6 | 7 | The system has two main modules: 8 | 9 | * One, developed in **Python** using the MTV (Model-Template-View) framework **Django**. 10 | * The other, developed in javascript using the MVC (Model-View-Controller) framework **AngularJS**. 11 | 12 | The Python module handles the application logic. This will be run in a web server based on HTTP requests from a web browser. The app will run the necessary processes, making the required queries to a database, and returning the appropriate response to the web browser. 13 | The Python/Django application handles this responses besides the possibility of creating new content, which will be stored in the database. 14 | 15 | On the other side, the Angular application makes the HTTP requests to the server, and once it has the response, it displays its content, controlling the different aspects of said presentation based on the application logic. 16 | 17 | 18 | Database 19 | -------- 20 | 21 | The database uses six tables to store all the necessary data for the system to work properly. This are: 22 | 23 | **dynamicForms_fieldentry** 24 | Stores the information the responses of each field in a survey. This includes the id within the given survey, its type, whether it’s a required field or if it was shown, depending on the multi path logic defined in the form. 25 | 26 | **dynamicForms_fileentry** 27 | Stores the information of a particular field, the File field. This table stores information about the uploaded file, such as the file type, the name and a reference to the corresponding FieldEntry. 28 | 29 | **dynamicForms_form** 30 | Stores the general information of each survey, like its title, slug, id and its owner. 31 | 32 | **dynamicForms_formentry** 33 | Stores the entries for the versions of each of the forms. For this reason, it keeps a reference to the corresponding version, and the time when the entry was submitted. 34 | 35 | **dynamicForms_survey** 36 | Stores each instance of a form created as a plugin to be included in DjangoCMS application. 37 | 38 | **dynamicForms_version** 39 | Keeps the information of the structure of the versions, such as its state, publication and expiration date, whether it uses a captcha, and a JSON containing the survey’s structure. 40 | 41 | JSON 42 | ---- 43 | 44 | This JSON contains the structure and the information of the version of a form. The JSON will be interpreted on the front-end and generate the saved survey using the necessary templates so that the final user can complete it. 45 | 46 | An example of a JSON:: 47 | 48 | { 49 | "pages": [{ 50 | "subTitle": "", 51 | "fields": [{ 52 | "field_id": 1, 53 | "validations": { 54 | "max_len_text": 255 55 | }, 56 | "text": "Text", 57 | "tooltip": "", 58 | "dependencies": { 59 | "fields": [], 60 | "pages": [] 61 | }, 62 | "required": false, 63 | "answer": [], 64 | "field_type": "TextField" 65 | }] 66 | }], 67 | "logic": { 68 | "fields": {}, 69 | "pages": {} 70 | } 71 | } 72 | 73 | The main structure of the JSON has two parts: **pages** and **logic**. The first one contains the fields, their ids, configuration such as maximum or minimum length of the text and also the logic dependencies of other fields. The second part contains the multipath logic configuration of the survey. Separated by field or pages the logic condition that hides or show one of those items. 74 | 75 | -------------------------------------------------------------------------------- /docs/features.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | Features 5 | -------- 6 | 7 | Dynamic Forms provides several useful functionalities and characteristics for survey creation. 8 | 9 | * Tools for creating, editing and modifying of surveys. 10 | * Support for multiple versions of a survey. 11 | * User-friendly and responsive web interface for the completion of the surveys. 12 | * Support for multi page surveys. 13 | * Multiple field types, such as: 14 | 15 | * Numeric 16 | * Single Text Line 17 | * Text Area 18 | * Single Response List 19 | * Multiple Response List 20 | * E-mail 21 | * Map 22 | * File 23 | 24 | * The possibility to show or hide a question (field) depending on the answer of one or more other fields. 25 | * The possibility of showing and hiding whole pages depending on the answer of one or more fields. 26 | * Custom validations for each of the different field types. 27 | * Statistical data from the responses to the surveys. 28 | * Export of responses as CSV. 29 | * Export of statistics in PDF format. 30 | * Inclusion of surveys as Django-CMS plugins. 31 | * QuerySets for response analisis. 32 | * Use of Django-Signals at the occurrence of certain events. 33 | * Customizable actions to determine what happens after a survey is completed (e.g.: Sending an email to the administrator). 34 | * Captcha support. 35 | 36 | Requirements 37 | ------------ 38 | 39 | * Python 3.4 40 | * Django 1.6 41 | * AngularJS v1.3.0 42 | -------------------------------------------------------------------------------- /docs/fields.rst: -------------------------------------------------------------------------------- 1 | Fields 2 | ====== 3 | 4 | Field components 5 | ---------------- 6 | 7 | Each of the field types that belong to this framework has the following components: 8 | 9 | **Python class** 10 | Each field type must have a Python class. This class must extend the abstract class ``Field`` (implemented in ``dynamicForms.fieldtypes.Field.py``) or one of its subclasses. 11 | This class will contain all the methods associated to this field type like validations, statistics operations, etc. It will also contain the paths to the HTML templates and JavaScript/CSS files associated with this field type. 12 | 13 | **JavaScript files** 14 | Each field type might need up to 3 JavaScript files: 15 | 16 | - JSON constructor 17 | 18 | Located in the folder ``static/js/fields``. This file must be provided and must contain a class that extends ``FieldBase``, which contains the fields attributes. 19 | 20 | - Operator 21 | 22 | Located in ``static/js/operators``. This file is needed only if this field type includes operators for the multipath logic. 23 | Contains a class that extends ``OperatorField``. 24 | All the methods defined in this class will be listed as available operators. 25 | 26 | - Validator 27 | 28 | Located in ``static/js/validators``. This file is necessary only if this field needs extra validation in the Front-End. 29 | 30 | **HTML Templates** 31 | Each field type must have defined 3 templates which will normally live under ``templates/fields//``, there is an extra template for fields that have statistics analysis. 32 | 33 | - ``properties.html`` 34 | 35 | Generates the validation options for this field type in the editor’s panel. Extends ``field_properties_base.html`` 36 | - ``template.html`` 37 | 38 | Contains the HTML code for this field to be shown to the final user to complete a survey. Extends ``field_template_base.html.`` 39 | - ``template_edit.html`` 40 | 41 | Contains the HTML code for this field to be shown in the editor page. Extends ``field_edit_template_base.html``. 42 | 43 | - ``template_statistic.html`` 44 | 45 | Contains the HTML code for this field to be shown in the statictis page. 46 | 47 | **CSS** 48 | Located in ``static/css/fields``. 49 | Contains the styles for the fields and will be used by the ``template.html`` mentioned before. 50 | 51 | Factory 52 | ------- 53 | 54 | To load all the defined field types dynamically the app uses factories in Front- and Back-End. 55 | 56 | This means that for a new field type to be supported, it has to be registered in these factories. Additionally it has to be registered using the same identifying name in both and without using one of the previously used identifiers. Conventionally the identifier will be the same as the class name (e.g. ``NumberField``, ``DecimalField``). 57 | 58 | 59 | Creating a new field type 60 | ------------------------- 61 | 62 | It is pretty easy to define a new type of field. Basically, it consists in creating the necessary components detailed in **Field Components**. 63 | And add a line to the settings of your project:: 64 | 65 | FIELD_FILES=( 66 | #other fields, 67 | 68 | ) 69 | 70 | Model field 71 | --------------- 72 | 73 | Dynamic Forms supports adding the items of models of other applications as combobox options. This is called ``ModelField``. 74 | For this to work it is necessary to define a new field type that extends the abstract class ``ModelField`` and which sets the *model* attribute to the model class whose items shall be shown. 75 | 76 | .. note:: 77 | 78 | It is not yet supported to filter this items. It should also have a JavaScript constructor class but just needs to redefine the properties.html template to show the correct name. -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Dynamic-Forms 3 | ============= 4 | 5 | About 6 | ===== 7 | 8 | Dynamic Forms is a framework developed on Python-Django made for the creation 9 | of surveys supporting multipaging and multipath. This means it supports the 10 | creation of pages and the definition of a question path logic that determines 11 | if a question has to be shown or hidden. The aforementioned surveys are created 12 | on a user-friendly webpage tested on Google Chrome, Mozilla Firefox and Internet 13 | Explorer. 14 | The development of this application focused on being extensible so that the creation 15 | and/or modification of new types of questions (fields) could be done easily. 16 | 17 | Contents 18 | ======== 19 | 20 | .. toctree:: 21 | :maxdepth: 2 22 | 23 | features 24 | starting 25 | surveys 26 | fields 27 | architecture 28 | 29 | -------------------------------------------------------------------------------- /docs/starting.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =============== 3 | 4 | Installation 5 | ------------ 6 | 7 | * Install Dynamic Forms with the Python package manager:: 8 | 9 | pip install dynamic-forms 10 | 11 | Settings 12 | -------- 13 | 14 | * Add ``'dynamicForms'`` to the ``INSTALLED_APPS`` of your project's settings:: 15 | 16 | INSTALLED_APPS = ( 17 | # other apps 18 | 'dynamicForms', 19 | ) 20 | 21 | * Add ``'dynamicForms.middlets.ValidationErrorToHttpErrorMiddleware'`` to the ``MIDDLEWARE_CLASSES`` of your project's settings:: 22 | 23 | MIDDLEWARE_CLASSES = ( 24 | # other 25 | 'dynamicForms.middlets.ValidationErrorToHttpErrorMiddleware', 26 | ) 27 | 28 | * Define the base url you want and add it to your project's settings:: 29 | 30 | FORMS_BASE_URL = '' 31 | 32 | * To configure the mail service the following variables must be defined in your settings file as well:: 33 | 34 | EMAIL_HOST = <'MAIL_SERVER'> 35 | EMAIL_HOST_USER = <'MAIL_ACCOUNT'> 36 | EMAIL_HOST_PASSWORD = <'MAIL_PASSWORD'> 37 | EMAIL_PORT = 38 | EMAIL_USE_TLS = True 39 | 40 | * Finally, in your project's ``urls.py`` add:: 41 | 42 | # other imports 43 | import dynamicForms 44 | 45 | urlpatterns = patterns('', 46 | # other patterns 47 | url(r'^/', include('dynamicForms.urls'), name='base'), 48 | ) 49 | -------------------------------------------------------------------------------- /docs/surveys.rst: -------------------------------------------------------------------------------- 1 | Surveys 2 | ======= 3 | 4 | Creating a new Survey 5 | --------------------- 6 | 7 | * Go to the defined base url and login with a Django Admin user. 8 | * Once logged in press the link “*New Form*” on the left menu of the page. You will be redirected to the Editor page. 9 | * Choose a title for this survey. The title will generate a slug which will identify the survey so it must be unique in the system. 10 | * On the Editor you will be able to create and modify the surveys before publishing them. For this purpose there is a panel on the right hand side of the page, with three tabs. 11 | 12 | * The first one is named "Palette" and lets you insert new fields (questions) to the survey. 13 | * The second one is for setting the properties of the fields. The properties will vary depending on the type of the field you are editing. 14 | * Last but not least, the third tab is the configuration tab. Among the options here are: enabling the use of a captcha, selecting the actions to be realized when a survey is completed and configuring the logic that determines if a field or page is shown or hidden. 15 | 16 | * Once the desired modifications have been done click on 'Save' or 'Publish'. 17 | * On the main page you will now see listed the newly created survey. 18 | 19 | States of a survey 20 | ^^^^^^^^^^^^^^^^^^ 21 | 22 | A survey might have several versions, with each version being in one of the following states: 23 | 24 | **Draft** 25 | Version is being edited and cannot be filled yet. It still can be modified in the Editor page. 26 | 27 | **Published** 28 | This is the currently published version. It cannot be modified and this is the version which will be shown when someone wants to complete the survey. In addition, you can see the responses and statistics of this version. 29 | 30 | **Expired** 31 | This version was published but has now been replaced by a new version. You can still see statistic and responses of this versions. 32 | 33 | Completing a survey 34 | ------------------- 35 | 36 | To complete or fill a survey it has to be displayed on a web page. Currently, there are 3 ways to do this. 37 | 38 | **URL** 39 | The survey can be mapped to a specific URL using the view "render_form". 40 | It is just necessary to add the following line to the ``urls.py`` file of your project:: 41 | 42 | url(r'^/$','dynamicForms.views.render_form',{'instance':''}), 43 | 44 | **TAG** 45 | You can include the survey in any webpage using a Django Tag. It is necessary to load the Tag before calling it:: 46 | 47 | {%load visor_tag%} 48 | 49 | {%visor_template_tag "" %} 50 | 51 | 52 | **Django CMS** 53 | The survey can be embedded as a Django-CMS plugin into any existing CMS page. 54 | 55 | Restrictions 56 | ^^^^^^^^^^^^ 57 | 58 | .. warning:: 59 | Multipath logic has very few consistency checks so the user that generates the surveys will be responsible for creating a consistent logic. 60 | 61 | .. warning:: 62 | Due to restrictions of the technologies used, you cannot put more than one survey on a single webpage. 63 | -------------------------------------------------------------------------------- /fields.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.core.serializers.json import DjangoJSONEncoder 3 | from django.db import models 4 | from django.utils.translation import ugettext_lazy as _ 5 | 6 | # from south.modelsinspector import add_introspection_rules 7 | 8 | 9 | # Form status constants 10 | DRAFT = 0 11 | PUBLISHED = 1 12 | EXPIRED = 2 13 | # These are the possible status for a form 14 | STATUS = ( 15 | (DRAFT, _("Draft")), 16 | (PUBLISHED, _("Published")), 17 | (EXPIRED, _("Expired")), 18 | ) 19 | 20 | # add_introspection_rules([], ["^pulpo_forms.fields.JSONField"]) 21 | 22 | 23 | class JSONField(models.TextField): 24 | """ 25 | JSONField is a generic textfield that neatly serializes/unserializes 26 | JSON objects seamlessly 27 | """ 28 | # Used so to_python() is called 29 | __metaclass__ = models.SubfieldBase 30 | 31 | def to_python(self, value): 32 | """ 33 | Convert our string value to JSON after we load it from the DB 34 | """ 35 | if value == "": 36 | return "" 37 | 38 | try: 39 | if isinstance(value, str): 40 | return json.loads(value) 41 | except ValueError: 42 | pass 43 | 44 | return "" 45 | 46 | def get_db_prep_save(self, value, connection, prepared=False): 47 | """ 48 | Convert our JSON object to a string before we save 49 | """ 50 | 51 | if isinstance(value, dict): 52 | value = json.dumps(value, cls=DjangoJSONEncoder) 53 | 54 | return super(JSONField, self).get_db_prep_save(value, connection) 55 | 56 | 57 | class Validations(): 58 | """ 59 | Class for validation objects of the versions json 60 | """ 61 | max_len_text = models.IntegerField(blank=True) 62 | max_number = models.IntegerField(blank=True) 63 | min_number = models.IntegerField(blank=True) 64 | 65 | def valid_number(self): 66 | if ((self.max_number is not None) 67 | and (self.min_number is not None)): 68 | return self.max_number >= self.min_number 69 | return True 70 | 71 | def valid_text(self): 72 | if self.max_len_text is not None: 73 | return self.max_len_text > 0 74 | 75 | def __init__(self): 76 | self.max_len_text = None 77 | self.max_number = None 78 | self.min_number = None 79 | 80 | 81 | class Option(): 82 | label = models.CharField(blank=True, max_length=100) 83 | id = models.IntegerField(blank=True) 84 | 85 | 86 | class Dependencies(): 87 | fields = models.CommaSeparatedIntegerField( 88 | null=True, blank=True, max_length=300) 89 | pages = models.CommaSeparatedIntegerField( 90 | null=True, blank=True, max_length=300) 91 | 92 | 93 | class Field_Data(): 94 | text = models.CharField(null=True, blank=True, max_length=500) 95 | required = models.BooleanField() 96 | tooltip = models.CharField(blank=True, max_length=300) 97 | answer = models.CharField(blank=True, max_length=400) 98 | dependencies = Dependencies() 99 | validations = Validations() 100 | options = [] 101 | max_id = models.IntegerField(blank=True) 102 | field_type = models.CharField(blank=True, max_length=30) 103 | field_id = models.IntegerField(blank=True) 104 | 105 | 106 | class AfterSubmit(object): 107 | sendMail = models.BooleanField() 108 | action = models.CharField() 109 | mailSubject = models.CharField() 110 | mailText = models.CharField() 111 | mailSender = models.CharField() 112 | mailRecipient = models.CharField() 113 | message = models.CharField() 114 | redirect = models.CharField() 115 | 116 | def __init__(self, sendMail, action, mailSubject, mailText, mailSender, 117 | mailRecipient, message, redirect): 118 | self.sendMail = sendMail 119 | self.action = action 120 | self.mailSubject = mailSubject 121 | self.mailText = mailText 122 | self.mailSender = mailSender 123 | self.mailRecipient = mailRecipient 124 | self.message = message 125 | self.redirect = redirect 126 | -------------------------------------------------------------------------------- /fieldtypes/CIField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes import Field 4 | from pulpo_forms.fieldtypes import FieldFactory 5 | 6 | 7 | class CIField(Field.Field): 8 | """ 9 | CI field type class 10 | """ 11 | template_name = "identity_doc/template.html" 12 | edit_template_name = "identity_doc/template_edit.html" 13 | prp_template_name = "identity_doc/properties.html" 14 | 15 | def check_id(self, value, **kwargs): 16 | digits = [int(i) for i in value] 17 | # If value has less than 8 digits, we complete with zeros on the left 18 | if len(digits) < 8: 19 | diff = 8 - len(digits) 20 | for x in range(0, diff): 21 | digits.insert(0, 0) 22 | 23 | const = [2, 9, 8, 7, 6, 3, 4] 24 | value = 0 25 | for x in range(0, 7): 26 | value += digits[x] * const[x] 27 | m = value % 10 28 | if ((10 - m) % 10) != digits[len(digits) - 1]: 29 | raise ValidationError('Enter a valid ID.', code='invalid') 30 | 31 | def get_methods(self, **kwargs): 32 | # Default validation or pass 33 | base = super(CIField, self).get_methods(**kwargs) 34 | base.extend([self.int_check, self.check_id]) 35 | return base 36 | 37 | def int_check(self, value, **kwargs): 38 | try: 39 | int(value) 40 | except (ValueError, TypeError): 41 | raise ValidationError('Enter a valid integer.', code='invalid') 42 | 43 | def get_assets(): 44 | return ['js/fields/CIField.js'] 45 | 46 | def get_styles(): 47 | return ['css/fields/CIField.css'] 48 | 49 | def __str__(self): 50 | return "Cedula" 51 | 52 | 53 | FieldFactory.FieldFactory.register('CIField', CIField) 54 | -------------------------------------------------------------------------------- /fieldtypes/CheckboxField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes.ListField import ListField 4 | from pulpo_forms.fieldtypes import FieldFactory 5 | from pulpo_forms.statistics.CheckboxStatistics import CheckboxStatistics 6 | 7 | 8 | class CheckboxField(ListField): 9 | """ 10 | Checkbox field validator, render and analize methods 11 | """ 12 | template_name = "checkbox/template.html" 13 | edit_template_name = "checkbox/template_edit.html" 14 | prp_template_name = "checkbox/properties.html" 15 | sts_template_name = "checkbox/template_statistic.html" 16 | 17 | def get_statistics(self, data_list, field): 18 | checkbox_statistics = CheckboxStatistics(data_list, field["options"]) 19 | statistics = checkbox_statistics.getSerializedData() 20 | statistics["field_text"] = field["text"] 21 | statistics["field_type"] = field["field_type"] 22 | if field["required"]: 23 | statistics["required"] = "Yes" 24 | else: 25 | statistics["required"] = "No" 26 | return statistics 27 | 28 | def belong_check(self, value, **kwargs): 29 | opt = kwargs['options'] 30 | l = [] 31 | for o in opt: 32 | l.append(o['id']) 33 | for v in value.split('#'): 34 | v = int(v) 35 | if v not in l: 36 | raise ValidationError("Invalid value, not among options.") 37 | 38 | def get_assets(): 39 | return [ 40 | 'js/fields/CheckboxField.js', 41 | 'js/operators/operatorList.js', 42 | 'js/operators/operatorChecks.js' 43 | ] 44 | 45 | def get_styles(): 46 | return ['css/fields/CheckboxField.css'] 47 | 48 | def __str__(self): 49 | return "Checkbox" 50 | 51 | 52 | FieldFactory.FieldFactory.register('CheckboxField', CheckboxField) 53 | -------------------------------------------------------------------------------- /fieldtypes/EmailField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | from django.core.validators import validate_email 3 | 4 | from pulpo_forms.fieldtypes import TextField 5 | from pulpo_forms.fieldtypes import FieldFactory 6 | 7 | 8 | class EmailField(TextField.TextField): 9 | """ 10 | Email validator using django's validation 11 | """ 12 | template_name = "email/template.html" 13 | edit_template_name = "email/template_edit.html" 14 | prp_template_name = "email/properties.html" 15 | 16 | def mail_check(self, value, **kwargs): 17 | try: 18 | validate_email(value) 19 | except ValidationError as e: 20 | # Transform the message to be cathed later. 21 | raise ValidationError(e.__str__()) 22 | 23 | def get_methods(self, **kwargs): 24 | base = super(EmailField, self).get_methods(**kwargs) 25 | base.append(self.mail_check) 26 | return base 27 | 28 | def get_assets(): 29 | return ['js/fields/EmailField.js'] 30 | 31 | def get_styles(): 32 | return ['css/fields/EmailField.css'] 33 | 34 | def __str__(self): 35 | return "Email" 36 | 37 | FieldFactory.FieldFactory.register('EmailField', EmailField) 38 | -------------------------------------------------------------------------------- /fieldtypes/Field.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.models import Version, FieldEntry 4 | 5 | 6 | class Field(object): 7 | """ 8 | Default abstract field type class 9 | """ 10 | folder = "fields/" 11 | template_name = "field_template_base.html" 12 | edit_template_name = "fiel_template_edit_base.html" 13 | prp_template_name = "field_properties_base.html" 14 | 15 | def validate(self, value, **kwargs): 16 | # Default validation or pass 17 | checks = self.get_methods(**kwargs) 18 | for method in checks: 19 | method(value, **kwargs) 20 | 21 | def get_methods(self, **kwargs): 22 | return [self.null_check] 23 | 24 | def null_check(self, value, **kwargs): 25 | if not value: 26 | raise ValidationError("Problem with the answer.") 27 | 28 | def get_validations(self, json, f_id): 29 | for page in json['pages']: 30 | for field in page['fields']: 31 | if (field['field_id'] == f_id): 32 | return field['validations'] 33 | 34 | def get_options(self, json, f_id): 35 | return None 36 | 37 | def check_consistency(self, field): 38 | # When a field is created check if the restrictions are consistent 39 | pass 40 | 41 | def count_responses_pct(self, form_pk, version_num, field_id): 42 | v = Version.objects.get(number=version_num, form_id=form_pk) 43 | queryset = FieldEntry.objects.filter( 44 | field_id=field_id, entry__version_id=v.pk) 45 | total = queryset.count() 46 | responses = total - queryset.filter(answer="").count() 47 | return (responses, total) 48 | 49 | def get_statistics(self, data_list, field): 50 | """ 51 | Returns a the statistics related to the data list. 52 | """ 53 | statistics = { 54 | "field_type": field["field_type"], 55 | "field_text": field["text"] 56 | } 57 | if field["required"]: 58 | statistics["required"] = "Yes" 59 | else: 60 | statistics["required"] = "No" 61 | return statistics 62 | 63 | def get_assets(): 64 | return [] 65 | 66 | def get_non_static(): 67 | return [] 68 | 69 | def get_styles(): 70 | return [] 71 | 72 | """ 73 | Default Render methods for field templates 74 | """ 75 | def render(self): 76 | return self.folder + self.template_name 77 | 78 | def render_properties(self): 79 | return self.folder + self.prp_template_name 80 | 81 | def render_edit(self): 82 | return self.folder + self.edit_template_name 83 | 84 | def render_statistic(self): 85 | return self.folder + self.sts_template_name 86 | 87 | class Meta: 88 | abstract = True 89 | -------------------------------------------------------------------------------- /fieldtypes/FieldFactory.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | 4 | class FieldFactory(): 5 | """ 6 | Factory 7 | """ 8 | fields = {} 9 | 10 | def get_class(id): 11 | return FieldFactory.fields[id] 12 | 13 | def get_all_classes(): 14 | return FieldFactory.fields.values() 15 | 16 | def register(id, type): 17 | if id not in FieldFactory.fields: 18 | FieldFactory.fields[id] = type 19 | else: 20 | raise ValidationError("invalid ID.") 21 | 22 | def get_strings(): 23 | l = {} 24 | for key in FieldFactory.fields: 25 | l[key] = FieldFactory.fields[key]().__str__() 26 | return l 27 | -------------------------------------------------------------------------------- /fieldtypes/FileField.py: -------------------------------------------------------------------------------- 1 | from pulpo_forms.fieldtypes import Field 2 | from pulpo_forms.fieldtypes import FieldFactory 3 | 4 | 5 | class FileField(Field.Field): 6 | """ 7 | Text field validator, render and analize methods 8 | """ 9 | template_name = "file/template.html" 10 | edit_template_name = "file/template_edit.html" 11 | prp_template_name = "file/properties.html" 12 | 13 | def get_assets(): 14 | return ['js/fields/FileField.js'] 15 | 16 | def __str__(self): 17 | return "FileField" 18 | 19 | 20 | FieldFactory.FieldFactory.register('FileField', FileField) 21 | -------------------------------------------------------------------------------- /fieldtypes/GeoField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes import Field 4 | from pulpo_forms.fieldtypes import FieldFactory 5 | 6 | 7 | class GeoField(Field.Field): 8 | """ 9 | GeoField 10 | """ 11 | template_name = "geolocation/template.html" 12 | edit_template_name = "geolocation/template_edit.html" 13 | prp_template_name = "geolocation/properties.html" 14 | 15 | def geo_check(self, value, **kwargs): 16 | try: 17 | v = value.split('#') 18 | lat = float(v[0]) 19 | if not (lat >= -90 and lat <= 90): 20 | raise ValidationError("Invalid latitude coordinate.") 21 | lon = float(v[1]) 22 | if not (lon >= -180 and lon <= 180): 23 | raise ValidationError("Invalid longitude coordinates.") 24 | 25 | except ValidationError as e: 26 | # Transform the message to be cathed later. 27 | raise ValidationError(e.__str__()) 28 | 29 | def get_methods(self, **kwargs): 30 | base = super(GeoField, self).get_methods(**kwargs) 31 | base.append(self.geo_check) 32 | return base 33 | 34 | def get_assets(): 35 | return ['js/fields/GeoField.js'] 36 | 37 | def get_non_static(): 38 | return ['https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false'] 39 | 40 | def get_styles(): 41 | return ['css/fields/GeoField.css'] 42 | 43 | def __str__(self): 44 | return "GeoLocation" 45 | 46 | FieldFactory.FieldFactory.register('GeoField', GeoField) 47 | -------------------------------------------------------------------------------- /fieldtypes/ListField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes.Field import Field 4 | from pulpo_forms.statistics.ListStatistics import ListStatistics 5 | 6 | 7 | class ListField(Field): 8 | """ 9 | List field validator, render and analize methods 10 | """ 11 | 12 | def get_methods(self, **kwargs): 13 | base = super(ListField, self).get_methods(**kwargs) 14 | base.append(self.belong_check) 15 | return base 16 | 17 | def belong_check(self, value, **kwargs): 18 | v = int(value) 19 | opt = kwargs['options'] 20 | l = [] 21 | for o in opt: 22 | l.append(o['id']) 23 | if v not in l: 24 | raise ValidationError("Invalid value, not among options.") 25 | 26 | def check_consistency(self, field): 27 | options = field.options 28 | if (options == []): 29 | raise ValidationError("List fields need at least one option.") 30 | 31 | def get_option_labels(self, field): 32 | return field["options"] 33 | 34 | def get_statistics(self, data_list, field): 35 | options = self.get_option_labels(field) 36 | list_statistics = ListStatistics(data_list, options) 37 | statistics = super(ListField, self).get_statistics(data_list, field) 38 | statistics.update(list_statistics.getSerializedData()) 39 | return statistics 40 | 41 | def get_options(self, json, f_id): 42 | for page in json['pages']: 43 | for field in page['fields']: 44 | if (field['field_id'] == f_id): 45 | return field['options'] 46 | 47 | class Meta: 48 | abstract = True 49 | -------------------------------------------------------------------------------- /fieldtypes/ModelField.py: -------------------------------------------------------------------------------- 1 | 2 | from django.core.exceptions import ValidationError 3 | from django.core.exceptions import ObjectDoesNotExist 4 | 5 | from pulpo_forms.fieldtypes.Field import Field 6 | 7 | 8 | class ModelField(Field): 9 | """ 10 | Model field validator, render and analize methods 11 | """ 12 | model = None 13 | name = "object" 14 | template_name = "modelField/template.html" 15 | edit_template_name = "modelField/template_edit.html" 16 | sts_template_name = "modelField/template_statistic.html" 17 | 18 | def get_methods(self, **kwargs): 19 | base = super(ModelField, self).get_methods(**kwargs) 20 | base.append(self.belong_check) 21 | return base 22 | 23 | def belong_check(self, value, **kwargs): 24 | v = int(value) 25 | if (self.model is None): 26 | raise ValidationError("Invalid model.") 27 | try: 28 | obj = self.model.objects.get(pk=v) 29 | except ObjectDoesNotExist: 30 | raise ValidationError("That %s does not exist." % self.name) 31 | 32 | def find_options(self): 33 | l = [] 34 | options = self.model.objects.all() 35 | if (options == []): 36 | raise ValidationError("This model has no items.") 37 | for o in options: 38 | l.append({'id': o.pk, 'label': o.__str__()}) 39 | return l 40 | 41 | def get_options(self, json, f_id): 42 | return self.find_options() 43 | 44 | class Meta: 45 | abstract = True 46 | -------------------------------------------------------------------------------- /fieldtypes/NumberField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes import Field 4 | from pulpo_forms.fieldtypes import FieldFactory 5 | from pulpo_forms.statistics.NumericStatistics import NumericStatistics 6 | 7 | 8 | class NumberField(Field.Field): 9 | """ 10 | Number field type class. 11 | """ 12 | template_name = "number/template.html" 13 | edit_template_name = "number/template_edit.html" 14 | prp_template_name = "number/properties.html" 15 | sts_template_name = "number/template_statistic.html" 16 | 17 | def check_min(self, value, **kwargs): 18 | field = kwargs['field'] 19 | val = field.validations 20 | if ((val.min_number is not None) and (int(value) < val.min_number)): 21 | raise ValidationError("Value below the minimum acceptable.") 22 | 23 | def check_max(self, value, **kwargs): 24 | field = kwargs['field'] 25 | val = field.validations 26 | if ((val.max_number is not None) and (int(value) > val.max_number)): 27 | raise ValidationError("Value above the maximum acceptable.") 28 | 29 | def int_check(self, value, **kwargs): 30 | try: 31 | int(value) 32 | except (ValueError, TypeError): 33 | print('except (ValueError, TypeError):') 34 | raise ValidationError('Enter a valid integer.', code='invalid') 35 | 36 | def get_methods(self, **kwargs): 37 | # Default validation or pass 38 | base = super(NumberField, self).get_methods(**kwargs) 39 | base.append(self.int_check) 40 | field = kwargs['field'] 41 | restrictions = field.validations 42 | if (restrictions.min_number is not None): 43 | base.append(self.check_min) 44 | if (restrictions.max_number is not None): 45 | base.append(self.check_max) 46 | return base 47 | 48 | def check_consistency(self, field): 49 | # When a field is created check if the restrictions are consistent 50 | val = field.validations 51 | if not val.valid_number(): 52 | raise ValidationError("The min value might not be below \ 53 | the max value.") 54 | 55 | def get_statistics(self, data, field): 56 | """ 57 | Returns a serialized NumericStatistics data containing statistical 58 | data for the field. 59 | """ 60 | statistics = super(NumberField, self).get_statistics(data, field) 61 | numeric_statistics = NumericStatistics(data) 62 | statistics.update(numeric_statistics.getSerializedData()) 63 | return statistics 64 | 65 | def get_assets(): 66 | return ['js/fields/NumberField.js', 'js/operators/operatorNumber.js'] 67 | 68 | def get_styles(): 69 | return ['css/fields/NumberField.css'] 70 | 71 | def __str__(self): 72 | return "NumberField" 73 | 74 | FieldFactory.FieldFactory.register('NumberField', NumberField) 75 | -------------------------------------------------------------------------------- /fieldtypes/SelectField.py: -------------------------------------------------------------------------------- 1 | from pulpo_forms.fieldtypes.ListField import ListField 2 | from pulpo_forms.fieldtypes import FieldFactory 3 | 4 | 5 | class SelectField(ListField): 6 | """ 7 | Combobox field validator, render and analize methods 8 | """ 9 | template_name = "combobox/template.html" 10 | edit_template_name = "combobox/template_edit.html" 11 | prp_template_name = "combobox/properties.html" 12 | sts_template_name = "combobox/template_statistic.html" 13 | 14 | def get_assets(): 15 | return ['js/fields/SelectField.js', 'js/operators/operatorList.js'] 16 | 17 | def get_styles(): 18 | return ['css/fields/SelectField.css'] 19 | 20 | def __str__(self): 21 | return "Combo Box" 22 | 23 | 24 | FieldFactory.FieldFactory.register('SelectField', SelectField) 25 | -------------------------------------------------------------------------------- /fieldtypes/TextAreaField.py: -------------------------------------------------------------------------------- 1 | from pulpo_forms.fieldtypes import TextField 2 | from pulpo_forms.fieldtypes import FieldFactory 3 | 4 | 5 | class TextAreaField(TextField.TextField): 6 | """ 7 | Validator for text area is the same as simple TextField 8 | """ 9 | template_name = "text_area/template.html" 10 | edit_template_name = "text_area/template_edit.html" 11 | prp_template_name = "text_area/properties.html" 12 | 13 | def get_assets(): 14 | return ['js/fields/TextAreaField.js'] 15 | 16 | def get_styles(): 17 | return ['css/fields/TextAreaField.css'] 18 | 19 | def __str__(self): 20 | return "Multi Line Text" 21 | 22 | FieldFactory.FieldFactory.register('TextAreaField', TextAreaField) 23 | -------------------------------------------------------------------------------- /fieldtypes/TextField.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from pulpo_forms.fieldtypes import Field 4 | from pulpo_forms.fieldtypes import FieldFactory 5 | 6 | 7 | class TextField(Field.Field): 8 | """ 9 | Text field validator, render and analize methods 10 | """ 11 | template_name = "text/template.html" 12 | edit_template_name = "text/template_edit.html" 13 | prp_template_name = "text/properties.html" 14 | 15 | def check_length(self, value, **kwargs): 16 | field = kwargs['field'] 17 | val = field.validations 18 | if (len(value) > val.max_len_text): 19 | raise ValidationError("Text is too long") 20 | 21 | def get_methods(self, **kwargs): 22 | # Default validation or pass 23 | base = super(TextField, self).get_methods(**kwargs) 24 | field = kwargs['field'] 25 | val = field.validations 26 | if (val.max_len_text is not None): 27 | base.append(self.check_length) 28 | return base 29 | 30 | def check_consistency(self, field): 31 | # When a field is created check if the restrictions are consistent 32 | val = field.validations 33 | if (not val.valid_text()): 34 | raise ValidationError("Max length might not be less than 0.") 35 | 36 | def get_assets(): 37 | return ['js/fields/TextField.js', 'js/validators/TextField.js'] 38 | 39 | def get_styles(): 40 | return ['css/fields/TextField.css'] 41 | 42 | def __str__(self): 43 | return "Single Line Text" 44 | 45 | 46 | FieldFactory.FieldFactory.register('TextField', TextField) 47 | -------------------------------------------------------------------------------- /fieldtypes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__init__.py -------------------------------------------------------------------------------- /fieldtypes/__pycache__/CIField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/CIField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/CheckboxField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/CheckboxField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/EmailField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/EmailField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/Field.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/Field.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/FieldFactory.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/FieldFactory.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/FileField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/FileField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/GeoField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/GeoField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/ListField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/ListField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/ModelField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/ModelField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/NumberField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/NumberField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/SelectField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/SelectField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/TextAreaField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/TextAreaField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/TextField.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/TextField.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/__init__.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/__init__.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/__pycache__/field_type.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/fieldtypes/__pycache__/field_type.cpython-34.pyc -------------------------------------------------------------------------------- /fieldtypes/field_type.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | 4 | def on_startup(): 5 | for file in settings.FIELD_FILES: 6 | __import__(file, fromlist=[""]) 7 | -------------------------------------------------------------------------------- /middlets.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ValidationError 2 | 3 | from rest_framework import status 4 | 5 | from .views import JSONResponse 6 | 7 | 8 | class ValidationErrorToHttpErrorMiddleware(object): 9 | """ 10 | Catch ValidationError exceptions and render them as JSONResponse 11 | """ 12 | 13 | def process_exception(self, request, exception): 14 | if isinstance(exception, ValidationError): 15 | content = {'error': exception.message} 16 | return JSONResponse(content, status.HTTP_400_BAD_REQUEST) 17 | -------------------------------------------------------------------------------- /migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | import pulpo_forms.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='FieldEntry', 18 | fields=[ 19 | ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), 20 | ('field_id', models.IntegerField()), 21 | ('field_type', models.CharField(max_length=100)), 22 | ('text', models.CharField(max_length=200)), 23 | ('required', models.BooleanField()), 24 | ('shown', models.BooleanField(default=True)), 25 | ('answer', models.CharField(blank=True, null=True, max_length=400)), 26 | ], 27 | ), 28 | migrations.CreateModel( 29 | name='FileEntry', 30 | fields=[ 31 | ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), 32 | ('field_id', models.IntegerField()), 33 | ('file_type', models.CharField(max_length=50)), 34 | ('file_name', models.CharField(max_length=50)), 35 | ('file_data', models.FileField(upload_to='doc')), 36 | ('field_entry', models.ForeignKey(related_name='files', blank=True, null=True, to='pulpo_forms.FieldEntry')), 37 | ], 38 | ), 39 | migrations.CreateModel( 40 | name='Form', 41 | fields=[ 42 | ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), 43 | ('title', models.CharField(max_length=100)), 44 | ('slug', models.SlugField(unique=True)), 45 | ('owner', models.ForeignKey(related_name='forms', blank=True, to=settings.AUTH_USER_MODEL)), 46 | ], 47 | options={ 48 | 'ordering': ('title',), 49 | }, 50 | ), 51 | migrations.CreateModel( 52 | name='FormEntry', 53 | fields=[ 54 | ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), 55 | ('entry_time', models.DateTimeField(blank=True)), 56 | ], 57 | ), 58 | migrations.CreateModel( 59 | name='Version', 60 | fields=[ 61 | ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)), 62 | ('number', models.IntegerField(default=1)), 63 | ('json', pulpo_forms.fields.JSONField(blank=True, default='')), 64 | ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Published'), (2, 'Expired')], default=0)), 65 | ('publish_date', models.DateTimeField(blank=True, null=True)), 66 | ('expiry_date', models.DateTimeField(blank=True, null=True)), 67 | ('captcha', models.BooleanField(default=False)), 68 | ('form', models.ForeignKey(to='pulpo_forms.Form', related_name='versions')), 69 | ], 70 | ), 71 | migrations.AddField( 72 | model_name='formentry', 73 | name='version', 74 | field=models.ForeignKey(to='pulpo_forms.Version', related_name='entries'), 75 | ), 76 | migrations.AddField( 77 | model_name='fieldentry', 78 | name='entry', 79 | field=models.ForeignKey(related_name='fields', blank=True, null=True, to='pulpo_forms.FormEntry'), 80 | ), 81 | ] 82 | -------------------------------------------------------------------------------- /migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/migrations/__init__.py -------------------------------------------------------------------------------- /my.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sat Oct 18 2014 13:54:14 GMT-0200 (UYST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['jasmine'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | './static/angular/angular.js', 19 | './static/jquery/js/*.js', 20 | './static/bootstrap/js/*.js', 21 | './static/angular/angular-mocks.js', 22 | './static/angular/d3.js', 23 | './static/angular/angular-charts.js', 24 | './static/angular/*.js', 25 | './static/js/validators/validatorFactory.js', 26 | './static/js/validators/*.js', 27 | './static/js/operators/operatorFactory.js', 28 | './static/js/operators/operatorField.js', 29 | './static/js/operators/operatorList.js', 30 | './static/js/operators/operatorNumber.js', 31 | './static/js/operators/operatorChecks.js', 32 | './static/js/fields/FieldFactory.js', 33 | './static/js/fields/*.js', 34 | './static/js/appVisor.js', 35 | './static/js/app.js', 36 | './static/js/visorCtrl.js', 37 | './static/js/editorCtrl.js', 38 | './static/js/mainpageCtrl.js', 39 | './testing/mainPage_test.js', 40 | './testing/visor_tests.js', 41 | './testing/editor_test.js', 42 | ], 43 | 44 | 45 | // list of files to exclude 46 | exclude: [ 47 | ], 48 | 49 | 50 | // preprocess matching files before serving them to the browser 51 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 52 | preprocessors: { 53 | }, 54 | 55 | 56 | // test results reporter to use 57 | // possible values: 'dots', 'progress' 58 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 59 | reporters: ['progress'], 60 | 61 | 62 | // web server port 63 | port: 9876, 64 | 65 | 66 | // enable / disable colors in the output (reporters and logs) 67 | colors: true, 68 | 69 | 70 | // level of logging 71 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 72 | logLevel: config.LOG_INFO, 73 | 74 | 75 | // enable / disable watching file and executing tests whenever any file changes 76 | autoWatch: true, 77 | 78 | 79 | // start these browsers 80 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 81 | browsers: ['Firefox'], 82 | 83 | 84 | // Continuous Integration mode 85 | // if true, Karma captures browsers, runs the tests and exits 86 | singleRun: true 87 | }); 88 | }; 89 | -------------------------------------------------------------------------------- /permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsOwnerSuperUserOrReadOnly(permissions.BasePermission): 5 | """ 6 | Custom permission to only allow owners of an object to edit it. 7 | """ 8 | 9 | def has_object_permission(self, request, view, obj): 10 | # Read permissions are allowed to any request, 11 | # so we'll always allow GET, HEAD or OPTIONS requests. 12 | if request.method in permissions.SAFE_METHODS: 13 | return True 14 | 15 | # Write permissions are only allowed to the owner of object or 16 | # a superuser. 17 | try: 18 | owner = obj.owner 19 | except AttributeError: 20 | owner = obj.form.owner 21 | return (owner == request.user or request.user.is_superuser) 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: 5 | README = readme.read() 6 | 7 | # allow setup.py to be run from any path 8 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 9 | 10 | setup( 11 | name='pulpo-forms', 12 | version='1.1', 13 | packages=['pulpo_forms'], 14 | include_package_data=True, 15 | license='Apache License', 16 | description='Django App to create dynamic Surveys', 17 | long_description=README, 18 | keywords='Django Survey Framework', 19 | url='https://github.com/pulpocoders/pulpo-forms-django', 20 | author='PythonWarriors + Pulpocoders', 21 | author_email='info@trea.uy', 22 | zip_safe=True, 23 | install_requires=[ 24 | 'Django>=1.6', 25 | 'djangorestframework>=3.1', 26 | 'reportlab', 27 | 'django-sekizai', 28 | 'django-compressor', 29 | ], 30 | classifiers=[ 31 | 'Programming Language :: Python', 32 | 'Programming Language :: Python :: 3.4', 33 | 'License :: OSI Approved :: Apache Software License', 34 | 'Operating System :: OS Independent', 35 | 'Development Status :: 4 - Beta', 36 | 'Environment :: Web Environment', 37 | 'Intended Audience :: Information Technology', 38 | 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application' 39 | ], 40 | ) 41 | -------------------------------------------------------------------------------- /signals.py: -------------------------------------------------------------------------------- 1 | from django.dispatch import Signal 2 | 3 | 4 | modified_logic = Signal(providing_args=["sent_data"]) 5 | -------------------------------------------------------------------------------- /static/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/__init__.py -------------------------------------------------------------------------------- /static/angular/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/angular/__init__.py -------------------------------------------------------------------------------- /static/angular/angular-growl-notifications.min.js: -------------------------------------------------------------------------------- 1 | /*! growl-notifications 15-09-2014 */ 2 | !function(){angular.module("growlNotifications.config",[]).value("growlNotifications.config",{debug:!0}),angular.module("growlNotifications.directives",[]),angular.module("growlNotifications.filters",[]),angular.module("growlNotifications.services",[]),angular.module("growlNotifications",["growlNotifications.config","growlNotifications.directives","growlNotifications.filters","growlNotifications.services"])}(),function(){function a(a,c,d){var e={ttl:a.options.ttl||5e3};return{restrict:"AE",scope:!0,controller:b,controllerAs:"$growlNotification",link:function(b,f,g,h){var i=angular.extend({},e,b.$eval(g.growlNotificationOptions));g.ttl&&(i.ttl=b.$eval(g.ttl)),c.move(f,a.element),h.timer=d(function(){c.leave(f)},i.ttl)}}}function b(a,b){this.timer=null,this.remove=function(){b.leave(a),this.timer&&this.timer.cancel&&this.timer.cancel()}}a.$inject=["growlNotifications","$animate","$timeout"],b.$inject=["$element","$animate"],angular.module("growlNotifications.directives").directive("growlNotification",a)}(),function(){function a(a){return{restrict:"AE",link:function(b,c){a.element=c}}}a.$inject=["growlNotifications"],angular.module("growlNotifications.directives").directive("growlNotifications",a)}(),function(){function a(){var a={ttl:5e3};this.setOptions=function(b){return angular.extend(a,b),this},this.ttl=function(b){return angular.isDefined(b)?(a.ttl=b,this):a.ttl},this.$get=function(){function b(){this.options=a,this.element=null}return new b}}angular.module("growlNotifications.services").provider("growlNotifications",a)}(); -------------------------------------------------------------------------------- /static/angular/angular-load.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";angular.module("angularLoad",[]).service("angularLoad",["$document","$q","$timeout",function(a,b,c){this.loadScript=function(d){var e=b.defer(),f=a[0].createElement("script");return f.onload=f.onreadystatechange=function(a){c(function(){e.resolve(a)})},f.onerror=function(a){c(function(){e.reject(a)})},f.src=d,a[0].body.appendChild(f),e.promise},this.loadCSS=function(d){var e=b.defer(),f=a[0].createElement("link");return f.rel="stylesheet",f.type="text/css",f.href=d,f.onload=f.onreadystatechange=function(a){c(function(){e.resolve(a)})},f.onerror=function(a){c(function(){e.reject(a)})},a[0].head.appendChild(f),e.promise}}])}(); 2 | //# sourceMappingURL=angular-load.min.js.map -------------------------------------------------------------------------------- /static/angular/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.3.9 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(I,d,B){'use strict';function D(f,q){q=q||{};d.forEach(q,function(d,h){delete q[h]});for(var h in f)!f.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(q[h]=f[h]);return q}var w=d.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;d.module("ngResource",["ng"]).provider("$resource",function(){var f=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}}; 7 | this.$get=["$http","$q",function(q,h){function t(d,g){this.template=d;this.defaults=s({},f.defaults,g);this.urlParams={}}function v(x,g,l,m){function c(b,k){var c={};k=s({},g,k);r(k,function(a,k){u(a)&&(a=a());var d;if(a&&a.charAt&&"@"==a.charAt(0)){d=b;var e=a.substr(1);if(null==e||""===e||"hasOwnProperty"===e||!C.test("."+e))throw w("badmember",e);for(var e=e.split("."),n=0,g=e.length;n li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: -@fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon-rotate(@degrees, @rotation) { 5 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); 6 | -webkit-transform: rotate(@degrees); 7 | -moz-transform: rotate(@degrees); 8 | -ms-transform: rotate(@degrees); 9 | -o-transform: rotate(@degrees); 10 | transform: rotate(@degrees); 11 | } 12 | 13 | .fa-icon-flip(@horiz, @vert, @rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); 15 | -webkit-transform: scale(@horiz, @vert); 16 | -moz-transform: scale(@horiz, @vert); 17 | -ms-transform: scale(@horiz, @vert); 18 | -o-transform: scale(@horiz, @vert); 19 | transform: scale(@horiz, @vert); 20 | } 21 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: ~"url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}')"; 7 | src: ~"url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype')", 8 | ~"url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff')", 9 | ~"url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype')", 10 | ~"url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg')"; 11 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/less/spinning.less: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: spin 2s infinite linear; 6 | -moz-animation: spin 2s infinite linear; 7 | -o-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | } 10 | 11 | @-moz-keyframes spin { 12 | 0% { -moz-transform: rotate(0deg); } 13 | 100% { -moz-transform: rotate(359deg); } 14 | } 15 | @-webkit-keyframes spin { 16 | 0% { -webkit-transform: rotate(0deg); } 17 | 100% { -webkit-transform: rotate(359deg); } 18 | } 19 | @-o-keyframes spin { 20 | 0% { -o-transform: rotate(0deg); } 21 | 100% { -o-transform: rotate(359deg); } 22 | } 23 | @keyframes spin { 24 | 0% { 25 | -webkit-transform: rotate(0deg); 26 | transform: rotate(0deg); 27 | } 28 | 100% { 29 | -webkit-transform: rotate(359deg); 30 | transform: rotate(359deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/bootstrap/fonts/font-awesome-4.1.0/scss/__init__.py -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font-family: FontAwesome; 7 | font-style: normal; 8 | font-weight: normal; 9 | line-height: 1; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon-rotate($degrees, $rotation) { 5 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 6 | -webkit-transform: rotate($degrees); 7 | -moz-transform: rotate($degrees); 8 | -ms-transform: rotate($degrees); 9 | -o-transform: rotate($degrees); 10 | transform: rotate($degrees); 11 | } 12 | 13 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 15 | -webkit-transform: scale($horiz, $vert); 16 | -moz-transform: scale($horiz, $vert); 17 | -ms-transform: scale($horiz, $vert); 18 | -o-transform: scale($horiz, $vert); 19 | transform: scale($horiz, $vert); 20 | } 21 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 9 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 10 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 11 | //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_spinning.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: spin 2s infinite linear; 6 | -moz-animation: spin 2s infinite linear; 7 | -o-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | } 10 | 11 | @-moz-keyframes spin { 12 | 0% { -moz-transform: rotate(0deg); } 13 | 100% { -moz-transform: rotate(359deg); } 14 | } 15 | @-webkit-keyframes spin { 16 | 0% { -webkit-transform: rotate(0deg); } 17 | 100% { -webkit-transform: rotate(359deg); } 18 | } 19 | @-o-keyframes spin { 20 | 0% { -o-transform: rotate(0deg); } 21 | 100% { -o-transform: rotate(359deg); } 22 | } 23 | @keyframes spin { 24 | 0% { 25 | -webkit-transform: rotate(0deg); 26 | transform: rotate(0deg); 27 | } 28 | 100% { 29 | -webkit-transform: rotate(359deg); 30 | transform: rotate(359deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/font-awesome-4.1.0/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "spinning"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/bootstrap/js/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/bootstrap/js/__init__.py -------------------------------------------------------------------------------- /static/css/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/css/__init__.py -------------------------------------------------------------------------------- /static/css/fields/CIField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the CI field. */ 2 | 3 | label.CIField { 4 | 5 | } 6 | 7 | input.CIField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/CheckboxField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the Checkbox field. */ 2 | 3 | label.CheckboxField { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /static/css/fields/EmailField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the email field. */ 2 | 3 | label.EmailField { 4 | 5 | } 6 | 7 | input.EmailField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/GeoField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the GeoLocation field. */ 2 | 3 | label.GeoField { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /static/css/fields/NumberField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the number field. */ 2 | 3 | label.NumberField { 4 | 5 | } 6 | 7 | input.NumberField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/SelectField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the select field. */ 2 | 3 | label.SelectField { 4 | 5 | } 6 | 7 | select.SelectField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/TextAreaField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the textarea field. */ 2 | 3 | label.TextAreaField { 4 | 5 | } 6 | 7 | textarea.TextAreaField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/TextField.css: -------------------------------------------------------------------------------- 1 | /* Styles for the text field. */ 2 | 3 | label.TextField { 4 | 5 | } 6 | 7 | input.TextField{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /static/css/fields/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/css/fields/__init__.py -------------------------------------------------------------------------------- /static/jquery/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/jquery/__init__.py -------------------------------------------------------------------------------- /static/jquery/css/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/jquery/css/__init__.py -------------------------------------------------------------------------------- /static/jquery/js/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/jquery/js/__init__.py -------------------------------------------------------------------------------- /static/js/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/js/__init__.py -------------------------------------------------------------------------------- /static/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function () { 4 | /* 5 | * Module dynamicFormsFramework 6 | * This module encapsulates the logic that will handle the form. 7 | */ 8 | var app = angular.module('dynamicFormsFrameworkAdmin', ['ui.sortable','ui.bootstrap', 9 | 'checklist-model','angularCharts', 10 | 'udpCaptcha', 'ngResource', 11 | 'growlNotifications']) 12 | .config(['$locationProvider', '$httpProvider', function ($locationProvider, $httpProvider) { 13 | 14 | $httpProvider.defaults.xsrfCookieName = 'csrftoken'; 15 | $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 16 | 17 | }]); 18 | 19 | app.config(['$resourceProvider', function($resourceProvider) { 20 | // Don't strip trailing slashes from calculated URLs 21 | $resourceProvider.defaults.stripTrailingSlashes = false; 22 | }]); 23 | 24 | app.run( function($rootScope){ 25 | $rootScope.notificationIndex = 0; 26 | $rootScope.invalidNotification = false; 27 | $rootScope.notifications = {}; 28 | 29 | $rootScope.add = function(notification){ 30 | var i; 31 | if(!notification){ 32 | $rootScope.invalidNotification = true; 33 | return; 34 | } 35 | i = $rootScope.notificationIndex++; 36 | $rootScope.invalidNotification = false; 37 | $rootScope.notifications[i] = notification; 38 | }; 39 | }) 40 | 41 | app.directive('ngConfirmClick', [function(){ 42 | return { 43 | priority: -1, 44 | restrict: 'A', 45 | link: function(scope, element, attrs){ 46 | element.bind('click', function(e){ 47 | var message = attrs.ngConfirmClick; 48 | if(message && !confirm(message)){ 49 | e.stopImmediatePropagation(); 50 | e.preventDefault(); 51 | } 52 | }); 53 | } 54 | } 55 | }]); 56 | 57 | })(); 58 | -------------------------------------------------------------------------------- /static/js/appVisor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function () { 4 | /* 5 | * Module dynamicFormsFramework 6 | * This module encapsulates the logic that will handle the form. 7 | */ 8 | var app = angular.module('dynamicFormsFramework', ['ui.bootstrap','checklist-model', 'udpCaptcha','ngResource', 9 | 'angularFileUpload','survey-question']) 10 | .config(['$locationProvider','$httpProvider', function ($locationProvider, $httpProvider) { 11 | 12 | $locationProvider.html5Mode({ 13 | enabled: true, 14 | requireBase: false 15 | }); 16 | $httpProvider.defaults.xsrfCookieName = 'csrftoken'; 17 | $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 18 | 19 | }]); 20 | 21 | app.config(['$resourceProvider', function($resourceProvider) { 22 | // Don't strip trailing slashes from calculated URLs 23 | $resourceProvider.defaults.stripTrailingSlashes = false; 24 | }]); 25 | 26 | /* 27 | * This directive checks custom javascript validations defined for each field. 28 | */ 29 | app.directive('validate', function() { 30 | return { 31 | require: 'ngModel', 32 | link: function(scope, elm, attrs, ctrl) { 33 | ctrl.$validators.validate = function(modelValue, viewValue) { 34 | if (ctrl.$isEmpty(modelValue)) { 35 | // Consider empty models to be valid 36 | return true; 37 | } 38 | var validator = validatorFactory.getValidator(attrs.fieldtype); 39 | if (validator){ 40 | if (validator.validate(viewValue, attrs)) { 41 | return true; 42 | } 43 | return false; 44 | } else { 45 | return true; 46 | } 47 | }; 48 | } 49 | }; 50 | }); 51 | 52 | })(); 53 | -------------------------------------------------------------------------------- /static/js/fields/CIField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function CIField() { 4 | 5 | } 6 | 7 | CIField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'CIField'; 10 | return (field); 11 | }; 12 | 13 | // Register field constructor in Factory 14 | fieldFactory.registerField('CIField', CIField); 15 | -------------------------------------------------------------------------------- /static/js/fields/CheckboxField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function CheckboxField() { 4 | 5 | } 6 | 7 | CheckboxField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'CheckboxField'; 10 | field.options = []; 11 | field.max_id = 0; 12 | return (field); 13 | }; 14 | 15 | // Register field constructor in Factory 16 | fieldFactory.registerField('CheckboxField', CheckboxField); 17 | -------------------------------------------------------------------------------- /static/js/fields/EmailField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function EmailField() { 4 | 5 | } 6 | 7 | EmailField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'EmailField'; 10 | field.validations = { 11 | max_len_text: 255, 12 | }; 13 | return (field); 14 | }; 15 | 16 | // Register field constructor in Factory 17 | fieldFactory.registerField('EmailField', EmailField); -------------------------------------------------------------------------------- /static/js/fields/FieldBase.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function FieldBase() { 4 | 5 | } 6 | 7 | FieldBase.buildField = function() { 8 | var field = { 9 | field_id : 0, 10 | field_type:'' , 11 | text: '', 12 | answer: [], 13 | validations: {}, 14 | required: false, 15 | tooltip:'', 16 | dependencies: { 17 | fields: [], 18 | pages: [], 19 | } 20 | }; 21 | return field; 22 | }; 23 | -------------------------------------------------------------------------------- /static/js/fields/FieldFactory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fieldFactory = (function () { 4 | 5 | // Available field classes 6 | var field = {}; 7 | 8 | return { 9 | getField: function (fieldName) { 10 | var Field = field[fieldName]; 11 | return Field; 12 | }, 13 | registerField: function (fieldName, Field) { 14 | // Register Field Class 15 | field[fieldName] = Field; 16 | return fieldFactory; 17 | }, 18 | listFields: function (){ 19 | return field; 20 | } 21 | }; 22 | })(); 23 | -------------------------------------------------------------------------------- /static/js/fields/FileField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function FileField() { 4 | 5 | } 6 | 7 | FileField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'FileField'; 10 | field.validations = {}; 11 | return (field); 12 | }; 13 | 14 | // Register field constructor in Factory 15 | fieldFactory.registerField('FileField', FileField); -------------------------------------------------------------------------------- /static/js/fields/GeoField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function GeoField() { 4 | 5 | } 6 | 7 | GeoField.buildField = function(){ 8 | 9 | var field = FieldBase.buildField(this); 10 | 11 | field.field_type = 'GeoField'; 12 | field.mapzoom = 8, 13 | field.mapXY = { 14 | latitude: -34.806777135903424, 15 | longitude: -56.164398487890594 16 | }, 17 | field.first = true; 18 | return (field); 19 | }; 20 | 21 | // Register field constructor in Factory 22 | fieldFactory.registerField('GeoField', GeoField); 23 | -------------------------------------------------------------------------------- /static/js/fields/Matricula.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function MatriculaField() { 4 | 5 | } 6 | 7 | MatriculaField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'MatriculaField'; 10 | field.validations = {}; 11 | return (field); 12 | }; 13 | 14 | // Register field constructor in Factory 15 | fieldFactory.registerField('MatriculaField', MatriculaField); -------------------------------------------------------------------------------- /static/js/fields/ModelField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function ModelField() { 4 | 5 | } 6 | 7 | ModelField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'ModelField'; 10 | field.options = []; 11 | field.max_id = 0; 12 | return (field); 13 | }; 14 | 15 | // Register field constructor in Factory 16 | fieldFactory.registerField('ModelField', ModelField); -------------------------------------------------------------------------------- /static/js/fields/NumberField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function NumberField() { 4 | 5 | } 6 | 7 | NumberField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'NumberField'; 10 | field.validations = { 11 | min_number: null, 12 | max_number: null, 13 | }; 14 | return (field); 15 | }; 16 | 17 | // Register field constructor in Factory 18 | fieldFactory.registerField('NumberField', NumberField); 19 | -------------------------------------------------------------------------------- /static/js/fields/SelectField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function SelectField() { 4 | 5 | } 6 | 7 | SelectField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'SelectField'; 10 | field.options = []; 11 | field.max_id = 0; 12 | return (field); 13 | }; 14 | 15 | // Register field constructor in Factory 16 | fieldFactory.registerField('SelectField', SelectField); 17 | -------------------------------------------------------------------------------- /static/js/fields/TextAreaField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function TextAreaField() { 4 | 5 | } 6 | 7 | TextAreaField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'TextAreaField'; 10 | field.validations = { 11 | max_len_text: 400, 12 | }; 13 | return (field); 14 | }; 15 | 16 | // Register field constructor in Factory 17 | fieldFactory.registerField('TextAreaField', TextAreaField); 18 | -------------------------------------------------------------------------------- /static/js/fields/TextField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function TextField() { 4 | 5 | } 6 | 7 | TextField.buildField = function(){ 8 | var field = FieldBase.buildField(this); 9 | field.field_type = 'TextField'; 10 | field.validations = { 11 | max_len_text: 255, 12 | }; 13 | return (field); 14 | }; 15 | 16 | // Register field constructor in Factory 17 | fieldFactory.registerField('TextField', TextField); 18 | -------------------------------------------------------------------------------- /static/js/fields/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/js/fields/__init__.py -------------------------------------------------------------------------------- /static/js/mainpageCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function () { 4 | 5 | var app = angular.module('dynamicFormsFrameworkAdmin'); 6 | 7 | /* 8 | * This controller handles the logic to display the list of forms 9 | */ 10 | app.controller('MainPageCtrl', ['$scope','$http','$location', 11 | function ($scope, $http, $location) { 12 | 13 | var mainPage = this; 14 | mainPage.formSlugParam = ($location.search()).form; 15 | mainPage.versionIdParam = ($location.search()).ver; 16 | mainPage.orders = [ 17 | {name: 'Id', value: 'id'}, 18 | {name: 'Owner', value: 'owner'}, 19 | {name: 'Title', value: 'title'}, 20 | ]; 21 | 22 | mainPage.selectascdsc = function(ascdsc){ 23 | mainPage.ascdsc = ascdsc; 24 | }; 25 | 26 | mainPage.url = function(){ 27 | var parser = $location.absUrl(); 28 | var arr = parser.split('/'); 29 | var crit = arr[arr.length - 3]; 30 | var sent = arr[arr.length - 2]; 31 | return ([crit, sent]); 32 | }; 33 | 34 | mainPage.actualOrder = function(){ 35 | if (mainPage.url()[0] == 'owner'){ 36 | return mainPage.orders[1]; 37 | } else if (mainPage.url()[0] == 'title'){ 38 | return mainPage.orders[2]; 39 | } else { 40 | return mainPage.orders[0]; 41 | } 42 | }; 43 | 44 | if (mainPage.url()[1] == 'dsc'){ 45 | mainPage.selectascdsc('dsc'); 46 | mainPage.actualascdsc = 'DSC'; 47 | } else { 48 | mainPage.selectascdsc('asc'); 49 | mainPage.actualascdsc = 'ASC'; 50 | } 51 | 52 | mainPage.getOrderUrl = function(){ 53 | return urlBase+mainPage.myOrder.value+'/'+mainPage.ascdsc; 54 | }; 55 | 56 | }]); 57 | })(); 58 | -------------------------------------------------------------------------------- /static/js/operators/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/js/operators/__init__.py -------------------------------------------------------------------------------- /static/js/operators/operatorChecks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function OperatorChecks() { 4 | OperatorList.call(); 5 | } 6 | 7 | OperatorChecks = Object.create(OperatorList); 8 | OperatorChecks.prototype.constructor = OperatorChecks; 9 | 10 | OperatorChecks.contains = function(data, contition){ 11 | var list = data.split(','); 12 | for (var i = 0; i < list.length; i++) { 13 | if (list[i] === contition) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | }; 19 | 20 | OperatorChecks.not_contains = function(data, contition){ 21 | var list = data.split(','); 22 | for (var i = 0; i < list.length; i++) { 23 | if (list[i] === contition) { 24 | return false; 25 | } 26 | } 27 | return true; 28 | }; 29 | 30 | operatorFactory.registerOperator('CheckboxField', OperatorChecks); 31 | -------------------------------------------------------------------------------- /static/js/operators/operatorFactory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var operatorFactory = (function () { 4 | 5 | // Available operators classes 6 | var operator = {}; 7 | var operatorMethods = {}; 8 | 9 | return { 10 | getOperator: function (operatorName) { 11 | var Operator = operator[operatorName]; 12 | return Operator; 13 | }, 14 | 15 | getOperatorMethods: function(operatorName){ 16 | return operatorMethods[operatorName]; 17 | }, 18 | registerOperator: function (operatorName, Operator) { 19 | // Register Operator Class 20 | operator[operatorName] = Operator; 21 | // Register Operator's available methods 22 | operatorMethods[operatorName] = Operator.listMethods(); 23 | return operatorFactory; 24 | }, 25 | listOperators: function (){ 26 | return operator; 27 | } 28 | }; 29 | 30 | })(); 31 | -------------------------------------------------------------------------------- /static/js/operators/operatorField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function OperatorField() { 4 | 5 | } 6 | 7 | OperatorField.listMethods = function() { 8 | var methods = []; 9 | for (var key in this) { 10 | var exclude = ['constructor', 'register', 'listMethods', 'operandKind']; 11 | if (typeof this[key] === 'function' && 12 | exclude.indexOf(key) < 0) { 13 | methods.push(key); 14 | } 15 | } 16 | return methods; 17 | }; 18 | 19 | OperatorField.operandKind = function(){ 20 | return 'input'; 21 | }; -------------------------------------------------------------------------------- /static/js/operators/operatorList.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function OperatorList() { 4 | 5 | OperatorField.call(); 6 | } 7 | 8 | 9 | OperatorList = Object.create(OperatorField); 10 | OperatorList.prototype.constructor = OperatorList; 11 | 12 | OperatorList.operandKind = function(){ 13 | return 'options'; 14 | }; 15 | 16 | OperatorList.equal = function(a, b){ 17 | return (a === b); 18 | }; 19 | 20 | OperatorList.not_equal = function(a, b){ 21 | return (a !== b); 22 | }; 23 | 24 | operatorFactory.registerOperator('SelectField', OperatorList); 25 | -------------------------------------------------------------------------------- /static/js/operators/operatorNumber.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function OperatorNumber() { 4 | OperatorField.call(); 5 | } 6 | 7 | OperatorNumber = Object.create(OperatorField); 8 | OperatorNumber.prototype.constructor = OperatorNumber; 9 | 10 | OperatorNumber.greater_than = function(a, b){ 11 | var aInt = parseInt(a,10); 12 | var bInt = parseInt(b,10); 13 | return (aInt>bInt); 14 | }; 15 | 16 | OperatorNumber.greater_than_or_equal = function(a, b){ 17 | var aInt = parseInt(a,10); 18 | var bInt = parseInt(b,10); 19 | return (aInt >= bInt); 20 | }; 21 | 22 | OperatorNumber.equal = function(a, b){ 23 | var aInt = parseInt(a,10); 24 | var bInt = parseInt(b,10); 25 | return (aInt == bInt); 26 | }; 27 | 28 | OperatorNumber.not_equal = function(a, b){ 29 | var aInt = parseInt(a,10); 30 | var bInt = parseInt(b,10); 31 | return (aInt != bInt); 32 | }; 33 | 34 | OperatorNumber.less_than_or_equal = function(a, b){ 35 | var aInt = parseInt(a,10); 36 | var bInt = parseInt(b,10); 37 | return (aInt <= bInt); 38 | }; 39 | 40 | OperatorNumber.less_than = function(a, b){ 41 | var aInt = parseInt(a,10); 42 | var bInt = parseInt(b,10); 43 | return (aInt < bInt); 44 | }; 45 | 46 | operatorFactory.registerOperator('NumberField', OperatorNumber); 47 | -------------------------------------------------------------------------------- /static/js/responsesCtrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function () { 4 | 5 | var app = angular.module('dynamicFormsFrameworkAdmin'); 6 | 7 | /* 8 | * This controller handles the logic to create, edit and save a form. 9 | */ 10 | app.controller('ResponsesCtrl', function ($scope, $rootScope, $location, ResponsesService) { 11 | 12 | var responses = this; 13 | responses.formId = ($location.search()).form; 14 | responses.versionNumber = ($location.search()).ver; 15 | responses.json = ''; 16 | 17 | responses.getResponses = function(){ 18 | ResponsesService.query({formId: responses.formId, versionId: responses.versionNumber}, 19 | function (data){ 20 | delete data.$promise; 21 | delete data.$resolved; 22 | responses.json = JSON.parse(JSON.stringify(data)); 23 | var fields,location; 24 | for (var i = 0; i < responses.json.length; i++) { 25 | fields = responses.json[i].fields; 26 | for (var j = 0; j < fields.length; j++) { 27 | if (fields[j].field_type == 'FileField'){ 28 | location = window.location.href.split("#")[0]; 29 | location += 'download/' + fields[j].field_id + '/' + fields[j].pk + '/'; 30 | fields[j].download_link = location; 31 | } 32 | }; 33 | }; 34 | }, function(error){ 35 | if (error.data.error) { 36 | $rootScope.add('Error loading responses: ' + error.data.error); 37 | } else { 38 | $rootScope.add('Error loading responses: ' + error.data); 39 | }; 40 | }); 41 | }; 42 | 43 | // Calls the function getResponses 44 | responses.getResponses(); 45 | responses.isFile = function(field){ 46 | var re = new RegExp('FileField'); 47 | var infoFile = /\[.*\].*:(.*)/g.exec(field); 48 | var res = ''; 49 | res = re.exec(field); 50 | return res != null && infoFile[1] != ' '; 51 | 52 | }; 53 | 54 | responses.fieldResponse=function(field){ 55 | 56 | var infoFile = /\[.*\](.*)/g.exec(field); 57 | return infoFile[1]; 58 | }; 59 | 60 | responses.downloadLink=function(field){ 61 | var infoFile = /.*,(\d*),(\d*)/g.exec(field); 62 | var field_id = infoFile[1]; 63 | var entry = infoFile[2]; 64 | return 'download/'+field_id+'/'+ entry+'/'; 65 | }; 66 | 67 | }); 68 | 69 | })(); 70 | -------------------------------------------------------------------------------- /static/js/services/resources.js: -------------------------------------------------------------------------------- 1 | var app = angular.module('dynamicFormsFrameworkAdmin'); 2 | 3 | app.factory('ConstantService', function($resource){ 4 | var constants_api_url = '/pulpo/constants/' 5 | 6 | return $resource( constants_api_url, {}, 7 | {'query': {method: 'GET', isArray: true }}); 8 | }); 9 | 10 | app.factory('FieldEditService', function($resource){ 11 | var field_edit_api_url = '/pulpo/field_edit/' 12 | 13 | return $resource( field_edit_api_url + ':field/', {}, 14 | {'query': {method: 'GET', isArray: true }}); 15 | }); 16 | 17 | app.factory('FormService', function($resource){ 18 | var form_api_url = '/pulpo/forms/' 19 | 20 | return $resource( form_api_url + ':id/', {}, 21 | {'query': {method: 'GET', isArray: true }, 22 | 'create': {method: 'POST'}, 23 | 'update': {method: 'PUT'}}); 24 | }); 25 | 26 | app.factory('VersionService', function($resource){ 27 | var version_api_url = '/pulpo/version/' 28 | 29 | return $resource( version_api_url + ':formId/'+ ':versionId/', 30 | {formId: '@formId', versionId:'@versionId'}, 31 | {'query': {method: 'GET', isArray: true }, 32 | 'create': {method: 'POST'}, 33 | 'update': {method: 'PUT'}}); 34 | }); 35 | 36 | 37 | app.factory('ResponsesService', function($resource){ 38 | var responses_api_url = '/pulpo/responses/' 39 | 40 | return $resource( responses_api_url + ':formId/'+ ':versionId/' + 41 | ':field/' + ':type/' + ':value/', 42 | {formId: '@formId', versionId:'@versionId', 43 | field: '@field', type:'@type', value: '@value'}, 44 | {'query': {method: 'GET', isArray: true}}); 45 | }); 46 | 47 | app.factory('StatisticsService', function($resource){ 48 | var statistics_api_url = '/pulpo/statistics/' 49 | 50 | return $resource( statistics_api_url + ':formId/'+ ':versionId/', 51 | {formId: '@formId', versionId:'@versionId'}, 52 | {'query': {method: 'GET', isArray: true}}); 53 | }); -------------------------------------------------------------------------------- /static/js/services/visorResources.js: -------------------------------------------------------------------------------- 1 | var app = angular.module('dynamicFormsFramework'); 2 | 3 | app.factory('VersionService', function($resource){ 4 | var version_api_url = '/pulpo/visor/publishVersion/' 5 | 6 | return $resource( version_api_url +':form/', 7 | {form:'@form'}, 8 | {'query': {method: 'GET', isArray: true }}); 9 | }); 10 | -------------------------------------------------------------------------------- /static/js/validators/TextField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function TextField() { 4 | 5 | } 6 | 7 | /* 8 | * Validates the field with the values of the attributes of 9 | * the element. 10 | */ 11 | TextField.validate = function(value, attrs){ 12 | /* 13 | * attrs = a dictionary of attributes on the element 14 | */ 15 | var ok = true; 16 | /* Validate example*/ 17 | //ok = 'hello world' == value; 18 | //ok &= value.length <= attrs.ngMaxlength; 19 | 20 | return (ok); 21 | }; 22 | 23 | // Register field constructor in Factory 24 | validatorFactory.registerValidator('TextField', TextField); 25 | -------------------------------------------------------------------------------- /static/js/validators/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/static/js/validators/__init__.py -------------------------------------------------------------------------------- /static/js/validators/validatorFactory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var validatorFactory = (function () { 4 | 5 | // Available validators classes 6 | var validator = {}; 7 | 8 | return { 9 | getValidator: function (validatorName) { 10 | var Validator = validator[validatorName]; 11 | return Validator; 12 | }, 13 | registerValidator: function (validatorName, Validator) { 14 | // Register Operator Class 15 | validator[validatorName] = Validator; 16 | return validatorFactory; 17 | }, 18 | listValidators: function (){ 19 | return validator; 20 | } 21 | }; 22 | 23 | })(); 24 | -------------------------------------------------------------------------------- /statistics/CheckboxStatistics.py: -------------------------------------------------------------------------------- 1 | from pulpo_forms.statistics.serializers import ListStatisticsSerializer 2 | 3 | 4 | class CheckboxStatistics(): 5 | 6 | def __init__(self, data_list, options): 7 | self.total_per_option = [] 8 | self.options = [] 9 | self.total_filled = 0 10 | self.total_not_filled = 0 11 | # Initiate lists 12 | for option in options: 13 | self.total_per_option.append(0) 14 | self.options.append(option["label"]) 15 | # Count and remove null values 16 | # Count not null values data and insert them into an auxiliary list 17 | aux_list = [] 18 | for data in data_list: 19 | if data != "": 20 | aux_list += data.split("#") 21 | self.total_filled += 1 22 | else: 23 | self.total_not_filled += 1 24 | 25 | total_options = len(options) 26 | for data in aux_list: 27 | pos = 0 28 | while (pos != total_options) and (int(data) != options[pos]["id"]): 29 | pos += 1 30 | if pos != total_options: 31 | self.total_per_option[pos] += 1 32 | else: 33 | raise Exception("Data does not match with any option") 34 | 35 | def getSerializedData(self): 36 | return ListStatisticsSerializer(self).data 37 | -------------------------------------------------------------------------------- /statistics/ListStatistics.py: -------------------------------------------------------------------------------- 1 | from pulpo_forms.statistics.serializers import ListStatisticsSerializer 2 | 3 | 4 | class ListStatistics(): 5 | """ 6 | Class with the statistics info of a number field 7 | """ 8 | 9 | def __init__(self, data_list, options): 10 | self.total_per_option = [] 11 | self.options = [] 12 | self.total_filled = 0 13 | self.total_not_filled = 0 14 | # Initiate lists 15 | for option in options: 16 | self.total_per_option.append(0) 17 | self.options.append(option["label"]) 18 | # Count and remove null values from data list and count not null values 19 | aux_list = [] 20 | for data in data_list: 21 | if data != "": 22 | aux_list.append(data) 23 | self.total_filled += 1 24 | else: 25 | self.total_not_filled += 1 26 | 27 | total_options = len(options) 28 | for data in aux_list: 29 | pos = 0 30 | while (pos != total_options) and (int(data) != options[pos]["id"]): 31 | pos += 1 32 | if pos != total_options: 33 | self.total_per_option[pos] += 1 34 | else: 35 | raise Exception("Data does not match with any field option.") 36 | 37 | def getSerializedData(self): 38 | return ListStatisticsSerializer(self).data 39 | -------------------------------------------------------------------------------- /statistics/NumericStatistics.py: -------------------------------------------------------------------------------- 1 | from statistics import mean, pstdev 2 | import math 3 | 4 | from pulpo_forms.statistics.serializers import NumericStatisticsSerializer 5 | 6 | 7 | class NumericStatistics(): 8 | """ 9 | Class with the statistics info of a number field 10 | """ 11 | 12 | def __init__(self, data_list): 13 | # Null values are counted as 0 14 | list_total = [] 15 | # Without null values 16 | list = [] 17 | self.total_filled = 0 18 | self.total_not_filled = 0 19 | self.quintilesX = [] 20 | self.quintilesY = [] 21 | 22 | for data in data_list: 23 | if data != "": 24 | list_total.append(int(data)) 25 | list.append(int(data)) 26 | self.total_filled += 1 27 | else: 28 | list_total.append(0) 29 | self.total_not_filled += 1 30 | 31 | if list != []: 32 | self.mean = round(mean(list), 2) 33 | self.standard_deviation = round(pstdev(list, self.mean), 2) 34 | minimum = min(list) 35 | maximum = max(list) 36 | 37 | quintile_length = math.floor((maximum - minimum + 1) / 5) 38 | # First 4 quintiles 39 | first = minimum 40 | for i in range(1, 5): 41 | second = first + quintile_length 42 | quintile_x = "[" + str(first) + ", " + str(second) + ")" 43 | self.quintilesX.append(quintile_x) 44 | quintile_y = 0 45 | for num in list: 46 | if (first <= num) and (num < second): 47 | quintile_y += 1 48 | self.quintilesY.append(quintile_y) 49 | first = second 50 | # Last quintile 51 | self.quintilesX.append( 52 | "[" + str(first) + ", " + str(maximum) + "]") 53 | quintile_y = 0 54 | for num in list: 55 | if (first <= num) and (num <= maximum): 56 | quintile_y += 1 57 | self.quintilesY.append(quintile_y) 58 | else: 59 | self.mean = 0 60 | self.standard_deviation = 0 61 | self.total_mean = round(mean(list_total), 2) 62 | self.total_standard_deviation = round( 63 | pstdev(list_total, self.total_mean), 2) 64 | 65 | 66 | def getSerializedData(self): 67 | return NumericStatisticsSerializer(self).data 68 | -------------------------------------------------------------------------------- /statistics/PieChart.py: -------------------------------------------------------------------------------- 1 | from reportlab.graphics.charts.piecharts import Pie 2 | from reportlab.graphics.charts.legends import Legend 3 | from reportlab.graphics.shapes import Drawing 4 | from reportlab.lib.colors import Color, HexColor 5 | 6 | import json 7 | 8 | class PieChart(Drawing): 9 | 10 | def __init__(self, data, labels): 11 | super(PieChart, self).__init__(400,200) 12 | 13 | colors = [ 14 | HexColor("#0000e5"), 15 | HexColor("#ff0011"), 16 | HexColor("#800000"), 17 | HexColor("#e05897"), 18 | HexColor("#a08ff7"), 19 | HexColor("#8f8ff5"), 20 | HexColor("#c7c7fa"), 21 | HexColor("#800000"), 22 | HexColor("#eb8585"), 23 | HexColor("#d60a0a"), 24 | HexColor("#ffff00"), 25 | HexColor("#1f1feb"), 26 | ] 27 | 28 | # Create pie chart 29 | pieChart = Pie() 30 | pieChart.x = 40 31 | pieChart.y = 30 32 | pieChart.width = 120 33 | pieChart.height = 120 34 | pieChart.slices.strokeWidth=0.5 35 | data = json.loads(data) 36 | pieChart.data = data 37 | pieChart.labels = [] 38 | labels = json.loads(labels.replace("'",'"')) 39 | for d in data: 40 | pieChart.labels.append(str(d)) 41 | 42 | # Create legend 43 | legend = Legend() 44 | legend.x = 380 45 | legend.y = 60 46 | legend.boxAnchor = 'se' 47 | legend.subCols[1].align = 'right' 48 | legend.colorNamePairs = [] 49 | 50 | len_data = len(data) 51 | for i in range(0,len_data): 52 | pieChart.slices[i].fillColor = colors[i] 53 | legend.colorNamePairs.append((colors[i],labels[i])) 54 | 55 | self.add(pieChart, "pie chart") 56 | self.add(legend, "legend") 57 | -------------------------------------------------------------------------------- /statistics/StatisticsCtrl.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from pulpo_forms.models import Form, Version, FieldEntry 4 | from pulpo_forms.fieldtypes.FieldFactory import FieldFactory as Factory 5 | 6 | 7 | class StatisticsCtrl(): 8 | 9 | def getStatistics(self, formId, versionNum, filters): 10 | """ 11 | Receives a the id of a version (formId, versionNum), 12 | returns the statistics of each field on it 13 | """ 14 | form = Form.objects.get(pk=formId) 15 | version = form.versions.get(number=versionNum) 16 | 17 | field_entries = Version.objects.get_entries(version.pk) 18 | for filter in filters: 19 | if filter['filter_type'] == "equals": 20 | field_entries = field_entries.data_iexact( 21 | field_id=filter['field'], data=filter['field_value']) 22 | elif filter['filter_type'] == "contains": 23 | field_entries = field_entries.data_icontains( 24 | field_id=filter['field'], data=filter['field_value']) 25 | elif filter['filter_type'] in ["gte", "gt", "lte", "lt"]: 26 | field_entries = field_entries.data_number( 27 | field_id=filter['field'], data=int(filter['field_value']), 28 | operator=filter['filter_type']) 29 | field_entries = field_entries.get_data() 30 | 31 | if field_entries: 32 | loaded = json.loads(version.json) 33 | pages = loaded["pages"] 34 | 35 | statistics = {} 36 | for page in pages: 37 | for field in page["fields"]: 38 | data = [] 39 | for field_entry in field_entries: 40 | if field_entry.field_id == field["field_id"]: 41 | data.append(field_entry.answer) 42 | field_type = Factory.get_class(field["field_type"]) 43 | field_statistics = field_type().get_statistics(data, field) 44 | statistics[field["field_id"]] = field_statistics 45 | else: 46 | raise Exception("No entries found.") 47 | 48 | return statistics 49 | 50 | def getFieldStatistics(self, formId, versionNum, fieldId): 51 | """ 52 | Returns statistics for specific field in form 53 | """ 54 | # Get version 55 | form = Form.objects.get(pk=formId) 56 | version = form.versions.get(number=versionNum) 57 | 58 | field_entries = FieldEntry.objects.filter( 59 | entry__version_id=version.pk, field_id=fieldId) 60 | 61 | if field_entries: 62 | loaded = json.loads(version.json) 63 | pages = loaded["pages"] 64 | found = False 65 | # Indicates page number 66 | i = 0 67 | while not found: 68 | j = 0 69 | fields = pages[i]["fields"] 70 | while (not found) and (j != len(fields)): 71 | if fields[j]["field_id"] == int(fieldId): 72 | field = fields[j] 73 | found = True 74 | else: 75 | j += 1 76 | i += 1 77 | 78 | data = [] 79 | for field_entry in field_entries: 80 | data.append(field_entry.answer) 81 | field_type = Factory.get_class(field["field_type"]) 82 | field_statistics = field_type().get_statistics(data, field) 83 | 84 | return field_statistics 85 | else: 86 | raise Exception("No entries found.") 87 | -------------------------------------------------------------------------------- /statistics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__init__.py -------------------------------------------------------------------------------- /statistics/__pycache__/CheckboxStatistics.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/CheckboxStatistics.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/ListStatistics.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/ListStatistics.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/NumericStatistics.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/NumericStatistics.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/PieChart.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/PieChart.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/StatisticsCtrl.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/StatisticsCtrl.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/StatisticsPdf.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/StatisticsPdf.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/__init__.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/__init__.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/__pycache__/serializers.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/statistics/__pycache__/serializers.cpython-34.pyc -------------------------------------------------------------------------------- /statistics/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | class NumericStatisticsSerializer(serializers.Serializer): 4 | """ 5 | Serializer for NumericStatistics 6 | """ 7 | mean = serializers.FloatField() 8 | standard_deviation = serializers.FloatField() 9 | total_mean = serializers.FloatField() 10 | total_filled = serializers.IntegerField() 11 | total_not_filled = serializers.IntegerField() 12 | total_standard_deviation = serializers.FloatField() 13 | quintilesY = serializers.CharField() 14 | quintilesX = serializers.CharField() 15 | 16 | class ListStatisticsSerializer(serializers.Serializer): 17 | """ 18 | Serializer for ListStatistics 19 | """ 20 | options = serializers.CharField() 21 | total_per_option = serializers.CharField() 22 | total_filled = serializers.IntegerField() 23 | total_not_filled = serializers.IntegerField() 24 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 |

BAD REQUEST - 404



8 |

You don't want to be here.

9 | -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 |

SERVER ERROR - 500



8 |

Oops! An unepexted error has ocurred.

9 | -------------------------------------------------------------------------------- /templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/__init__.py -------------------------------------------------------------------------------- /templates/asset_block_template.html: -------------------------------------------------------------------------------- 1 | {% load sekizai_tags %} 2 | 3 | {% for asset_route in asset_list %} 4 | {% addtoblock "js" %} 5 | 6 | {% endaddtoblock %} 7 | {% endfor %} 8 | 9 | {% for asset_route in non_static_assets %} 10 | {% addtoblock "jsUnc" %} 11 | 12 | {% endaddtoblock %} 13 | {% endfor %} 14 | 15 | {% for asset_route in style_list %} 16 | {% addtoblock "css" %} 17 | 18 | {% endaddtoblock %} 19 | {% endfor %} -------------------------------------------------------------------------------- /templates/captcha_template.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 3 |
4 |
5 |

6 | 7 | 8 | 9 |

10 |
11 | 12 |
13 |
14 | 17 |
18 |
19 |
20 | 21 | 22 | 23 | {% endverbatim %} 24 | -------------------------------------------------------------------------------- /templates/cms_base.html: -------------------------------------------------------------------------------- 1 | {% load cms_tags sekizai_tags %} 2 | 3 | 4 | {% page_attribute "page_title" %} 5 | {% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %} 6 | 7 | 8 | {% cms_toolbar %} 9 | {% placeholder cms_base_content %} 10 | {% block base_content %}{% endblock %} 11 | {% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %} 12 | 13 | -------------------------------------------------------------------------------- /templates/cms_template.html: -------------------------------------------------------------------------------- 1 | {% extends "cms_base.html" %} 2 | {% load cms_tags visor_tag %} 3 | 4 | {% block base_content %} 5 | {% placeholder cms_template_content %} 6 | {% endblock %} -------------------------------------------------------------------------------- /templates/field_condition.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 |
9 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 23 |
24 |
25 | 28 |
-------------------------------------------------------------------------------- /templates/fields/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/__init__.py -------------------------------------------------------------------------------- /templates/fields/checkbox/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/checkbox/__init__.py -------------------------------------------------------------------------------- /templates/fields/checkbox/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 |
4 | 5 |
6 |
7 |
8 | 9 | 12 | 13 | 16 |
17 |
18 |
19 | 22 | 23 |
24 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/checkbox/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 8 |
9 |
10 | 17 |
18 |
19 | {% endverbatim %} 20 | {%endblock%} 21 | -------------------------------------------------------------------------------- /templates/fields/checkbox/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 8 |
9 |
10 | 14 |
15 |
16 | {% endverbatim %} 17 | {%endblock%} 18 | -------------------------------------------------------------------------------- /templates/fields/checkbox/template_statistic.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 |
6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Type{{field.type}}
Answered fields{{field.tf}}
Empty fields{{field.tnf}}
Required{{field.req}}
29 | Export PDF 30 | 31 |
32 | {% endverbatim %} 33 | -------------------------------------------------------------------------------- /templates/fields/combobox/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/combobox/__init__.py -------------------------------------------------------------------------------- /templates/fields/combobox/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 |
4 |
5 |
6 |
7 | 8 | 11 | 12 | 15 |
16 |
17 |
18 | 19 | 25 |
26 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/combobox/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 13 | {% endverbatim %} 14 | {%endblock%} 15 | -------------------------------------------------------------------------------- /templates/fields/combobox/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 12 | {% endverbatim %} 13 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/combobox/template_statistic.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 |
6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Type{{field.type}}
Answered fields{{field.tf}}
Empty fields{{field.tnf}}
Required{{field.req}}
29 | Export PDF 30 | 31 |
32 | 33 | {% endverbatim %} 34 | -------------------------------------------------------------------------------- /templates/fields/email/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/email/__init__.py -------------------------------------------------------------------------------- /templates/fields/email/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 | 4 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/email/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 12 | {% endverbatim %} 13 | {%endblock%} 14 | -------------------------------------------------------------------------------- /templates/fields/email/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 9 | {% endverbatim %} 10 | {%endblock%} 11 | -------------------------------------------------------------------------------- /templates/fields/field_edit_template_base.html: -------------------------------------------------------------------------------- 1 | {%verbatim%} 2 | 3 | {%endverbatim%} 4 | {%block field%} 5 | {%endblock%} 6 | -------------------------------------------------------------------------------- /templates/fields/field_properties_base.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Field Properties 4 |
5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | {%verbatim%} 13 | {{editor.selectedField.field_type}} 14 | {%endverbatim%} 15 |
16 |
17 |
18 | 19 | Required 20 | 21 |
22 |
23 | 24 | 26 | Not Required 27 | 28 |
29 |
30 | 31 | {%block validations%} 32 | {%endblock%} 33 |
34 |
-------------------------------------------------------------------------------- /templates/fields/field_template_base.html: -------------------------------------------------------------------------------- 1 |
2 | {%block label%} 3 | {%verbatim%} 4 | 7 | {%endverbatim%} 8 | {%endblock%} 9 | {%block field%} 10 | {%endblock%} 11 |
12 | -------------------------------------------------------------------------------- /templates/fields/file/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 |
4 | 5 |
6 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/file/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 9 | 14 | 15 | 16 | {{fileName(question.answer)}} 17 | 18 | {% endverbatim %} 19 | {%endblock%} 20 | -------------------------------------------------------------------------------- /templates/fields/file/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 8 | 9 | {% endverbatim %} 10 | {%endblock%} 11 | -------------------------------------------------------------------------------- /templates/fields/geolocation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/geolocation/__init__.py -------------------------------------------------------------------------------- /templates/fields/geolocation/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 | 4 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/geolocation/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {% load staticfiles sekizai_tags %} 3 | 4 | {%block field%} 5 | {% verbatim %} 6 | 9 |
11 | {{loadmap(question)}} 12 |
13 | {% endverbatim %} 14 | {%endblock%} 15 | 16 | -------------------------------------------------------------------------------- /templates/fields/geolocation/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | 3 | {%block field%} 4 | {% verbatim %} 5 | 8 |
9 |
10 | {{editor.loadmap(question)}} 11 |
12 |
13 | {% endverbatim %} 14 | {%endblock%} 15 | -------------------------------------------------------------------------------- /templates/fields/identity_doc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/identity_doc/__init__.py -------------------------------------------------------------------------------- /templates/fields/identity_doc/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 | 4 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/identity_doc/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 12 | {% endverbatim %} 13 | {%endblock%} 14 | -------------------------------------------------------------------------------- /templates/fields/identity_doc/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 10 | {% endverbatim %} 11 | {%endblock%} 12 | -------------------------------------------------------------------------------- /templates/fields/number/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/number/__init__.py -------------------------------------------------------------------------------- /templates/fields/number/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 |
4 | 5 | 10 |
11 |
12 | 13 | 18 |
19 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/number/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 9 | 17 | {% endverbatim %} 18 | {%endblock%} 19 | -------------------------------------------------------------------------------- /templates/fields/number/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 8 | 11 | {% endverbatim %} 12 | {%endblock%} 13 | -------------------------------------------------------------------------------- /templates/fields/number/template_statistic.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 |
6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
Type{{field.type}}
Mean{{field.m}}
Total Mean{{field.mt}}
Standard Deviation{{field.sd}}
Total Standard Deviation{{field.sdt}}
Answered fields{{field.tf}}
Empty fields{{field.tnf}}
Required{{field.req}}
43 | Export PDF 44 | 45 |
46 | {% endverbatim %} 47 | -------------------------------------------------------------------------------- /templates/fields/text/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/text/__init__.py -------------------------------------------------------------------------------- /templates/fields/text/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_properties_base.html' %} 2 | {%block validations%} 3 |
4 | Length: 5 | 9 |
10 | {%endblock%} -------------------------------------------------------------------------------- /templates/fields/text/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 15 | {% endverbatim %} 16 | {%endblock%} 17 | 18 | -------------------------------------------------------------------------------- /templates/fields/text/template_edit.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_edit_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 10 | {% endverbatim %} 11 | {%endblock%} 12 | -------------------------------------------------------------------------------- /templates/fields/text_area/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templates/fields/text_area/__init__.py -------------------------------------------------------------------------------- /templates/fields/text_area/properties.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/text/properties.html' %} 2 | -------------------------------------------------------------------------------- /templates/fields/text_area/template.html: -------------------------------------------------------------------------------- 1 | {%extends 'fields/field_template_base.html' %} 2 | {%block field%} 3 | {% verbatim %} 4 | 7 | 8 | 30 | 31 |
32 | 33 |
34 |

After submitting the form

35 | 39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 | 57 | 58 | 59 | 60 | 61 | {% endverbatim %} -------------------------------------------------------------------------------- /templates/preview.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles sekizai_tags load_fields_assets %} 2 | 3 | 4 | 5 | 6 | 7 | {% verbatim %} 8 | Django surveys - {{version.form}} 9 | {% endverbatim %} 10 | {% addtoblock "css" %} 11 | 12 | {% endaddtoblock %} 13 | {% addtoblock "css" %} 14 | 15 | {% endaddtoblock %} 16 | {% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %} 17 | 18 | 19 | 23 |
24 | 25 | 26 | {% addtoblock "js" %} 27 | 28 | {% endaddtoblock %} 29 | {% addtoblock "js" %} 30 | 31 | {% endaddtoblock %} 32 | {% addtoblock "js" %} 33 | 34 | {% endaddtoblock %} 35 | {% addtoblock "js" %} 36 | 37 | {% endaddtoblock %} 38 | {% addtoblock "js" %} 39 | 40 | {% endaddtoblock %} 41 | {% addtoblock "js" %} 42 | 43 | {% endaddtoblock %} 44 | {% addtoblock "js" %} 45 | 46 | {% endaddtoblock %} 47 | {% addtoblock "js" %} 48 | 49 | {% endaddtoblock %} 50 | {% addtoblock "js" %} 51 | 52 | {% endaddtoblock %} 53 | {% addtoblock "js" %} 54 | 55 | {% endaddtoblock %} 56 | {% addtoblock "js" %} 57 | 58 | {% endaddtoblock %} 59 | {% addtoblock "js" %} 60 | 61 | {% endaddtoblock %} 62 | {% fields_assets_block %} 63 | 64 | {% addtoblock "js" %} 65 | 66 | {% endaddtoblock %} 67 | {% addtoblock "js" %} 68 | 69 | {% endaddtoblock %} 70 | {% addtoblock "js" %} 71 | 72 | {% endaddtoblock %} 73 | 74 | {% render_block "jsUnc" %} 75 | {% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %} 76 | 77 | 78 | -------------------------------------------------------------------------------- /templates/preview_template.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 3 |
4 |
5 |
6 |
7 |
8 |

{{version.form}}

9 |
10 |

There was an error loading the form

11 | 12 |
13 | 14 | Notification:
{{notification}} 15 |
16 |
17 |
18 |
19 |
20 |
21 |

{{selectedPage.subTitle}}

22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |

32 | 33 | 34 | 35 |

36 |
37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 | 45 | 49 | 53 |
54 |
55 | 59 |
60 |
61 |
62 |
63 |
64 |
65 | {% endverbatim %} 66 | -------------------------------------------------------------------------------- /templates/responses.html: -------------------------------------------------------------------------------- 1 | {%extends 'base.html' %} 2 | {% load staticfiles sekizai_tags %} 3 | 4 | {%block content%} 5 | {% verbatim %} 6 |
7 |
8 | 9 |
10 |
11 |

12 | Responses: Form: {{responses.formId}} - version: {{responses.versionNumber}} 13 |

14 |
15 |
16 | 17 |
18 | 19 | EXPORT CSV 20 | 21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
    30 |
  • 31 |

    Entry: {{response.entry_time}}

    32 |
      33 |
    • 34 |
      35 | {{field.text}}: {{field.answer}} 36 |
      37 |
      38 | {{field.text}}: {{field.answer}} 39 |
      40 |
    • 41 |
    42 |
  • 43 |
44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 | {% endverbatim %} 52 | {%endblock%} 53 | 54 | {%block scripts%} 55 | {% addtoblock "js" %} 56 | 57 | {% endaddtoblock %} 58 | {% addtoblock "js" %} 59 | 60 | {% endaddtoblock %} 61 | {% addtoblock "js" %} 62 | 63 | {% endaddtoblock %} 64 | {%endblock%} -------------------------------------------------------------------------------- /templates/select_modal.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/versions.html: -------------------------------------------------------------------------------- 1 | {%extends 'base.html' %} 2 | 3 | 4 | {%block content%} 5 |
6 | 7 |
8 | 9 | 10 |
11 |
12 |

13 | Forms 14 |

15 |
16 |
17 |
18 |
19 |
20 | {% for ver in versions %} 21 | {{ ver.number }} 22 | {% endfor %} 23 |
24 |
25 |
26 |
27 | {%endblock%} -------------------------------------------------------------------------------- /templates/visor.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles sekizai_tags load_fields_assets %} 2 | 3 | 4 | 5 | 6 | 7 | {% verbatim %} 8 | Django surveys - {{version.form}} 9 | {% endverbatim %} 10 | {% addtoblock "css" %} 11 | 12 | {% endaddtoblock %} 13 | {% addtoblock "css" %} 14 | 15 | {% endaddtoblock %} 16 | {% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %} 17 | 18 | 19 | 23 |
24 | 25 | 26 | {% addtoblock "js" %} 27 | 28 | {% endaddtoblock %} 29 | {% addtoblock "js" %} 30 | 31 | {% endaddtoblock %} 32 | {% addtoblock "js" %} 33 | 34 | {% endaddtoblock %} 35 | {% addtoblock "js" %} 36 | 37 | {% endaddtoblock %} 38 | {% addtoblock "js" %} 39 | 40 | {% endaddtoblock %} 41 | {% addtoblock "js" %} 42 | 43 | {% endaddtoblock %} 44 | {% addtoblock "js" %} 45 | 46 | {% endaddtoblock %} 47 | {% addtoblock "js" %} 48 | 49 | {% endaddtoblock %} 50 | {% addtoblock "js" %} 51 | 52 | {% endaddtoblock %} 53 | {% fields_assets_block %} 54 | 55 | {% addtoblock "js" %} 56 | 57 | {% endaddtoblock %} 58 | {% addtoblock "js" %} 59 | 60 | {% endaddtoblock %} 61 | {% addtoblock "js" %} 62 | 63 | {% endaddtoblock %} 64 | {% addtoblock "js" %} 65 | 66 | {% endaddtoblock %} 67 | 68 | {% render_block "jsUnc" %} 69 | {% render_block "js"%} 70 | 71 | 72 | -------------------------------------------------------------------------------- /templates/visor_cms.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles sekizai_tags load_fields_assets %} 2 | 3 | 4 | 5 | 6 | {% verbatim %} 7 | Django surveys - {{instance}} 8 | {% endverbatim %} 9 | {% addtoblock "css" %} 10 | 11 | {% endaddtoblock %} 12 | {% addtoblock "css" %} 13 | 14 | {% endaddtoblock %} 15 | 16 |
17 | 22 |
23 |
24 | 25 | {% addtoblock "js" %} 26 | 27 | {% endaddtoblock %} 28 | {% addtoblock "js" %} 29 | 30 | {% endaddtoblock %} 31 | {% addtoblock "js" %} 32 | 33 | {% endaddtoblock %} 34 | {% addtoblock "js" %} 35 | 36 | {% endaddtoblock %} 37 | {% addtoblock "js" %} 38 | 39 | {% endaddtoblock %} 40 | {% addtoblock "js" %} 41 | 42 | {% endaddtoblock %} 43 | {% addtoblock "js" %} 44 | 45 | {% endaddtoblock %} 46 | {% addtoblock "js" %} 47 | 48 | {% endaddtoblock %} 49 | {% addtoblock "js" %} 50 | 51 | {% endaddtoblock %} 52 | 53 | {% fields_assets_block %} 54 | 55 | {% addtoblock "js" %} 56 | 57 | {% endaddtoblock %} 58 | {% addtoblock "js" %} 59 | 60 | {% endaddtoblock %} 61 | {% addtoblock "js" %} 62 | 63 | {% endaddtoblock %} 64 | {% addtoblock "js" %} 65 | 66 | {% endaddtoblock %} 67 | 68 | {% render_block "jsUnc" %} 69 | -------------------------------------------------------------------------------- /templates/visor_template.html: -------------------------------------------------------------------------------- 1 | {% verbatim %} 2 | 3 |
4 | 5 |
6 | 7 | {% endverbatim %} 8 | -------------------------------------------------------------------------------- /templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sparq-Holding-Inc/pulpo-forms-django/60d268faa492ba8256cc32b3108d6a27dabcd40f/templatetags/__init__.py -------------------------------------------------------------------------------- /templatetags/load_fields_assets.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.template.loader import render_to_string 3 | from django.templatetags.static import static 4 | 5 | from classytags.helpers import InclusionTag 6 | 7 | from pulpo_forms.fieldtypes import FieldFactory 8 | 9 | register = template.Library() 10 | 11 | 12 | class fields_assets_block(InclusionTag): 13 | template = 'asset_block_template.html' 14 | 15 | def get_context(self, context): 16 | l = FieldFactory.FieldFactory.get_all_classes() 17 | ret = [] 18 | non_static = [] 19 | styles = [] 20 | for c in l: 21 | ret.extend(c.get_assets()) 22 | non_static.extend(c.get_non_static()) 23 | styles.extend(c.get_styles()) 24 | context['asset_list'] = [] 25 | context['non_static_assets'] = [] 26 | context['style_list'] = [] 27 | # Permanent assets 28 | context['asset_list'].append( 29 | static('js/validators/validatorFactory.js')) 30 | context['asset_list'].append(static('js/fields/FieldFactory.js')) 31 | context['asset_list'].append(static('js/fields/FieldBase.js')) 32 | context['asset_list'].append(static('js/operators/operatorFactory.js')) 33 | context['asset_list'].append(static('js/operators/operatorField.js')) 34 | # Dynamic assets 35 | for elem in ret: 36 | st_elem = static(elem) 37 | if st_elem not in context['asset_list']: 38 | context['asset_list'].append(st_elem) 39 | for elem in non_static: 40 | if elem not in context['non_static_assets']: 41 | context['non_static_assets'].append(elem) 42 | for elem in styles: 43 | st_elem = static(elem) 44 | if st_elem not in context['style_list']: 45 | context['style_list'].append(st_elem) 46 | return context 47 | 48 | def render_tag(self, context): 49 | data = self.get_context(context) 50 | output = render_to_string(self.template, data) 51 | return output 52 | 53 | register.tag(fields_assets_block) 54 | -------------------------------------------------------------------------------- /templatetags/visor_tag.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.template.loader import render_to_string 3 | from django.conf import settings 4 | from django.http import Http404 5 | 6 | from classytags.core import Options 7 | from classytags.arguments import Argument 8 | from classytags.helpers import InclusionTag 9 | 10 | from pulpo_forms.models import Form 11 | from pulpo_forms.fields import PUBLISHED 12 | 13 | register = template.Library() 14 | 15 | 16 | class visor_template_tag(InclusionTag): 17 | """ 18 | Template Tag to include a Form into an existing Page. 19 | Usage: 20 | {% visor_template_tag form %} 21 | where form is the slug of the form to be loaded. 22 | """ 23 | template = 'visor_cms.html' 24 | options = Options( 25 | Argument('form'), 26 | ) 27 | 28 | def get_context(self, context, form): 29 | context['errors'] = "" 30 | try: 31 | f = Form.objects.get(slug=form) 32 | except Form.DoesNotExist: 33 | context['errors'] += "This Form does not exist.\n" 34 | return context 35 | v = f.versions.filter(status=PUBLISHED).first() 36 | if (not v): 37 | context['errors'] += "This Form has no published version.\n" 38 | raise Http404 39 | else: 40 | output = f.slug 41 | base_url = settings.FORMS_BASE_URL 42 | context['instance'] = output 43 | context['base_url'] = base_url 44 | return context 45 | 46 | def render_tag(self, context, form): 47 | data = self.get_context(context, form) 48 | if (data['errors'] != ""): 49 | return render_to_string('404.html', data) 50 | output = render_to_string(self.template, data) 51 | return output 52 | 53 | register.tag(visor_template_tag) 54 | -------------------------------------------------------------------------------- /testing/mainPage_test.js: -------------------------------------------------------------------------------- 1 | describe("MainPage Testing", function() { 2 | 3 | beforeEach(angular.mock.module('dynamicFormsFrameworkAdmin')); 4 | beforeEach(inject(function ($rootScope, $controller, _$location_, _$httpBackend_) { 5 | $location = _$location_; 6 | $location.url('/id/asc/'); 7 | scope = $rootScope.$new(); 8 | createController = function() { 9 | return $controller('MainPageCtrl', { 10 | '$scope': scope, 11 | '$location' : $location, 12 | }); 13 | }; 14 | })); 15 | 16 | it("Testing main modes.", inject(function($controller,$rootScope) { 17 | var ctrl = createController(); 18 | var order = [ 19 | {name: "Id", value: "id"}, 20 | {name: "Owner", value: "owner"}, 21 | {name: "Title", value: "title"}, 22 | ]; 23 | expect(ctrl.orders).toEqual(order); 24 | var param = 'asc'; 25 | ctrl.selectascdsc(param); 26 | expect(ctrl.ascdsc).toEqual(param); 27 | param = 'dsc'; 28 | ctrl.selectascdsc(param); 29 | expect(ctrl.ascdsc).toEqual(param); 30 | expect(ctrl.actualOrder()).toEqual(order[0]); 31 | $location.url('/owner/asc/'); 32 | expect(ctrl.actualOrder()).toEqual(order[1]); 33 | $location.url('/title/asc/'); 34 | expect(ctrl.actualOrder()).toEqual(order[2]); 35 | })); 36 | 37 | }); --------------------------------------------------------------------------------