diff --git a/modules/webdeposit/etc/templates/Makefile.am b/modules/webdeposit/etc/templates/Makefile.am
index dc4bb6c08..b927151b4 100644
--- a/modules/webdeposit/etc/templates/Makefile.am
+++ b/modules/webdeposit/etc/templates/Makefile.am
@@ -1,26 +1,35 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2012 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 templatesdir = $(sysconfdir)/templates
 templates_DATA = \
-		 webdeposit_add.html \
-		 webdeposit_index.html \
-		 webdeposit_index_deposition_types.html
+            webdeposit_add.html \
+            webdeposit_add_action_bar.html \
+            webdeposit_add_base.html \
+            webdeposit_add_field.html \
+            webdeposit_add_field_label.html \
+            webdeposit_add_field_subform.html \
+            webdeposit_add_group_end.html \
+            webdeposit_add_group_start.html \
+            webdeposit_index.html \
+            webdeposit_index_deposition_types.html \
+            webdeposit_widget_plupload.html \
+			webdeposit_myview.html
 
 EXTRA_DIST = $(templates_DATA)
 
 CLEANFILES = *~ *.tmp
diff --git a/modules/webdeposit/etc/templates/webdeposit_add.html b/modules/webdeposit/etc/templates/webdeposit_add.html
index 69f0f0c2a..4a1711db6 100644
--- a/modules/webdeposit/etc/templates/webdeposit_add.html
+++ b/modules/webdeposit/etc/templates/webdeposit_add.html
@@ -1,340 +1,19 @@
 {#
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 #}
-
-{% extends "page.html" %}
-
-{% block header %}
-    {{ super() }}
-    {% js 'js/jquery-ui.min.js', '20-jquery-ui' %}
-    {% js 'js/plupload/plupload.full.js', '50-webdeposit' %}
-    {% js 'js/webdeposit_form.js', '50-webdeposit' %}
-    {% js 'ckeditor/ckeditor.js', '50-ckeditor' %}
-    {% js 'ckeditor/invenio-ckeditor-config.js', '50-ckeditor' %}
-    {% css 'img/jquery-ui/themes/base/jquery.ui.theme.css', '20-jquery-ui' %}
-    {% css 'img/jquery-ui/themes/base/jquery.ui.datepicker.css', '20-jquery-ui' %}
-
-{% endblock %}
-
-{% block body %}
-
-<style>
-
-.ui-autocomplete-loading { background: white url('{{ url_for('static', filename='img/loading.gif') }}') right center no-repeat; }
-
-span.ui-icon.ui-icon-circle-triangle-w { color: transparent; cursor: pointer; }
-span.ui-icon.ui-icon-circle-triangle-e { color: transparent; cursor: pointer; }
-
-.typeahead {
-    max-height: 250px;
-    overflow-y: auto;
-    /* prevent horizontal scrollbar */
-    overflow-x: hidden;
-}
-
-.l{
-    size: 10px;
-}
-
-.required:after {
-    color: red;
-    content:" *";
-}
-
-.rmlink {
-    cursor: pointer;
-    display: block;
-    margin-left: auto;
-    margin-right: auto
-}
-</style>
-
-<div class="page-header">
-  <h2>{{ form._title }}
-  {% if form._drafting %}
-    <small class="pull-right">
-      <small class="muted" id="status-indicator" style="font-size:12px; margin-right:10px;">Saved!</small>
-
-      <a class="btn btn-info"
-         href="{{ url_for('webdeposit.create_new', deposition_type=deposition_type) }}">
-        <i class="icon-edit icon-white"></i> {{ _('New Deposition') }}
-      </a>
-
-      <a class="btn btn-danger"
-         href="{{ url_for('webdeposit.delete', deposition_type=deposition_type, uuid=uuid) }}">
-        <i class="icon-remove icon-white"></i> {{ _('Delete Deposition') }}
-      </a>
-
-
-      <div class="btn-group">
-        <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
-          <i class="icon-list"></i> {{ _('Ongoing Depositions') }}
-          <span class="caret"></span>
-        </a>
-        <ul class="dropdown-menu">
-        {% for draft in drafts %}
-          <li> <a href="{{ url_for('webdeposit.add', deposition_type=draft.workflow.name, uuid=draft.uuid) }}">
-            {{ '<strong>'|safe if uuid == draft.uuid }}
-              {{ draft.workflow.name }}:
-              {% if draft.form_values and draft.form_values.title %}
-                  {{ draft.form_values.title }}
-              {% else %}
-                  {{ _('Untitled') }}
-              {% endif %}
-            {{ '</strong>'|safe if uuid == draft.uuid }}
-            <span style="font-size: 80%;" class="muted">{{ draft.timestamp|invenio_pretty_date }}</span>
-           </a>
-          </li>
-        {% endfor %}
-        </ul>
-      </div>
-
-    </small>
-    <div class="clearfix"></div>
-  {% endif %}
-  </h2>
-</div>
-
-<form enctype="multipart/form-data" name="submitForm"
-      id="submitForm" class="form-horizontal" method="post"
-      action="{{ url_for('webdeposit.add', deposition_type=deposition_type, uuid=uuid) }}">
-  <fieldset>
-
-
-    {% for group, fields in form.get_groups() %}
-
-    {% if loop.index == 1 %}
-    <div class="row">
-    <div id="webdeposit_form_accordion" class="offset1 span8 accordion">
-    {% endif %}
-
-    {% if group.name != 'Rest' %}
-    <div class="accordion-group">
-        <div class="accordion-heading">
-          <a class="accordion-toggle" data-toggle="collapse"
-               href="#collapse-{{ loop.index }}">
-               {{ group.name }} <b class="caret" style="margin-top: 8px;"></b>
-               {% if 'meta' in group and 'indication' in group.meta %}
-                   <span class="pull-right muted">{{ group.meta.indication }}</spani>
-               {% endif %}
-          </a>
-        </div>
-        <div id="collapse-{{ loop.index }}" class="accordion-body collapse in">
-          <div class="accordion-inner">
-    {% else %}
-        <br>
-    {% endif %}
-
-    {% if 'meta' in group and 'description' in group.meta%}
-        <p>{{ group.meta.description }}</p>
-    {% endif %}
-
-    {% for field in fields %}
-
-
-    {% if field.form %}
-
-    {% endif %}
-    <div class="control-group {{ "error" if field.errors }}" id="error-group-{{ field.name }}">
-      <div class="control-label {{ "error" if field.errors }}">
-      {% if "submit" not in field.__html__() and "pluploader" not in field.__html__() %}
-        {% set label_class = (' required' if field.required else '') %}
-        {% if field.form %}
-          <h5>
-            {{ field.label.text }}
-          </h5>
-        {% else %}
-            {{ field.label(class_=label_class) }}
-        {% endif %}
-      {% endif %}
-    </div>
-
-
-    {% if field.form %}
-      </div>
-
-
-        {% for subfield in field.form %}
-
-          <div class="control-group {{ "error" if subfield.errors }}" id="error-group-{{ subfield.name }}">
-
-          <div class="control-label {{ "error" if subfield.errors }}">
-            {% if "submit" not in subfield.__html__() and "pluploader" not in subfield.__html__() %}
-              {% set label_class = (' required' if subfield.required else '') %}
-              {{ subfield.label(class_=label_class) }}
-            {% endif %}
-          </div>
-
-        <div class="controls" id="field-{{ subfield.name }}">
-              {% if subfield._icon_html and "pluploader" not in subfield.__html__() and not field.ckeditor %}
-                <div class="input-prepend">
-                    <span class="add-on">
-                    {{ subfield._icon_html|safe }}
-                    </span>
-              {% elif "pluploader" not in subfield.__html__() and not field.ckeditor %}
-                <div style="margin-left: 27px;">
-              {% else %}
-                <div>
-              {% endif %}
-
-              {{ subfield(class_=field.short_name) }}
-
-              </div>
-
-          {% if subfield.errors %}
-            {% for error in subfield.errors %}
-              <div class="alert alert-error help-inline error-list-{{ subfield.name }}">{{ error }}</div>
-            {% endfor %}
-          {% endif %}
-          <div class="alert alert-error help-inline" id="error-{{ subfield.name }}" style="display:none;">error message</div>
-          <div class="alert alert-info help-inline" id="info-{{ subfield.name }}" style="display:none;">info message</div>
-          <div class="alert alert-success help-inline" id="success-{{ subfield.name }}" style="display:none;">success message</div>
-          </div>
-        </div>
-
-        {% if ("keywords" in field.__html__()) %}
-        <div class="control-group" style="display: none;">
-            <input name="keywords-{{ field.short_name}}" type="text" value="">
-        </div>
-
-        {% endif %}
-
-        {% endfor %}
-
-      <hr>
-
-
-    {% else %}
-
-    <div {% if "pluploader" not in field.__html__() %} class="controls" {% endif %} id="field-{{ field.name }}">
-          {% if field._icon_html and "pluploader" not in field.__html__() and not field.ckeditor %}
-            <div class="input-prepend">
-                <span class="add-on">
-                {{ field._icon_html|safe }}
-                </span>
-          {% elif "pluploader" not in field.__html__() and not field.ckeditor %}
-            <div style="margin-left: 27px;">
-          {% else %}
-            <div>
-          {% endif %}
-              {{ field(class_=field.short_name) }}
-
-              {% if field.description %}
-                  <div class="help-block" style="font-size:12px; width: 350px; white-space:normal; color:#999999;">
-                      {{ field.description }}
-                  </div>
-              {% endif %}
-            </div>
-
-          {% if field.errors %}
-            {% for error in field.errors %}
-              <div class="alert alert-error help-inline error-list-{{ field.name }}">{{ error }}</div>
-            {% endfor %}
-          {% endif %}
-              <div class="alert alert-error help-inline" id="error-{{ field.name }}" style="display:none;">error message</div>
-              <div class="alert alert-info help-inline" id="info-{{ field.name }}" style="display:none;">info message</div>
-              <div class="alert alert-success help-inline" id="success-{{ field.name }}" style="display:none;">success message</div>
-          </div>
-
-        </div>
-
-        {% if ("keywords" in field.__html__()) %}
-        <div class="control-group" style="display: none;">
-          <input name="keywords-{{ field.short_name}}" type="text" value="">
-        </div>
-        {% endif %}
-
-    {% endif %}
-    {% endfor %}
-    {% if group != 'Rest' %}
-        </div>
-        </div>
-        </div>
-    {% endif %}
-    {% endfor %}
-    <div class="alert alert-error offset1 span8" id="empty-fields-error" style="font-size:12px; display:none;"></div>
-    </div>
-
-  </fieldset>
-</form>
-
-
-{% endblock %}
-
-
-{% block javascript %}
-{{ super() }}
-
-<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropbox.js" id="dropboxjs" data-app-key="your_app_key"></script>
-
-<!-- yahooapis is imported for pluploader -->
-<script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
-<script type="text/javascript">
-
-$(document).ready(function() {
-  var required_fields = {{ form.required_field_names|tojson|safe }};
-
-  webdeposit_init_plupload('.pluploader',
-                            '{{ url_for('webdeposit.plupload', deposition_type=deposition_type, uuid=uuid) }}',
-                            '{{ url_for('webdeposit.plupload_delete', uuid=uuid) }}',
-                            '{{ url_for('webdeposit.plupload_get_file', uuid=uuid) }}',
-                            {{ form.files|safe }},
-                            '{{ url_for('webdeposit.upload_from_url', deposition_type=deposition_type, uuid=uuid) }}');
-
-  webdeposit_input_error_check('#submitForm input, #submitForm textarea, #submitForm select',
-                               '{{ url_for("webdeposit.error_check", uuid=uuid) }}',
-                               required_fields);
-
-  webdeposit_check_status('{{ url_for('webdeposit.check_status', uuid=uuid) }}');
-
-
-// Render autocomplete functions and ckeditor
-{% for field in form %}
-    {% if field.autocomplete %}
-        webdeposit_field_autocomplete('input[name="{{ field.name }}"]',
-                                    '{{ url_for("webdeposit.autocomplete",
-                                        uuid=uuid, type=field.name) }}');
-    {% endif %}
-
-    {% if field.ckeditor %}
-        webdeposit_ckeditor_init( '{{ field.id }}',
-                                  '{{ url_for("webdeposit.error_check", uuid=uuid) }}',
-                                  required_fields );
-    {% endif %}
-
-{% endfor %}
-
-  $(".datepicker").datepicker({dateFormat: 'yy-mm-dd'});
-
-  $("input#submitButton").click(function(e ) {
-          e.preventDefault();
-          emptyForm = checkEmptyFields(true, '', required_fields);
-          if (emptyForm[0] == 0){
-              $('#empty-fields-error').hide('slow');
-              $('#submitForm').submit();
-          }
-          else {
-              $('#empty-fields-error').html("These fields are required!</br>" + "<a class='close' data-dismiss='alert' href='#'>×</a>" + emptyForm[1]);
-              $('#empty-fields-error').show('slow');
-          }
-      });
-
-});
-</script>
-
-{% endblock %}
+{% extends "webdeposit_add_base.html" %}
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_action_bar.html b/modules/webdeposit/etc/templates/webdeposit_add_action_bar.html
new file mode 100644
index 000000000..a068ac494
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_action_bar.html
@@ -0,0 +1,10 @@
+<div class="well"{% if margin %}style="margin-top: {{margin}}"{% endif %}>
+    <a class="btn btn-danger pull-left" href="{{ url_for('webdeposit.delete', deposition_type=deposition_type, uuid=uuid) }}"><i class="icon-trash  icon-white"></i> {{ _('Delete') }}</a>
+    <span class="pull-right">
+        <span class="loader"><img src="{{ url_for('static', filename='css/images/ajax-loader.gif' ) }}" /></span>
+        <span class="status-indicator muted"></span>&nbsp;
+        <button class="btn form-save" data-toggle="tooltip" title="{{_('Press "Save" to save your upload for editing later, as many times you like.')}}" ><i class="icon-file"></i> Save</button>
+        <button data-target="#submitModal" data-toggle="modal" role="button" data-toggle="tooltip" title="{{_('Press "Submit" to finalize and make your upload public (further editing afterwards is  currently not possible).')}}" class="btn btn-primary"><i class="icon-ok  icon-white"></i> Submit</button>
+    </span>
+    <span class="clearfix"></span>
+</div>
\ No newline at end of file
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_base.html b/modules/webdeposit/etc/templates/webdeposit_add_base.html
new file mode 100644
index 000000000..557f8d350
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_base.html
@@ -0,0 +1,203 @@
+{#
+## This file is part of Invenio.
+## Copyright (C) 2013 CERN.
+##
+## Invenio is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Invenio is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Invenio; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#}
+{% extends "page.html" %}
+
+
+{% macro form_action_bar(margin="") -%}
+    {% include "webdeposit_add_action_bar.html" %}
+{%- endmacro %}
+
+{%- macro form_group_accordion_start(group, idx) -%}
+    {% include "webdeposit_add_group_start.html" %}
+{%- endmacro -%}
+
+{%- macro form_group_accordion_end(group, idx) -%}
+    {% include "webdeposit_add_group_end.html" %}
+{%- endmacro -%}
+
+{%- macro field_label(thisfield) -%}
+    {% include "webdeposit_add_field_label.html" %}
+{%- endmacro -%}
+
+{%- macro field_display(thisfield, field_class="span5", container_class="control-group") -%}
+    {% include "webdeposit_add_field.html" %}
+{%- endmacro -%}
+
+{%- macro field_display_subform(thisfield) -%}
+    {% include "webdeposit_add_field_subform.html" %}
+{%- endmacro -%}
+
+{% block header %}
+    {{ super() }}
+    {% js 'js/jquery-ui.min.js', '20-jquery-ui' %}
+    {% js 'js/plupload/plupload.full.js', '50-webdeposit' %}
+    {% js 'js/webdeposit_form.js', '50-webdeposit' %}
+    {% js 'js/hogan.js', '40-webdeposit-hogan' %}
+    {% js 'js/webdeposit_templates.js', '50-webdeposit' %}
+    {% js 'ckeditor/ckeditor.js', '50-ckeditor' %}
+    {% js 'ckeditor/invenio-ckeditor-config.js', '50-ckeditor' %}
+    {% css 'img/jquery-ui/themes/base/jquery.ui.theme.css', '20-jquery-ui' %}
+    {% css 'img/jquery-ui/themes/base/jquery.ui.datepicker.css', '20-jquery-ui' %}
+
+<style>
+
+.ui-autocomplete-loading { background: white url('{{ url_for('static', filename='img/loading.gif') }}') right center no-repeat; }
+
+span.ui-icon.ui-icon-circle-triangle-w { color: transparent; cursor: pointer; }
+span.ui-icon.ui-icon-circle-triangle-e { color: transparent; cursor: pointer; }
+
+.typeahead {
+    max-height: 250px;
+    overflow-y: auto;
+    /* prevent horizontal scrollbar */
+    overflow-x: hidden;
+}
+
+.l{
+    size: 10px;
+}
+
+.required:after {
+    color: red;
+    content:" *";
+}
+
+.rmlink {
+    cursor: pointer;
+    display: block;
+    margin-left: auto;
+    margin-right: auto
+}
+</style>
+
+{% endblock %}
+
+{% block body %}
+<div class="row">
+    <div id="file_container" class="span8 form-feedback-warning">
+    <div id="flash-message"></div>
+    <form enctype="multipart/form-data" name="submitForm" id="submitForm" class="form-horizontal" method="post" action="{{ url_for('webdeposit.add', deposition_type=deposition_type, uuid=uuid) }}">
+    {% block form_header scoped %}{{ form_action_bar() }}{% endblock form_header%}
+
+    {% block form_title scoped %}
+        <h1>{{ form._title }}</h1>
+        {% if form._subtitle %}
+            <p class="muted"><small>{{ form._subtitle|safe }}</small></p>
+        {% endif %}
+    {% endblock form_title %}
+
+    {% block form_body scoped %}
+        {% for group, fields in form.get_groups() %}
+            {% set grouploop = loop %}
+            {% block form_group scoped %}
+                {% if grouploop.first %}
+                    <div id="webdeposit_form_accordion" class="accordion">
+                {% endif %}
+                {% block form_group_header scoped %}
+                    {% if group %}
+                        {{ form_group_accordion_start(group, grouploop.index) }}
+                    {% endif %}
+                {% endblock %}
+
+                {% block form_group_body scoped %}
+                    {% if group and group.meta.description %}
+                        <p>{{ group.meta.description|urlize }}</p>
+                    {% endif %}
+
+                    {% block fieldset scoped %}
+                    <fieldset>
+                    {% for field in fields %}
+                        {% block field_body scoped %}
+                            {% if field.form %}
+                                {{ field_display_subform(field) }}
+                            {% else %}
+                                {{ field_display(field) }}
+                            {% endif %}
+                        {% endblock field_body %}
+                    {% endfor %}
+                    </fieldset>
+                    {% endblock fieldset %}
+                {% endblock form_group_body%}
+
+                {% block form_group_footer scoped %}
+                    {% if group %}
+                        {{ form_group_accordion_end(group, grouploop.index) }}
+                    {% endif %}
+
+                {% endblock form_group_footer %}
+
+                {% if grouploop.last %}</div>{% endif %}
+            {% endblock form_group %}
+        {% endfor %}
+    {% endblock form_body %}
+
+    </form>
+    </div>
+    {% if form._drafting %}
+        <div class="span4">
+            {% include "webdeposit_myview.html" %}
+        </div>
+    {% endif %}
+    </div>
+</div>
+{% endblock %}
+
+
+
+{% block javascript %}
+{{ super() }}
+{%- block form_script_options %}
+<script type="text/javascript">
+var date_options = {dateFormat: 'yy-mm-dd'}
+</script>
+{%- endblock form_script_options %}
+<script type="text/javascript" src="https://www.dropbox.com/static/api/1/dropbox.js" id="dropboxjs" data-app-key="{{config.CFG_DROPBOX_API_KEY}}"></script>
+<script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
+<script type="text/javascript">
+$(document).ready(function() {
+    required_fields = {{ form.required_field_names|tojson|safe }};
+
+    webdeposit_init_plupload(
+        '.pluploader',
+        '{{ url_for('webdeposit.plupload', deposition_type=deposition_type, uuid=uuid) }}',
+        '{{ url_for('webdeposit.plupload_delete', uuid=uuid) }}',
+        '{{ url_for('webdeposit.plupload_get_file', uuid=uuid) }}',
+        {{ form.files|safe }},
+        '{{ url_for('webdeposit.upload_from_url', deposition_type=deposition_type, uuid=uuid) }}'
+    );
+    webdeposit_input_error_check('#submitForm input, #submitForm textarea, #submitForm select', '{{ url_for("webdeposit.error_check", uuid=uuid) }}');
+    webdeposit_button_click('#submitForm .form-button', '{{ url_for("webdeposit.error_check", uuid=uuid) }}');
+    webdeposit_check_status('{{ url_for('webdeposit.check_status', uuid=uuid) }}');
+    // Render autocomplete functions and ckeditor
+{%- for field in form %}
+    {%- if field.autocomplete %}
+    webdeposit_field_autocomplete('input[name="{{ field.name }}"]', '{{ url_for("webdeposit.autocomplete", form_type=form.type, field=field.name) }}');
+    {%- endif %}
+    {%- if field.ckeditor %}
+    webdeposit_ckeditor_init( '{{ field.id }}', '{{ url_for("webdeposit.error_check", uuid=uuid) }}');
+    {%- endif %}
+{%- endfor %}
+    $(".datepicker").datepicker();
+
+    // Save & submit buttons
+    webdeposit_init_save('{{ url_for("webdeposit.error_check", uuid=uuid) }}', '.form-save', '#submitForm');
+    webdeposit_init_submit('{{ url_for("webdeposit.error_check", uuid=uuid) }}', '.form-submit', '#submitForm');
+});
+</script>
+{% endblock javascript %}
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_field.html b/modules/webdeposit/etc/templates/webdeposit_add_field.html
new file mode 100644
index 000000000..a0faa203c
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_field.html
@@ -0,0 +1,18 @@
+<div class="{{container_class}} {{ "error" if thisfield.errors }}{{ 'hide' if thisfield.flags.hidden}}" id="state-group-{{ thisfield.name }}">
+
+    {{ field_label(thisfield) }}
+
+    <div class="{{ 'controls' if thisfield.widget.__name__ not in ['plupload_widget'] }}" id="field-{{ thisfield.name }}">
+        {{ thisfield(class_= field_class + " " + thisfield.short_name) }}
+
+        {% if thisfield.description %}
+            <p class="muted field-desc"><small>{{thisfield.description|urlize}}</small></p>
+        {% endif %}
+
+        <div class="alert help-inline {{ 'alert-error' if thisfield.errors else 'hide' }}" id="state-{{ thisfield.name }}" style="margin-top: 5px;">
+            {% for error in thisfield.errors %}
+                <div>{{ error }}</div>
+            {% endfor %}
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_field_label.html b/modules/webdeposit/etc/templates/webdeposit_add_field_label.html
new file mode 100644
index 000000000..7b26ac822
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_field_label.html
@@ -0,0 +1,14 @@
+{% if thisfield.widget.__name__ not in ['plupload_widget'] and not 'button' in thisfield.__html__()|lower %}
+    {% if thisfield.label.text %}
+        {% if thisfield.form %}
+            <h5>{{ thisfield.label.text }}</h5>
+        {% else %}
+            <label class="control-label{{' required' if thisfield.flags.required}}{{ ' error' if thisfield.errors }}" for="{{thisfield.label.field_id}}">
+                {%- if thisfield.icon %}
+                    <span class="" style="margin-right: 5px; margin-top: 5px;"><i class={{ thisfield.icon}}></i></span>
+                {%- endif %}
+                {{ thisfield.label.text }}
+            </label>
+        {% endif %}
+    {% endif %}
+{% endif %}
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_field_subform.html b/modules/webdeposit/etc/templates/webdeposit_add_field_subform.html
new file mode 100644
index 000000000..9a9efa27e
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_field_subform.html
@@ -0,0 +1,7 @@
+<div class="control-group {{ "error" if thisfield.errors }}" id="state-group-{{ thisfield.name }}">
+    {{ field_label(thisfield) }}
+</div>
+{% for subfield in thisfield.form %}
+    {{ field_display( subfield )}}
+{% endfor %}
+<hr />
\ No newline at end of file
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_group_end.html b/modules/webdeposit/etc/templates/webdeposit_add_group_end.html
new file mode 100644
index 000000000..a9ddd69d3
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_group_end.html
@@ -0,0 +1 @@
+    </div></div></div>
\ No newline at end of file
diff --git a/modules/webdeposit/etc/templates/webdeposit_add_group_start.html b/modules/webdeposit/etc/templates/webdeposit_add_group_start.html
new file mode 100644
index 000000000..b56bece60
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_add_group_start.html
@@ -0,0 +1,9 @@
+<div class="accordion-group">
+    <div class="accordion-heading">
+        {% if group.meta.indication %}
+            <span class="accordion-toggle muted pull-right">{{ group.meta.indication }}</span>
+        {% endif %}
+        <a class="accordion-toggle" data-toggle="collapse" href="#collapse-{{ idx }}"> {{ group.name }} <b class="caret" style="margin-top: 8px;"></b></a>
+    </div>
+    <div id="collapse-{{ idx }}" class="accordion-body collapse {{ 'in' if group.meta.classes is none else group.meta.classes }}">
+    <div class="accordion-inner">
\ No newline at end of file
diff --git a/modules/webdeposit/etc/templates/webdeposit_index.html b/modules/webdeposit/etc/templates/webdeposit_index.html
index bc6a85421..72b6a9a32 100644
--- a/modules/webdeposit/etc/templates/webdeposit_index.html
+++ b/modules/webdeposit/etc/templates/webdeposit_index.html
@@ -1,62 +1,93 @@
 {#
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 #}
 
 {% extends "page.html" %}
 {% block body %}
 
 <div class="page-header">
   <h3>
     {{ _(deposition_type) }}
     <small>
       {{ _('select or create deposition') }}
       <a class="btn btn-info pull-right"
          href="{{ url_for('webdeposit.create_new', deposition_type=deposition_type) }}">
         <i class="icon-edit icon-white"></i> {{ _('New Deposition') }}
       </a>
     </small>
   </h3>
 </div>
 
 <div class="row">
   {% if drafts %}
   <ul class="nav nav-tabs nav-stacked offset3 span6">
   {% for draft in drafts %}
     <li> <a href="{{ url_for('webdeposit.add', deposition_type=draft.workflow.name, uuid=draft.uuid) }}">
        <i class="icon-chevron-right pull-right"></i>
        {{ '<strong>'|safe if uuid == draft.uuid }}
         {{ draft.workflow.name }}:
         {% if draft.form_values and draft.form_values.title %}
             {{ draft.form_values.title }}
         {% else %}
             {{ _('Untitled') }}
         {% endif %}
       {{ '</strong>'|safe if uuid == draft.uuid }}
       <span style="font-size: 80%;" class="muted">{{ draft.timestamp|invenio_pretty_date }}</span>
      </a>
     </li>
   {% endfor %}
   </ul>
   {% else %}
   <div class="span12">
     <strong>{{ _('There is no ongoing deposition.') }}</strong>
   </div>
   {% endif %}
 </div>
 
+{% if past_depositions %}
+
+<div class="row" style="margin-top: 22px;">
+  <ul class="nav nav-list">
+  <li class="divider" style="overflow: visible;"></li>
+</ul>
+
+  <h4 class="offset2"style="margin-top: 25px;">Past depositions</h4>
+
+   <ul class="nav nav-tabs nav-stacked offset3 span6">
+       {% for dep in past_depositions %}
+      {% if dep.extra_data.recid %}
+          <li> <a href="/record/{{ dep.extra_data.recid }}">
+           <i class="icon-chevron-right pull-right"></i>
+            {{ dep.name }}:
+            {% if dep.extra_data.title %}
+                {{ dep.extra_data.title }}
+            {% else %}
+                {{ _('Untitled') }}
+            {% endif %}
+         </a>
+         </li>
+     {% endif %}
+  {% endfor %}
+  </ul>
+
+
+</div>
+
+{% endif %}
+
 {% endblock %}
diff --git a/modules/webdeposit/etc/templates/webdeposit_myview.html b/modules/webdeposit/etc/templates/webdeposit_myview.html
new file mode 100644
index 000000000..b9861cb2d
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_myview.html
@@ -0,0 +1,20 @@
+<div class="well">
+    <h2>My uploads</h2>
+    {% if not drafts %}
+    <p class="muted">You currently have no uploads.</p>
+    {% else %}
+    <h4>Unsubmitted</h4>
+    <table class="table table-striped">
+    {% for draft in drafts %}
+    <tr>
+        <td><a href="{{ url_for('webdeposit.add', deposition_type=draft.workflow.name, uuid=draft.uuid) }}">{% if draft.form_values and draft.form_values.title %}
+                  {{ draft.form_values.title }}
+              {% else %}
+                  {{ _('Untitled') }}
+              {% endif %}</a></td><td>{{ draft.timestamp|invenio_pretty_date }}</td><td><a href="{{ url_for('webdeposit.delete', deposition_type=deposition_type, uuid=uuid) }}" class="rmlink" rel="tooltip" title="Delete upload"><i class="icon-trash"></i></a></td>
+    </tr>
+    {% endfor %}
+    </table>
+    {% endif %}
+</div>
+
diff --git a/modules/webdeposit/etc/templates/webdeposit_widget_plupload.html b/modules/webdeposit/etc/templates/webdeposit_widget_plupload.html
new file mode 100644
index 000000000..a9c4aaa83
--- /dev/null
+++ b/modules/webdeposit/etc/templates/webdeposit_widget_plupload.html
@@ -0,0 +1,25 @@
+<div class="pluploader" {{field_id}}>
+    <div class="well" id="filebox">
+        <div id="drag_and_drop_text" style="text-align:center;z-index:-100;">
+            <h1><small>Drag and Drop files here</small></h1>
+        </div>
+    </div>
+    <table id="file-table" class="table table-striped table-bordered" style="display:none;">
+        <thead>
+            <tr>
+            <th>Filename</th>
+            <th>Size</th>
+            <th>Status</th>
+            <td></td>
+            </tr>
+        </thead>
+        <tbody id="filelist">
+        </tbody>
+    </table>
+    <a class="btn btn-primary" id="pickfiles" >Select files</a>
+    <a class="btn btn-success disabled" id="uploadfiles"><i class="icon-upload icon-white"></i> Start upload</a>
+    <a class="btn btn-danger" id="stopupload"
+    style="display:none;"><i class="icon-stop icon-white"></i> Cancel upload</a>
+    <span id="upload_speed" class="pull-right"></span>
+    <div id="upload-errors"></div>
+</div>
diff --git a/modules/webdeposit/lib/Makefile.am b/modules/webdeposit/lib/Makefile.am
index 5a31b075c..4e89e1eda 100644
--- a/modules/webdeposit/lib/Makefile.am
+++ b/modules/webdeposit/lib/Makefile.am
@@ -1,48 +1,51 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 SUBDIRS = deposition_forms deposition_fields deposition_types
 
 pylibdir = $(libdir)/python/invenio
 
 pylib_DATA = __init__.py \
+             webdeposit_autocomplete_utils.py \
+			 webdeposit_api_blueprint.py \
              webdeposit_blueprint.py \
-             webdeposit_utils.py \
+             webdeposit_cook_json_utils.py \
+             webdeposit_field.py \
+             webdeposit_field_widgets.py \
+             webdeposit_filter_utils.py \
+             webdeposit_form.py \
+             webdeposit_load_deposition_types.py \
              webdeposit_load_fields.py \
              webdeposit_load_forms.py \
-             webdeposit_load_deposition_types.py \
-             webdeposit_field_widgets.py \
              webdeposit_model.py \
+             webdeposit_processor_utils.py \
+             webdeposit_regression_tests.py \
+             webdeposit_utils.py \
+             webdeposit_validation_utils.py \
              webdeposit_workflow.py \
              webdeposit_workflow_utils.py \
-             webdeposit_field.py \
-             webdeposit_autocomplete_utils.py \
-             webdeposit_validation_utils.py \
-             webdeposit_config.py \
-             webdeposit_config_utils.py \
-             webdeposit_form.py \
-             webdeposit_cook_json_utils.py \
-             webdeposit_regression_tests.py
+			 webdeposit_api_regression_tests.py
 
 jsdir=$(localstatedir)/www/js
 
-js_DATA = webdeposit_form.js
+js_DATA = webdeposit_form.js \
+          webdeposit_templates.js
 
 EXTRA_DIST = $(pylib_DATA) \
              $(js_DATA)
 
 CLEANFILES = *~ *.tmp *.pyc
diff --git a/modules/webdeposit/lib/deposition_fields/Makefile.am b/modules/webdeposit/lib/deposition_fields/Makefile.am
index 9cf412d23..7d0a70706 100644
--- a/modules/webdeposit/lib/deposition_fields/Makefile.am
+++ b/modules/webdeposit/lib/deposition_fields/Makefile.am
@@ -1,37 +1,38 @@
 ## This file is part of Invenio.
 ## Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 pylibdir = $(libdir)/python/invenio/webdeposit_deposition_fields
 
 pylib_DATA = __init__.py \
              author_field.py \
-             integer_text_field.py \
              journal_field.py \
              publisher_field.py \
              title_field.py \
              date_field.py \
              abstract_field.py \
              file_upload_field.py \
              issn_field.py \
              keywords_field.py \
              language_field.py \
              notes_field.py \
              pages_number_field.py \
              doi_field.py \
-             record_id_field.py
+             record_id_field.py \
+             wtforms_field.py \
+			 record_id_field.py
 
 CLEANFILES = *~ *.tmp *.pyc
diff --git a/modules/webdeposit/lib/deposition_fields/abstract_field.py b/modules/webdeposit/lib/deposition_fields/abstract_field.py
index 674c707bb..f4be36412 100644
--- a/modules/webdeposit/lib/deposition_fields/abstract_field.py
+++ b/modules/webdeposit/lib/deposition_fields/abstract_field.py
@@ -1,34 +1,34 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextAreaField
 from invenio.webdeposit_field import WebDepositField
 
-__all__ = ['AbstractField']
 
+__all__ = ['AbstractField']
 
-class AbstractField(WebDepositField(key='abstract.summary'), TextAreaField):
 
+class AbstractField(WebDepositField, TextAreaField):
     def __init__(self, **kwargs):
-        super(AbstractField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-pencil"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
-
+        defaults = dict(
+            icon='icon-pencil',
+            recjson_key='abstract.summary'
+        )
+        defaults.update(kwargs)
+        super(AbstractField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/author_field.py b/modules/webdeposit/lib/deposition_fields/author_field.py
index fc3eed5e6..cbd5699be 100644
--- a/modules/webdeposit/lib/deposition_fields/author_field.py
+++ b/modules/webdeposit/lib/deposition_fields/author_field.py
@@ -1,42 +1,35 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
 from invenio.webdeposit_autocomplete_utils import orcid_authors
 
 __all__ = ['AuthorField']
 
 
-class AuthorField(WebDepositField(key='authors[0].full_name'), TextField):
-
+class AuthorField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(AuthorField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-user"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
-
-    def autocomplete(self):
-        # Load custom autocompletion function
-        autocomplete = self.config.get_autocomplete_function()
-        if autocomplete is not None:
-            return autocomplete(self.data)
-
-        return orcid_authors(self.data)
+        defaults = dict(
+            icon='icon-user',
+            recjson_key='authors[0].full_name',
+            autocomplete=orcid_authors
+        )
+        defaults.update(kwargs)
+        super(AuthorField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/date_field.py b/modules/webdeposit/lib/deposition_fields/date_field.py
index f49b42842..1f022c401 100644
--- a/modules/webdeposit/lib/deposition_fields/date_field.py
+++ b/modules/webdeposit/lib/deposition_fields/date_field.py
@@ -1,33 +1,60 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import DateField
+from wtforms.validators import optional
 from invenio.webdeposit_field import WebDepositField
+from datetime import date, datetime
 
 __all__ = ['Date']
 
 
-class Date(WebDepositField(), DateField):
-
+class Date(WebDepositField, DateField):
     def __init__(self, **kwargs):
-        super(Date, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-calendar"></i>'
+        defaults = dict(
+            icon='icon-calendar',
+            validators=[optional()]
+        )
+        defaults.update(kwargs)
+        super(Date, self).__init__(**defaults)
+
+    def json_data(self):
+        """
+        Serialize data into JSON serializalbe object
+        """
+        # Just use _value() to format the date into a string.
+        if self.data:
+            return self.data.strftime(self.format) #pylint: disable-msg=
+        return None
 
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+    def process_data(self, value):
+        """
+        Called when loading data from Python (incoming objects can be either
+        datetime objects or strings, depending on if they are loaded from
+        an JSON or Python objects).
+        """
+        if isinstance(value, basestring):
+            self.object_data = datetime.strptime(value, self.format).date()
+        elif isinstance(value, datetime):
+            self.object_data = value.date()
+        elif isinstance(value, date):
+            self.object_data = value
+        # Be sure to set both self.object_data and self.data due to internals of
+        # Field.process() and draft_form_process_and_validate().
+        self.data = self.object_data
diff --git a/modules/webdeposit/lib/deposition_fields/doi_field.py b/modules/webdeposit/lib/deposition_fields/doi_field.py
index a0868f4d5..92df54bd7 100644
--- a/modules/webdeposit/lib/deposition_fields/doi_field.py
+++ b/modules/webdeposit/lib/deposition_fields/doi_field.py
@@ -1,43 +1,59 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
-from invenio.webdeposit_validation_utils import datacite_doi_validate
+from invenio.webdeposit_validation_utils import doi_syntax_validator
+from invenio.webdeposit_filter_utils import strip_prefixes, strip_string
+from invenio.webdeposit_processor_utils import datacite_lookup
 
 __all__ = ['DOIField']
 
 
-class DOIField(WebDepositField(key='publication_info.DOI'), TextField):
+def missing_doi_warning(dummy_form, field, dummy_submit=False):
+    """
+    Field processor, checking for existence of a DOI, and otherwise
+    asking people to provide it.
+    """
+    if not field.errors and not field.data:
+        field.message_state = "warning"
+        field.messages.append("Please provide a DOI if possible.")
+        raise StopIteration()
 
-    def __init__(self, **kwargs):
-        super(DOIField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-barcode"></i>'
-
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
 
-            return validation_json
-        return datacite_doi_validate(self)
+class DOIField(WebDepositField, TextField):
+    def __init__(self, **kwargs):
+        defaults = dict(
+            icon='icon-barcode',
+            recjson_key='publication_info.DOI',
+            validators=[
+                doi_syntax_validator,
+            ],
+            filters=[
+                strip_string,
+                strip_prefixes("doi:", "http://dx.doi.org/"),
+            ],
+            processors=[
+                missing_doi_warning,
+                datacite_lookup(display_info=True),
+            ],
+            placeholder="e.g. 10.1234/foo.bar...",
+        )
+        defaults.update(kwargs)
+        super(DOIField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/file_upload_field.py b/modules/webdeposit/lib/deposition_fields/file_upload_field.py
index 5418ec64f..d03a7c87a 100644
--- a/modules/webdeposit/lib/deposition_fields/file_upload_field.py
+++ b/modules/webdeposit/lib/deposition_fields/file_upload_field.py
@@ -1,33 +1,30 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import FileField
 from invenio.webdeposit_field import WebDepositField
 
 __all__ = ['FileUploadField']
 
 
-class FileUploadField(WebDepositField(), FileField):
-
+class FileUploadField(WebDepositField, FileField):
     def __init__(self, **kwargs):
-        super(FileUploadField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-file"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+        defaults = dict(icon='icon-file')
+        defaults.update(kwargs)
+        super(FileUploadField, self).__init__(**defaults)
\ No newline at end of file
diff --git a/modules/webdeposit/lib/deposition_fields/integer_text_field.py b/modules/webdeposit/lib/deposition_fields/integer_text_field.py
index 4d5fd7879..e6c9b9def 100644
--- a/modules/webdeposit/lib/deposition_fields/integer_text_field.py
+++ b/modules/webdeposit/lib/deposition_fields/integer_text_field.py
@@ -1,32 +1,28 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import IntegerField
 from invenio.webdeposit_field import WebDepositField
 
 __all__ = ['IntegerTextField']
 
 
-class IntegerTextField(WebDepositField(), IntegerField):
-
-    def __init__(self, **kwargs):
-        super(IntegerTextField, self).__init__(**kwargs)
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+class IntegerTextField(WebDepositField, IntegerField):
+    # FIXME is field needed?
+    pass
\ No newline at end of file
diff --git a/modules/webdeposit/lib/deposition_fields/issn_field.py b/modules/webdeposit/lib/deposition_fields/issn_field.py
index e5662ad38..76d5dff75 100644
--- a/modules/webdeposit/lib/deposition_fields/issn_field.py
+++ b/modules/webdeposit/lib/deposition_fields/issn_field.py
@@ -1,42 +1,34 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
-from invenio.webdeposit_validation_utils import sherpa_romeo_issn_validate
+#from invenio.webdeposit_processor_utils import sherpa_romeo_issn_validate
 
 __all__ = ['ISSNField']
 
-
-class ISSNField(WebDepositField(key='issn'), TextField):
-
+class ISSNField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(ISSNField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-barcode"></i>'
-
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
-            return validation_json
-        return sherpa_romeo_issn_validate(self)
+        defaults = dict(
+            icon='icon-barcode',
+            recjson_key='issn',
+            #validators=[sherpa_romeo_issn_validate] #FIXME
+        )
+        defaults.update(kwargs)
+        super(ISSNField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/journal_field.py b/modules/webdeposit/lib/deposition_fields/journal_field.py
index 4a4814e54..d205308dd 100644
--- a/modules/webdeposit/lib/deposition_fields/journal_field.py
+++ b/modules/webdeposit/lib/deposition_fields/journal_field.py
@@ -1,51 +1,66 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
 from invenio.webdeposit_autocomplete_utils import sherpa_romeo_journals
-from invenio.webdeposit_validation_utils import sherpa_romeo_journal_validate
+from invenio.webdeposit_processor_utils import sherpa_romeo_journal_process
 
 __all__ = ['JournalField']
 
 
-class JournalField(WebDepositField(), TextField):
-
+class JournalField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(JournalField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-book"></i>'
-
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
-
-            return validation_json
-        return sherpa_romeo_journal_validate(self)
-
-    def autocomplete(self):
-        # Load custom autocompletion function
-        autocomplete = self.config.get_autocomplete_function()
-        if autocomplete is not None:
-            return autocomplete(self.data)
-        return sherpa_romeo_journals(self.data)
+        defaults = dict(
+            icon='icon-book',
+            processors=[sherpa_romeo_journal_process],
+            autocomplete=sherpa_romeo_journals,
+        )
+        defaults.update(kwargs)
+        super(JournalField, self).__init__(**defaults)
+
+
+
+# from wtforms import TextField
+# from invenio.bibknowledge import get_kb_mappings
+# from invenio.webdeposit_field import WebDepositField
+
+# __all__ = ['JournalField']
+
+
+# def _kb_transform(val):
+#     ret = {}
+#     ret['value'] = val['key']
+#     ret['label'] = val['key']
+#     return ret
+
+
+# class JournalField(WebDepositField, TextField):
+
+#     def __init__(self, **kwargs):
+#         self._icon_html = ''
+#         super(JournalField, self).__init__(**kwargs)
+
+#     def pre_validate(self, form):
+#         return dict(error=0, error_message='')
+
+#     def autocomplete(self, term, limit):
+#         if not term:
+#             term = ''
+#         return map(_kb_transform, get_kb_mappings('journal_name', '', term)[:limit])
diff --git a/modules/webdeposit/lib/deposition_fields/keywords_field.py b/modules/webdeposit/lib/deposition_fields/keywords_field.py
index 040c339ac..429a10cb5 100644
--- a/modules/webdeposit/lib/deposition_fields/keywords_field.py
+++ b/modules/webdeposit/lib/deposition_fields/keywords_field.py
@@ -1,33 +1,35 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
 
 __all__ = ['KeywordsField']
 
 
-class KeywordsField(WebDepositField(), TextField):
+class KeywordsField(WebDepositField, TextField):
 
     def __init__(self, **kwargs):
-        super(KeywordsField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-tags"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+        defaults = dict(
+            icon='icon-tags',
+            #validators=[sherpa_romeo_journal_validate], #FIXME
+            #autocomplete=sherpa_romeo_journals,
+        )
+        defaults.update(kwargs)
+        super(KeywordsField, self).__init__(**defaults)
\ No newline at end of file
diff --git a/modules/webdeposit/lib/deposition_fields/language_field.py b/modules/webdeposit/lib/deposition_fields/language_field.py
index 31cfc7444..19315d3fe 100644
--- a/modules/webdeposit/lib/deposition_fields/language_field.py
+++ b/modules/webdeposit/lib/deposition_fields/language_field.py
@@ -1,33 +1,33 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import SelectField
 from invenio.webdeposit_field import WebDepositField
+from wtforms.validators import optional
 
 __all__ = ['LanguageField']
 
 
-class LanguageField(WebDepositField(key='language'), SelectField):
-
+class LanguageField(WebDepositField, SelectField):
     def __init__(self, **kwargs):
-        super(LanguageField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-flag"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+        defaults = dict(icon='icon-flag',
+                        recjson_key='language',
+                        validators=[optional()])
+        defaults.update(kwargs)
+        super(LanguageField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/notes_field.py b/modules/webdeposit/lib/deposition_fields/notes_field.py
index 432c70d68..2ed5e4931 100644
--- a/modules/webdeposit/lib/deposition_fields/notes_field.py
+++ b/modules/webdeposit/lib/deposition_fields/notes_field.py
@@ -1,33 +1,32 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextAreaField
 from invenio.webdeposit_field import WebDepositField
 
 __all__ = ['NotesField']
 
 
-class NotesField(WebDepositField(), TextAreaField):
-
+class NotesField(WebDepositField, TextAreaField):
     def __init__(self, **kwargs):
-        super(NotesField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-list"></i>'
-
-    def pre_validate(self, form=None):
-        return dict(error=0, error_message='')
+        defaults = dict(
+            icon='icon-list',
+        )
+        defaults.update(kwargs)
+        super(NotesField, self).__init__(**defaults)
\ No newline at end of file
diff --git a/modules/webdeposit/lib/deposition_fields/pages_number_field.py b/modules/webdeposit/lib/deposition_fields/pages_number_field.py
index 9ba182358..1a31e7333 100644
--- a/modules/webdeposit/lib/deposition_fields/pages_number_field.py
+++ b/modules/webdeposit/lib/deposition_fields/pages_number_field.py
@@ -1,45 +1,34 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
-from invenio.webdeposit_validation_utils import number_validate
+#from invenio.webdeposit_validation_utils import number_validate
 
 __all__ = ['PagesNumberField']
 
 
-class PagesNumberField(WebDepositField(), TextField):
-
+class PagesNumberField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(PagesNumberField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-th"></i>'
-
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
-
-            return validation_json
-
-        # Default validation
-        return number_validate(self, error_message='Pages must be a number!')
+        defaults = dict(
+            icon='icon-th',
+            #FIXMEvalidators=[number_validate(error_message='Pages must be a number!')] #FIXME
+        )
+        defaults.update(kwargs)
+        super(PagesNumberField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/publisher_field.py b/modules/webdeposit/lib/deposition_fields/publisher_field.py
index 89dc875fc..4abfdebb9 100644
--- a/modules/webdeposit/lib/deposition_fields/publisher_field.py
+++ b/modules/webdeposit/lib/deposition_fields/publisher_field.py
@@ -1,50 +1,47 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
-from invenio.webdeposit_validation_utils import sherpa_romeo_publisher_validate
+from invenio.webdeposit_processor_utils import sherpa_romeo_publisher_process
 from invenio.webdeposit_autocomplete_utils import sherpa_romeo_publishers
 
 __all__ = ['PublisherField']
 
 
-class PublisherField(WebDepositField(), TextField):
-
+class PublisherField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(PublisherField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-certificate"></i>'
+        defaults = dict(
+            icon='icon-certificate',
+            processors=[sherpa_romeo_publisher_process],
+            autocomplete=sherpa_romeo_publishers
+        )
+        defaults.update(kwargs)
+        super(PublisherField, self).__init__(**defaults)
 
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
-            return validation_json
-        return sherpa_romeo_publisher_validate(self)
+    # def post_process(self, form, extra_processors=[]):
+    #     sherpa_romeo_publisher_validate(self, form) #FIXME
+    #     super(PublisherField, self).post_process(form, extra_processors=extra_processors)
 
-    def autocomplete(self):
-        # Load custom autocompletion function
-        autocomplete = self.config.get_autocomplete_function()
-        if autocomplete is not None:
-            return autocomplete(self.data)
-        return sherpa_romeo_publishers(self.data)
+    # def autocomplete(self, term, limit): #FIXME
+    #      # Load custom auto complete function
+    #     autocomplete = self.config.get_autocomplete_function()
+    #     if autocomplete is not None:
+    #         return autocomplete(self.data)
+    #     return sherpa_romeo_publishers(self.data)
diff --git a/modules/webdeposit/lib/deposition_fields/record_id_field.py b/modules/webdeposit/lib/deposition_fields/record_id_field.py
index 723e40592..d696b69d8 100644
--- a/modules/webdeposit/lib/deposition_fields/record_id_field.py
+++ b/modules/webdeposit/lib/deposition_fields/record_id_field.py
@@ -1,35 +1,37 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms import TextField
 from invenio.webdeposit_field import WebDepositField
-from invenio.webdeposit_validation_utils import record_id_validate
+from invenio.webdeposit_processor_utils import record_id_process
 
 __all__ = ['RecordIDField']
 
 
-class RecordIDField(WebDepositField(key='recid'), TextField):
+class RecordIDField(WebDepositField, TextField):
     """ Used to update existing records """
 
     def __init__(self, **kwargs):
-        super(RecordIDField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-barcode"></i>'
-
-    def pre_validate(self, form=None):
-        return record_id_validate(self, form)
+        defaults = dict(
+            icon='icon-barcode',
+            recjson_key='recid',
+            processors=[record_id_process]
+        )
+        defaults.update(kwargs)
+        super(RecordIDField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/title_field.py b/modules/webdeposit/lib/deposition_fields/title_field.py
index 79da8caa4..ff09e52b5 100644
--- a/modules/webdeposit/lib/deposition_fields/title_field.py
+++ b/modules/webdeposit/lib/deposition_fields/title_field.py
@@ -1,54 +1,46 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-from wtforms import TextField
+from wtforms import TextField, ValidationError
 from invenio.webdeposit_field import WebDepositField
 
 __all__ = ['TitleField']
 
 
-class TitleField(WebDepositField(key='title.title'), TextField):
+def validate_title(form, field):
+    value = field.data or ''
+    # Empty string allowed (required validator may be defined on per-field basis)
+    if value == "" or value.isspace():
+        return
 
+    error_message = ''
+    if len(value) <= 4:
+        raise ValidationError("This field must have at least 4 characters")
+
+
+class TitleField(WebDepositField, TextField):
     def __init__(self, **kwargs):
-        super(TitleField, self).__init__(**kwargs)
-        self._icon_html = '<i class="icon-book"></i>'
-
-    def pre_validate(self, form=None):
-        # Load custom validation
-        validators = self.config.get_validators()
-        if validators is not [] and validators is not None:
-            validation_json = {}
-            for validator in validators:
-                json = validator(self)
-                validation_json = self.merge_validation_json(validation_json, json)
-            return validation_json
-
-        value = self.data
-        if value == "" or value.isspace():
-            return dict(error=0, error_message='')
-        error_message = 'Document Title must have at least 4 characters'
-        if len(str(value)) < 4:
-            try:
-                self.errors.append(error_message)
-            except AttributeError:
-                self.errors = list(self.process_errors)
-                self.errors.append(error_message)
-            return dict(error=1,
-                        error_message=error_message)
-        return dict(error=0, error_message='')
+        defaults = dict(
+            icon='icon-book',
+            recjson_key='title.title',
+            #FIXMEvalidators=[validate_title]
+
+        )
+        defaults.update(kwargs)
+        super(TitleField, self).__init__(**defaults)
diff --git a/modules/webdeposit/lib/deposition_fields/wtforms_field.py b/modules/webdeposit/lib/deposition_fields/wtforms_field.py
new file mode 100644
index 000000000..2e67b053e
--- /dev/null
+++ b/modules/webdeposit/lib/deposition_fields/wtforms_field.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+##
+## This file is part of Invenio.
+## Copyright (C) 2013 CERN.
+##
+## Invenio is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Invenio is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Invenio; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+"""
+This module makes all WTForms fields available in WebDeposit, and ensure that
+they subclass WebDepositField for added functionality
+
+The code is basically identical to importing all the WTForm fields and for each
+field make a subclass according to the pattern (using FloatField as
+an example)::
+
+    class FloatField(WebDepositField, wtforms.FloatField):
+        pass
+"""
+
+import wtforms
+from invenio.webdeposit_field import WebDepositField
+
+
+__all__ = []
+
+for attr_name in dir(wtforms):
+    attr = getattr(wtforms, attr_name)
+    try:
+        if issubclass(attr, wtforms.Field):
+            # From a WTForm field, dynamically create a new class the same name as
+            # the WTForm field (inheriting from WebDepositField() and the WTForm
+            # field itself). Store the new class in the current module with the
+            # same name as the WTForms.
+            #
+            # For further information please see Python reference documne for
+            # globals() and type() functions.
+            globals()[attr_name] = type(str(attr_name), (WebDepositField, attr), {})
+            __all__.append(attr_name)
+    except TypeError:
+        pass
diff --git a/modules/webdeposit/lib/deposition_forms/article_form.py b/modules/webdeposit/lib/deposition_forms/article_form.py
index e2ac3b8cf..ff5645eb8 100644
--- a/modules/webdeposit/lib/deposition_forms/article_form.py
+++ b/modules/webdeposit/lib/deposition_forms/article_form.py
@@ -1,82 +1,92 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
 
-from wtforms import SubmitField
 from wtforms.validators import Required
+from invenio.config import CFG_SITE_SUPPORT_EMAIL
 from invenio.webinterface_handler_flask_utils import _
 from invenio.webdeposit_form import WebDepositForm as Form
 from invenio.webdeposit_field_widgets import date_widget, plupload_widget, \
                                              bootstrap_submit
-
-# Import custom fields
 from invenio.webdeposit_load_fields import fields
 __all__ = ['ArticleForm']
 
 
 class ArticleForm(Form):
 
-    doi = fields.DOIField(label=_('DOI'))
+    doi = fields.DOIField(label=_('DOI'), recjson_key='publication_info.DOI')
     publisher = fields.PublisherField(label=_('Publisher'),
-                                      validators=[Required()])
+                                      validators=[Required()],
+                                      recjson_key='imprint.publisher_name')
     journal = fields.JournalField(label=_('Journal Title'),
                                   validators=[Required()])
-    issn = fields.ISSNField(label=_('ISSN'))
-    title = fields.TitleField(label=_('Document Title'))
-    author = fields.AuthorField(label=_('Author'))
-    abstract = fields.AbstractField(label=_('Abstract'))
+    issn = fields.ISSNField(label=_('ISSN'), recjson_key='issn')
+    title = fields.TitleField(label=_('Document Title'),
+                              recjson_key='title.title')
+    author = fields.AuthorField(label=_('Author'),
+                                recjson_key='authors[0].full_name')
+    abstract = fields.AbstractField(label=_('Abstract'),
+                                    recjson_key='abstract.summary')
     pagesnum = fields.PagesNumberField(label=_('Number of Pages'))
     languages = [("en", _("English")),
-                ("fre", _("French")),
-                ("ger", _("German")),
-                ("dut", _("Dutch")),
-                ("ita", _("Italian")),
-                ("spa", _("Spanish")),
-                ("por", _("Portuguese")),
-                ("gre", _("Greek")),
-                ("slo", _("Slovak")),
-                ("cze", _("Czech")),
-                ("hun", _("Hungarian")),
-                ("pol", _("Polish")),
-                ("nor", _("Norwegian")),
-                ("swe", _("Swedish")),
-                ("fin", _("Finnish")),
-                ("rus", _("Russian"))]
+                 ("fre", _("French")),
+                 ("ger", _("German")),
+                 ("dut", _("Dutch")),
+                 ("ita", _("Italian")),
+                 ("spa", _("Spanish")),
+                 ("por", _("Portuguese")),
+                 ("gre", _("Greek")),
+                 ("slo", _("Slovak")),
+                 ("cze", _("Czech")),
+                 ("hun", _("Hungarian")),
+                 ("pol", _("Polish")),
+                 ("nor", _("Norwegian")),
+                 ("swe", _("Swedish")),
+                 ("fin", _("Finnish")),
+                 ("rus", _("Russian"))]
     language = fields.LanguageField(label=_('Language'), choices=languages)
-    date = fields.Date(label=_('Date of Document'), widget=date_widget)
+    date = fields.Date(label=_('Date of Document'), widget=date_widget,
+                       recjson_key='imprint.date')
     keywords = fields.KeywordsField(label=_('Keywords'))
-    notes = fields.NotesField(label=_('Notes'))
+    notes = fields.NotesField(label=_('Notes'), recjson_key='comment')
     plupload_file = fields.FileUploadField(widget=plupload_widget)
-    submit = SubmitField(label=_('Submit Article'),
-                         widget=bootstrap_submit)
+    submit = fields.SubmitField(label=_('Submit Article'),
+                                widget=bootstrap_submit)
 
     """ Form Configuration variables """
     _title = _('Submit an Article')
+    _subtitle = 'Instructions: (i) Press "Save" to save your upload for editing'\
+                'later, as many times you like. (ii) Upload and remove extra files in the'\
+                'bottom of the form. (iii) When ready, press "Submit" to finalize and make'\
+                'your upload public (editing afterwards only possible via submitting changes'\
+                'to <a class="muted"'\
+                'href="mailto:' + CFG_SITE_SUPPORT_EMAIL + '">' +\
+                CFG_SITE_SUPPORT_EMAIL+'</a>).'
     _drafting = True   # enable and disable drafting
 
     # Group fields in categories
 
     groups = [
         ('Publisher/Journal',
             ['doi', 'publisher', 'journal', 'issn'],
             {'description': "Publisher and Journal fields are required.",
              'indication': 'required'}),
         ('Basic Information',
             ['title', 'author', 'abstract', 'pagesnum']),
         ('Other', ['language', 'date', 'keywords', 'notes'])
     ]
diff --git a/modules/webdeposit/lib/deposition_forms/photo_form.py b/modules/webdeposit/lib/deposition_forms/photo_form.py
index 79870e891..33eecd69e 100644
--- a/modules/webdeposit/lib/deposition_forms/photo_form.py
+++ b/modules/webdeposit/lib/deposition_forms/photo_form.py
@@ -1,45 +1,44 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-from wtforms import SubmitField
 from invenio.webdeposit_form import WebDepositForm as Form
 from invenio.webinterface_handler_flask_utils import _
 # Import custom fields
 from invenio.webdeposit_load_fields import fields
 from invenio.webdeposit_field_widgets import date_widget, plupload_widget, \
                                              bootstrap_submit
 
 __all__ = ['PhotoForm']
 
 
 class PhotoForm(Form):
 
     title = fields.TitleField(label=_('Photo Title'))
     author = fields.AuthorField(label=_('Photo Author'))
     date = fields.Date(label=_('Photo Date'),
                        widget=date_widget)
     keywords = fields.KeywordsField(label=_('Keywords'))
-    notes = fields.NotesField(label=_('Comments or Notes'))
+    notes = fields.NotesField(label=_('Description'))
     plupload_file = fields.FileUploadField(label=_('Files'),
                                            widget=plupload_widget)
-    submit = SubmitField(label=_('Submit Photo'), widget=bootstrap_submit)
+    submit = fields.SubmitField(label=_('Submit Photo'), widget=bootstrap_submit)
 
     #configuration variables
     _title = _("Submit a Photo")
     _drafting = True  # enable and disable drafting
diff --git a/modules/webdeposit/lib/deposition_forms/poem_form.py b/modules/webdeposit/lib/deposition_forms/poem_form.py
index f5aa9b657..616807cae 100644
--- a/modules/webdeposit/lib/deposition_forms/poem_form.py
+++ b/modules/webdeposit/lib/deposition_forms/poem_form.py
@@ -1,61 +1,60 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
 
-from wtforms import SubmitField
 from wtforms.validators import Required
 from invenio.webinterface_handler_flask_utils import _
 from invenio.webdeposit_form import WebDepositForm as Form
 from invenio.webdeposit_field_widgets import bootstrap_submit
 
 # Import custom fields
 from invenio.webdeposit_load_fields import fields
 
 __all__ = ['PoemForm']
 
 
 class PoemForm(Form):
 
     title = fields.TitleField(label=_('Poem Title'), validators=[Required()])
     author = fields.AuthorField(label=_('Author'), validators=[Required()])
     languages = [("en", _("English")),
                 ("fre", _("French")),
                 ("ger", _("German")),
                 ("dut", _("Dutch")),
                 ("ita", _("Italian")),
                 ("spa", _("Spanish")),
                 ("por", _("Portuguese")),
                 ("gre", _("Greek")),
                 ("slo", _("Slovak")),
                 ("cze", _("Czech")),
                 ("hun", _("Hungarian")),
                 ("pol", _("Polish")),
                 ("nor", _("Norwegian")),
                 ("swe", _("Swedish")),
                 ("fin", _("Finnish")),
                 ("rus", _("Russian"))]
     language = fields.LanguageField(label=_('Language'), choices=languages,
                                     validators=[Required()])
     year = fields.Date(label=_('Year'), validators=[Required()])
     poem_text = fields.AbstractField(label='Poem Text', validators=[Required()])
-    submit = SubmitField(label=_('Submit Poem'),
+    submit = fields.SubmitField(label=_('Submit Poem'),
                          widget=bootstrap_submit)
 
     """ Form Configuration variables """
     _title = _('Submit a Poem')
     _drafting = True   # enable and disable drafting
diff --git a/modules/webdeposit/lib/deposition_forms/preprint_form.py b/modules/webdeposit/lib/deposition_forms/preprint_form.py
index 0eae86a03..0bbbfd318 100644
--- a/modules/webdeposit/lib/deposition_forms/preprint_form.py
+++ b/modules/webdeposit/lib/deposition_forms/preprint_form.py
@@ -1,61 +1,61 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
 
-from wtforms import TextField, SubmitField
 from wtforms.validators import Required
 from invenio.webdeposit_form import WebDepositForm as Form
 from invenio.webinterface_handler_flask_utils import _
-from invenio.webdeposit_field_widgets import date_widget, bootstrap_submit
+from invenio.webdeposit_field_widgets import plupload_widget, date_widget, \
+                                             bootstrap_submit
 
 # Import custom fields
 from invenio.webdeposit_load_fields import fields
 __all__ = ['PreprintForm']
 
 
 class PreprintForm(Form):
 
     author = fields.AuthorField(label=_('Author'), validators=[Required()])
     subject_category = fields.TitleField(label=_('Subject category'),
                                                 validators=[Required()])
     note = fields.NotesField(label=_('Note'))
-    institution = TextField(label=_('Institution'))
-    languages = [("en", _("English")), \
-                ("fre", _("French")), \
-                ("ger", _("German")), \
-                ("dut", _("Dutch")), \
-                ("ita", _("Italian")), \
-                ("spa", _("Spanish")), \
-                ("por", _("Portuguese")), \
-                ("gre", _("Greek")), \
-                ("slo", _("Slovak")), \
-                ("cze", _("Czech")), \
-                ("hun", _("Hungarian")), \
-                ("pol", _("Polish")), \
-                ("nor", _("Norwegian")), \
-                ("swe", _("Swedish")), \
-                ("fin", _("Finnish")), \
-                ("rus", _("Russian"))]
+    institution = fields.TextField(label=_('Institution'))
+    languages = [("en", _("English")),
+                 ("fre", _("French")),
+                 ("ger", _("German")),
+                 ("dut", _("Dutch")),
+                 ("ita", _("Italian")),
+                 ("spa", _("Spanish")),
+                 ("por", _("Portuguese")),
+                 ("gre", _("Greek")),
+                 ("slo", _("Slovak")),
+                 ("cze", _("Czech")),
+                 ("hun", _("Hungarian")),
+                 ("pol", _("Polish")),
+                 ("nor", _("Norwegian")),
+                 ("swe", _("Swedish")),
+                 ("fin", _("Finnish")),
+                 ("rus", _("Russian"))]
     language = fields.LanguageField(label=_("Language"), choices=languages)
     date = fields.Date(label=_('Date'), widget=date_widget)
-    file_field = fields.FileUploadField(label=_('File'))
-    submit = SubmitField(label=_('Submit Preprint'), widget=bootstrap_submit)
+    file_field = fields.FileUploadField(widget=plupload_widget)
+    submit = fields.SubmitField(label=_('Submit Preprint'), widget=bootstrap_submit)
 
     """ Form Configuration variables """
     _title = _("Submit a Preprint")
-    _drafting = True  #enable and disable drafting
+    _drafting = True  # enable and disable drafting
diff --git a/modules/webdeposit/lib/deposition_forms/thesis_form.py b/modules/webdeposit/lib/deposition_forms/thesis_form.py
index 55585daa3..5ba58ceed 100644
--- a/modules/webdeposit/lib/deposition_forms/thesis_form.py
+++ b/modules/webdeposit/lib/deposition_forms/thesis_form.py
@@ -1,71 +1,72 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
 
-from wtforms import SelectField, SubmitField
 from wtforms.validators import Required
 from invenio.webdeposit_form import WebDepositForm as Form
 from invenio.webinterface_handler_flask_utils import _
-from invenio.webdeposit_field_widgets import date_widget, plupload_widget, bootstrap_submit
+from invenio.webdeposit_cook_json_utils import add_author
+from invenio.webdeposit_field_widgets import date_widget, plupload_widget, \
+                                             bootstrap_submit
 
 # Import custom fields
 from invenio.webdeposit_load_fields import fields
 __all__ = ['ThesisForm']
 
 
 class ThesisForm(Form):
 
     title = fields.TitleField(label=_('Original Thesis Title'),
                               validators=[Required()])
-    subtitle = fields.TitleField(label=_('Original Thesis Subtitle'))
-    alternative_title = fields.TitleField(label=_('Alternative Title'))
-    author = fields.AuthorField(label=_('Author'))
+    subtitle = fields.TitleField(label=_('Original Thesis Subtitle'),
+                                 recjson_key='title.subtitle')
+    author = fields.AuthorField(label=_('Author'),
+                                cook_function=add_author)
     supervisor = fields.AuthorField(label=_('Thesis Supervisor'))
     abstract = fields.AbstractField(label=_('Abstract'))
-    subject = fields.TitleField(label=_('Subject'))
 
-    languages = [("en", _("English")), \
-                ("fre", _("French")), \
-                ("ger", _("German")), \
-                ("dut", _("Dutch")), \
-                ("ita", _("Italian")), \
-                ("spa", _("Spanish")), \
-                ("por", _("Portuguese")), \
-                ("gre", _("Greek")), \
-                ("slo", _("Slovak")), \
-                ("cze", _("Czech")), \
-                ("hun", _("Hungarian")), \
-                ("pol", _("Polish")), \
-                ("nor", _("Norwegian")), \
-                ("swe", _("Swedish")), \
-                ("fin", _("Finnish")), \
-                ("rus", _("Russian"))]
+    languages = [("en", _("English")),
+                 ("fre", _("French")),
+                 ("ger", _("German")),
+                 ("dut", _("Dutch")),
+                 ("ita", _("Italian")),
+                 ("spa", _("Spanish")),
+                 ("por", _("Portuguese")),
+                 ("gre", _("Greek")),
+                 ("slo", _("Slovak")),
+                 ("cze", _("Czech")),
+                 ("hun", _("Hungarian")),
+                 ("pol", _("Polish")),
+                 ("nor", _("Norwegian")),
+                 ("swe", _("Swedish")),
+                 ("fin", _("Finnish")),
+                 ("rus", _("Russian"))]
     language = fields.LanguageField(label=_("Language"), choices=languages)
     publisher = fields.PublisherField(label=_('Thesis Publisher'))
     defence_date = fields.Date(label=_('Date of Defence'), widget=date_widget)
 
     funded_choices = [("yes", _("Yes")), ("no", _("No"))]
-    funded = SelectField(label=_("Has your thesis been funded by the CERN Doctoral Student Program?"),
-                                  choices=funded_choices)
+    funded = fields.SelectField(label=_("Has your thesis been funded by the CERN Doctoral Student Program?"),
+                                choices=funded_choices)
 
-    file_field = fields.FileUploadField(label=_('File'), widget=plupload_widget)
-    submit = SubmitField(label=_('Submit Thesis'), widget=bootstrap_submit)
+    file_field = fields.FileUploadField(widget=plupload_widget)
+    submit = fields.SubmitField(label=_('Submit Thesis'), widget=bootstrap_submit)
 
     """ Form Configuration variables """
     _title = _("Submit a Thesis")
     _drafting = True  # enable and disable drafting
diff --git a/modules/webdeposit/lib/webdeposit_api_blueprint.py b/modules/webdeposit/lib/webdeposit_api_blueprint.py
new file mode 100644
index 000000000..347aedf75
--- /dev/null
+++ b/modules/webdeposit/lib/webdeposit_api_blueprint.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+##
+## This file is part of Invenio.
+## Copyright (C) 2012, 2013 CERN.
+##
+## Invenio is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Invenio is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Invenio; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+import json
+from flask import  \
+    request, \
+    jsonify
+
+from invenio.bibworkflow_config import CFG_WORKFLOW_STATUS
+from invenio.webdeposit_load_deposition_types import deposition_metadata
+from invenio.webinterface_handler_flask_utils import InvenioBlueprint
+from invenio.webdeposit_utils import create_workflow,\
+    get_workflow, \
+    set_form_status, \
+    preingest_form_data, \
+    get_preingested_form_data, \
+    validate_preingested_data, \
+    deposit_files
+from invenio.webuser_flask import current_user
+from invenio.web_api_key import api_key_required
+from invenio.jsonutils import wash_for_json
+
+blueprint = InvenioBlueprint('webdeposit_api', __name__,
+                             url_prefix='/api/deposit',
+                             config='invenio.websubmit_config')
+
+
+class enum(object):
+    def __init__(self, **enums):
+        for enum, code in enums.items():
+            self.__setattr__(enum, code)
+
+ERROR = enum(INVALID_DEPOSITION=1)
+
+
+@blueprint.route('/create/<deposition_type>/', methods=['POST', 'GET'])
+@api_key_required
+def deposition_create(deposition_type):
+
+    user_id = current_user.get_id()
+
+    if deposition_type not in deposition_metadata:
+        return False, jsonify({'error': ERROR.INVALID_DEPOSITION,
+                               'message': 'Invalid deposition.'})
+
+    workflow = create_workflow(deposition_type, user_id)
+    return jsonify({'uuid': str(workflow.get_uuid())})
+
+
+@blueprint.route('/set/<deposition_type>/', methods=['GET', 'POST'])
+@api_key_required
+def json_set(deposition_type):
+    if deposition_type not in deposition_metadata:
+        return False, jsonify({'error': ERROR.INVALID_DEPOSITION,
+                               'message': 'Invalid deposition.'})
+
+    user_id = current_user.get_id()
+    uuid = request.values['uuid']
+    if 'form_data' in request.values:
+        form_data = request.form['form_data']
+        form_data = wash_for_json(form_data)
+        form_data = json.loads(form_data)
+        preingest_form_data(user_id, form_data, uuid)
+
+    if request.files:
+        deposit_files(user_id, deposition_type, uuid, preingest=True)
+
+    return 'OK'
+
+
+@blueprint.route('/get/<deposition_type>/', methods=['GET'])
+@api_key_required
+def json_get(deposition_type):
+    if request.method == 'GET':
+        uuid = request.args['uuid']
+        user_id = current_user.get_id()
+        form_data = get_preingested_form_data(user_id, uuid)
+        # edit the form_data.pop('files') and return it with the actual url of
+        # the file
+        return jsonify(form_data)
+    else:
+        return ''
+
+
+@blueprint.route('/submit/<deposition_type>/', methods=['GET'])
+@api_key_required
+def deposition_submit(deposition_type):
+    uuid = request.values['uuid']
+
+    user_id = current_user.get_id()
+    workflow = get_workflow(uuid, deposition_type)
+    errors = validate_preingested_data(user_id, uuid, deposition_type=None)
+    if errors:
+        return jsonify(errors)
+
+    workflow_status = CFG_WORKFLOW_STATUS.RUNNING
+    while workflow_status != CFG_WORKFLOW_STATUS.FINISHED:
+        # Continue workflow
+        workflow.run()
+        set_form_status(1, uuid, CFG_WORKFLOW_STATUS.FINISHED)
+        workflow_status = workflow.get_status()
+
+    return jsonify({})
diff --git a/modules/webdeposit/lib/webdeposit_api_regression_tests.py b/modules/webdeposit/lib/webdeposit_api_regression_tests.py
new file mode 100644
index 000000000..85a60220c
--- /dev/null
+++ b/modules/webdeposit/lib/webdeposit_api_regression_tests.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+##
+## This file is part of Invenio.
+## Copyright (C) 2012, 2013 CERN.
+##
+## Invenio is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Invenio is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Invenio; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+from invenio.testutils import make_test_suite, run_test_suite, InvenioTestCase
+
+
+class TestWebDepositAPI(InvenioTestCase):
+    def clear_tables(self):
+        from invenio.bibworkflow_model import Workflow, WfeObject
+        from invenio.sqlalchemyutils import db
+
+        Workflow.query.delete()
+        WfeObject.query.delete()
+        db.session.commit()
+
+    def setUp(self):
+        from random import randint
+        from invenio.web_api_key import create_new_web_api_key, \
+            get_available_web_api_keys
+        from invenio.webdeposit_load_deposition_types import \
+            deposition_metadata
+        # self.clear_tables()
+
+        create_new_web_api_key(1, key_description='webdeposit_api_testing')
+        keys = get_available_web_api_keys(1)
+        self.apikey = keys[0].id
+
+        # Test random deposition
+        self.deposition = deposition_metadata.keys()[randint(0, len(deposition_metadata.keys()) - 1)]
+        super(TestWebDepositAPI, self).setUp()
+
+    def tearDown(self):
+        # self.clear_tables()
+        super(TestWebDepositAPI, self).tearDown()
+
+    def test_create(self):
+        from flask import current_app, url_for
+        from invenio.web_api_key import build_web_request
+
+        url = url_for('webdeposit_api.deposition_create',
+                      deposition_type=self.deposition)
+
+        url_create = build_web_request(url, api_key=self.apikey,
+                                       timestamp=False)
+        with current_app.test_client() as c:
+            response = c.get(url_create)
+
+            self.assert200(response)
+
+            assert "uuid" in response.json
+
+    def test_json_get_set_functions(self):
+        import json
+        from flask import current_app, url_for
+        from invenio.webdeposit_load_deposition_types import \
+            deposition_metadata
+        from invenio.webdeposit_utils import create_workflow
+        from wtforms import TextAreaField
+        from invenio.webdeposit_load_forms import forms
+        from invenio.web_api_key import build_web_request
+
+        self.uuid = create_workflow(self.deposition, user_id=1).get_uuid()
+
+        # Get form from deposition
+        for fun in deposition_metadata[self.deposition]['workflow']:
+            if fun.func_name == 'render':
+                form_type = fun.__form_type__
+
+        form = forms[form_type]()
+
+        # Insert form data
+        form_data = {}
+        for field in form:
+            if isinstance(field, TextAreaField):
+                form_data[field.name] = 'testing webdeposit API'
+
+        data = {'form_data': json.dumps(form_data),
+                'uuid': self.uuid}
+        url = url_for('webdeposit_api.json_set',
+                      deposition_type=self.deposition)
+        url_set = build_web_request(url, {},
+                                    uid=1, api_key=self.apikey,
+                                    timestamp=False)
+        with current_app.test_client() as c:
+            response = c.post(url_set, data=data)
+            assert response._status_code == 200
+
+            url = url_for('webdeposit_api.json_get', deposition_type=self.deposition)
+            url_get = build_web_request(url, {'uuid':
+                                        self.uuid},
+                                        uid=1, api_key=self.apikey,
+                                        timestamp=False)
+            response = c.get(url_get)
+            assert response._status_code == 200
+
+            for field in form:
+                if isinstance(field, TextAreaField):
+                    assert response.json[field.name] == 'testing webdeposit API'
+
+TEST_SUITE = make_test_suite(TestWebDepositAPI)
+
+if __name__ == "__main__":
+    run_test_suite(TEST_SUITE)
diff --git a/modules/webdeposit/lib/webdeposit_autocomplete_utils.py b/modules/webdeposit/lib/webdeposit_autocomplete_utils.py
index fd0e08ea6..de7d09923 100644
--- a/modules/webdeposit/lib/webdeposit_autocomplete_utils.py
+++ b/modules/webdeposit/lib/webdeposit_autocomplete_utils.py
@@ -1,43 +1,54 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from invenio.sherpa_romeo import SherpaRomeoSearch
 from invenio.orcid import OrcidSearch
 
 
-def sherpa_romeo_publishers(value):
-    sherpa_romeo = SherpaRomeoSearch()
-    publishers = sherpa_romeo.search_publisher(value)
-    if publishers is None:
-        return []
-    return publishers
+def sherpa_romeo_publishers(dummy_form, term, limit=50):
+    if term:
+        sherpa_romeo = SherpaRomeoSearch()
+        publishers = sherpa_romeo.search_publisher(term)
+        if publishers is None:
+            return []
+        return publishers
+    return []
 
 
-def sherpa_romeo_journals(value):
-    s = SherpaRomeoSearch()
-    journals = s.search_journal(value)
-    if journals is None:
-        return []
-    return journals
+def sherpa_romeo_journals(dummy_form, term, limit=50):
+    """
+    Search SHERPA/RoMEO for journal name
+    """
+    if term:
+        # SherpaRomeoSearch doesnt' like unicode
+        if isinstance(term, unicode):
+            term = term.encode('utf8')
+        s = SherpaRomeoSearch()
+        journals = s.search_journal(term)
+        if journals is not None:
+            return journals[:limit]
+    return []
 
 
-def orcid_authors(value):
-    orcid = OrcidSearch()
-    orcid.search_authors(value)
-    return orcid.get_authors_names()
+def orcid_authors(dummy_form, term, limit=50):
+    if term:
+        orcid = OrcidSearch()
+        orcid.search_authors(term)
+        return orcid.get_authors_names()
+    return []
diff --git a/modules/webdeposit/lib/webdeposit_blueprint.py b/modules/webdeposit/lib/webdeposit_blueprint.py
index 458bcf7f7..57e7e1597 100644
--- a/modules/webdeposit/lib/webdeposit_blueprint.py
+++ b/modules/webdeposit/lib/webdeposit_blueprint.py
@@ -1,409 +1,380 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebDeposit Flask Blueprint"""
 
 import os
-import shutil
 
-from glob import iglob
 from flask import current_app, \
     render_template, \
     request, \
     jsonify, \
     redirect, \
     url_for, \
     flash, \
-    send_file
+    send_file, \
+    abort
 from werkzeug.utils import secure_filename
 from uuid import uuid1 as new_uuid
 
 from invenio.cache import cache
 from invenio.webdeposit_load_deposition_types import deposition_types, \
     deposition_metadata
 from invenio.webinterface_handler_flask_utils import _, InvenioBlueprint
-from invenio.webdeposit_utils import get_current_form, \
-    get_form, \
-    draft_field_set, \
+from invenio.webdeposit_utils import get_form, \
     draft_field_list_add, \
     delete_workflow, \
     create_workflow, \
     get_latest_or_new_workflow, \
     get_workflow, \
     draft_field_get_all, \
-    draft_field_error_check, \
+    draft_form_process_and_validate, \
+    draft_form_autocomplete, \
     draft_field_get, \
     set_form_status, \
     get_form_status, \
     create_user_file_system, \
     CFG_DRAFT_STATUS, \
     url_upload,\
-    get_all_drafts
+    get_all_drafts, \
+    deposit_files, \
+    delete_file, \
+    save_form
 from invenio.webuser_flask import current_user
 from invenio.bibworkflow_config import CFG_WORKFLOW_STATUS
 
 blueprint = InvenioBlueprint('webdeposit', __name__,
                              url_prefix='/deposit',
                              config='invenio.websubmit_config',
                              menubuilder=[('main.webdeposit',
                                           _('Deposit'),
                                           'webdeposit.index_deposition_types',
                                           2)],
                              breadcrumbs=[(_('Deposit'),
-                                           'webdeposit.index_deposition_types')])
+                                          'webdeposit.index_deposition_types')])
 
 
 @blueprint.route('/upload_from_url/<deposition_type>/<uuid>', methods=['POST'])
 @blueprint.invenio_authenticated
 def upload_from_url(deposition_type, uuid):
     if request.method == 'POST':
         url = request.form['url']
 
         if "name" in request.form:
             name = request.form['name']
         else:
             name = None
 
         if "size" in request.form:
             size = request.form['size']
         else:
             size = None
 
         unique_filename = url_upload(current_user.get_id(),
                                      deposition_type,
                                      uuid, url, name, size)
         return unique_filename
 
 
 @blueprint.route('/upload/<deposition_type>/<uuid>', methods=['POST'])
 @blueprint.invenio_authenticated
 def plupload(deposition_type, uuid):
     """ The file is splitted in chunks on the client-side
         and it is merged again on the server-side
 
         @return: the path of the uploaded file
     """
-    if request.method == 'POST':
-        try:
-            chunks = request.form['chunks']
-            chunk = request.form['chunk']
-        except KeyError:
-            chunks = None
-            pass
-        name = request.form['name']
-        current_chunk = request.files['file']
-
-        try:
-            filename = secure_filename(name) + "_" + chunk
-        except UnboundLocalError:
-            filename = secure_filename(name)
-
-        CFG_USER_WEBDEPOSIT_FOLDER = create_user_file_system(current_user.get_id(),
-                                                             deposition_type,
-                                                             uuid)
-
-        # Save the chunk
-        current_chunk.save(os.path.join(CFG_USER_WEBDEPOSIT_FOLDER, filename))
-
-        unique_filename = ""
-
-        if chunks is None:  # file is a single chunk
-            unique_filename = str(new_uuid()) + filename
-            old_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER, filename)
-            file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
-                                     unique_filename)
-            os.rename(old_path, file_path)  # Rename the chunk
-            size = os.path.getsize(file_path)
-            file_metadata = dict(name=name, file=file_path, size=size)
-            draft_field_list_add(current_user.get_id(), uuid,
-                                 "files", file_metadata)
-        elif int(chunk) == int(chunks) - 1:
-            '''All chunks have been uploaded!
-                start merging the chunks'''
-            filename = secure_filename(name)
-            chunk_files = []
-            for chunk_file in iglob(os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
-                                                 filename + '_*')):
-                chunk_files.append(chunk_file)
-
-            # Sort files in numerical order
-            chunk_files.sort(key=lambda x: int(x.split("_")[-1]))
-
-            unique_filename = str(new_uuid()) + filename
-            file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
-                                     unique_filename)
-            destination = open(file_path, 'wb')
-            for chunk in chunk_files:
-                shutil.copyfileobj(open(chunk, 'rb'), destination)
-                os.remove(chunk)
-            destination.close()
-            size = os.path.getsize(file_path)
-            file_metadata = dict(name=name, file=file_path, size=size)
-            draft_field_list_add(current_user.get_id(), uuid,
-                                 "files", file_metadata)
-    return unique_filename
+    return deposit_files(current_user.get_id(), deposition_type, uuid)
 
 
 @blueprint.route('/plupload_delete/<uuid>', methods=['GET', 'POST'])
 @blueprint.invenio_authenticated
 def plupload_delete(uuid):
-    if request.method == 'POST':
-        files = draft_field_get(current_user.get_id(), uuid, "files")
-        result = "File Not Found"
-        filename = request.form['filename']
-        files = draft_field_get(current_user.get_id(), uuid, "files")
-        for i, f in enumerate(files):
-            if filename == f['file'].split('/')[-1]:  # get the unique name from the path
-                os.remove(f['file'])
-                del files[i]
-                result = str(files) + "              "
-                draft_field_set(current_user.get_id(), uuid, "files", files)
-                result = "File " + f['name'] + " Deleted"
-                break
-    return result
+    return delete_file(current_user.get_id(), uuid)
 
 
 @blueprint.route('/plupload_get_file/<uuid>', methods=['GET'])
 @blueprint.invenio_authenticated
 def plupload_get_file(uuid):
     filename = request.args.get('filename')
     tmp = ""
     files = draft_field_get(current_user.get_id(), uuid, "files")
     for f in files:
         tmp += f['file'].split('/')[-1] + '<br><br>'
         if filename == f['file'].split('/')[-1]:
             return send_file(f['file'],
                              attachment_filename=f['name'],
                              as_attachment=True)
 
     return "filename: " + filename + '<br>' + tmp
 
 
 @blueprint.route('/check_status/<uuid>/', methods=['GET', 'POST'])
 @blueprint.invenio_authenticated
 def check_status(uuid):
     form_status = get_form_status(current_user.get_id(), uuid)
     return jsonify({"status": form_status})
 
 
-@blueprint.route('_autocomplete/<uuid>', methods=['GET', 'POST'])
+@blueprint.route('/autocomplete/<form_type>/<field>', methods=['GET', 'POST'])
 @blueprint.invenio_authenticated
-def autocomplete(uuid):
+def autocomplete(form_type, field):
     """ Returns a list with of suggestions for the field
         based on the current value
     """
-    query = request.args.get('term')  # value
-    field_type = request.args.get('type')  # field
+    term = request.args.get('term')  # value
     limit = request.args.get('limit', 50, type=int)
 
-    form = get_current_form(current_user.get_id(), uuid=uuid)[1]
-    form.__dict__["_fields"][field_type].process_data(query)
+    result = draft_form_autocomplete(
+        form_type, field, term, limit
+    )
 
-    #Check if field has an autocomplete function
-    if hasattr(form.__dict__["_fields"][field_type], "autocomplete"):
-        return jsonify(results=form.__dict__["_fields"][field_type].
-                       autocomplete()[:limit])
-    else:
-        return jsonify(results=[])
+    return jsonify(results=result)
 
 
-@blueprint.route('_errorCheck/<uuid>')
+@blueprint.route('/save/<uuid>', methods=['POST'])
 @blueprint.invenio_authenticated
 def error_check(uuid):
-    """ Used for field error checking
     """
-    value = request.args.get('attribute')
-    field_name = request.args.get('name')
+    Save and run error check on field values
 
-    if field_name == "":
-        return "{}"
+    The request body must contain a JSON-serialized field/value-dictionary.
+    A single or multiple fields may be passed in the dictionary, and values
+    may be any JSON-serializable object. Example::
 
-    draft_field_set(current_user.get_id(), uuid, field_name, value)
+        {
+            'title': 'Invenio Software',
+            'authors': [['Smith, Joe', 'CERN'],['Smith, Jane','CERN']]
+        }
+
+    The response is a JSON-serialized dictionary with the keys:
+
+    * messages: Field/messages-dictionary
+    * values: Field/value-dictionary of unsubmitted fields that changed value.
+    * <flag>_on: List of fields, which flag changed to on.
+    * <flag>_off: List of fields, which flag changed to off.
+
+
+    The field/messages-dictionary looks like this::
+
+        {'title': {'state': '<state>', 'messages': [,...]}}
+
+    where <state> is either 'success' if field was validated successfully,
+    'info' if an information message should be displayed, and respectively the
+    same for 'warning' and 'error'.
+
+        Example response::
+
+        {
+            'messages': {'title': {'state': '<state>', 'messages': [,...]}},
+            'values': {'<field>': <value>, ...},
+            'hidden_on': ['<field>', ...],
+            'hidden_off': ['<field>', ...],
+            'disabled_on': ['<field>', ...],
+            'disabled_off': ['<field>', ...],
+        }
+
+    @return: A JSON-serialized field/result-dictionary (see above)
+    """
+    if request.method != 'POST':
+        abort(400)
+
+    # Process data, run validation, set in workflow object and return result
+    result = draft_form_process_and_validate(current_user.get_id(), uuid, request.json)
 
-    check_result = draft_field_error_check(current_user.get_id(),
-                                           uuid, field_name, value)
     try:
-        return jsonify(check_result)
+        return jsonify(result)
     except TypeError:
-        return jsonify({"error_message": "", "error": 0})
+        return jsonify(None)
 
 
 @blueprint.route('/<deposition_type>/delete/<uuid>')
 @blueprint.invenio_authenticated
 def delete(deposition_type, uuid):
     """ Deletes the whole deposition with uuid=uuid
         (including form drafts)
         redirects to load another workflow
     """
     if deposition_type not in deposition_metadata:
         flash(_('Invalid deposition type `%s`.' % deposition_type), 'error')
         return redirect(url_for('.index_deposition_types'))
     delete_workflow(current_user.get_id(), uuid)
     flash(deposition_type + _(' deposition deleted!'), 'error')
     return redirect(url_for("webdeposit.index",
                             deposition_type=deposition_type))
 
 
 @blueprint.route('/<deposition_type>/new/')
 @blueprint.invenio_authenticated
 def create_new(deposition_type):
     """ Creates new deposition
     """
     if deposition_type not in deposition_metadata:
         flash(_('Invalid deposition type `%s`.' % deposition_type), 'error')
         return redirect(url_for('.index_deposition_types'))
     workflow = create_workflow(deposition_type, current_user.get_id())
     uuid = workflow.get_uuid()
     flash(deposition_type + _(' deposition created!'), 'info')
     return redirect(url_for("webdeposit.add",
                             deposition_type=deposition_type,
                             uuid=uuid))
 
 
 @blueprint.route('/')
 def index_deposition_types():
     """ Renders the deposition types (workflows) list """
     current_app.config['breadcrumbs_map'][request.endpoint] = [
         (_('Home'), '')] + blueprint.breadcrumbs
     drafts = get_all_drafts(current_user.get_id())
 
     return render_template('webdeposit_index_deposition_types.html',
                            deposition_types=deposition_types,
                            drafts=drafts)
 
 
 @blueprint.route('/<deposition_type>/')
 @blueprint.invenio_authenticated
 def index(deposition_type):
     if deposition_type not in deposition_metadata:
         flash(_('Invalid deposition type `%s`.' % deposition_type), 'error')
         return redirect(url_for('.index_deposition_types'))
     current_app.config['breadcrumbs_map'][request.endpoint] = [
         (_('Home'), '')] + blueprint.breadcrumbs + [(deposition_type, None)]
     user_id = current_user.get_id()
     drafts = draft_field_get_all(user_id, deposition_type)
 
+    from invenio.bibworkflow_model import Workflow
+    past_depositions = \
+        Workflow.get(Workflow.name == deposition_type,
+                     Workflow.user_id == user_id,
+                     Workflow.status == CFG_WORKFLOW_STATUS.FINISHED).\
+        all()
+
     return render_template('webdeposit_index.html', drafts=drafts,
                            deposition_type=deposition_type,
-                           deposition_types=deposition_types)
+                           deposition_types=deposition_types,
+                           past_depositions=past_depositions)
 
 
 @blueprint.route('/<deposition_type>/<uuid>', methods=['GET', 'POST'])
 @blueprint.invenio_authenticated
 def add(deposition_type, uuid):
     """
         Runs the workflows and shows the current form/output of the workflow
         Loads the associated to the uuid workflow.
 
         if the current step of the workflow renders a form, it loads it.
         if the workflow is finished or in case of error,
         it redirects to the deposition types page
         flashing also the associated message.
 
         Moreover, it handles a form's POST request for the fields and files,
         and validates the whole form after the submission.
 
         @param deposition_type: the type of the deposition to be run.
         @param uuid: the universal unique identifier for the workflow.
     """
 
     status = 0
 
     if deposition_type not in deposition_metadata:
         flash(_('Invalid deposition type `%s`.' % deposition_type), 'error')
         return redirect(url_for('.index_deposition_types'))
 
     elif uuid is None:
         # get the latest one. if there is no workflow created
         # lets create a new workflow with given deposition type
         workflow = get_latest_or_new_workflow(deposition_type)
         uuid = workflow.get_uuid()
         #flash(_('Deposition %s') % (uuid,), 'info')
         return redirect(url_for('.add', deposition_type=deposition_type,
                                 uuid=uuid))
     else:
         # get workflow with specific uuid
-        workflow = get_workflow(deposition_type, uuid)
+        workflow = get_workflow(uuid, deposition_type)
         if workflow is None:
             flash(_('Deposition with uuid `') + uuid + '` not found.', 'error')
             return redirect(url_for('.index_deposition_types'))
 
     cache.delete_many(str(current_user.get_id()) + ":current_deposition_type",
                       str(current_user.get_id()) + ":current_uuid")
-    cache.add(str(current_user.get_id()) + ":current_deposition_type", deposition_type)
+    cache.add(str(current_user.get_id()) + ":current_deposition_type",
+              deposition_type)
     cache.add(str(current_user.get_id()) + ":current_uuid", uuid)
 
     current_app.config['breadcrumbs_map'][request.endpoint] = [
         (_('Home'), '')] + blueprint.breadcrumbs + \
         [(deposition_type, 'webdeposit.index',
          {'deposition_type': deposition_type}),
          (uuid, 'webdeposit.add',
          {'deposition_type': deposition_type, 'uuid': uuid})]
 
     if request.method == 'POST':
         # Save the files
         for uploaded_file in request.files.values():
             filename = secure_filename(uploaded_file.filename)
             if filename == "":
                 continue
 
             CFG_USER_WEBDEPOSIT_FOLDER = create_user_file_system(current_user.get_id(),
                                                                  deposition_type,
                                                                  uuid)
             unique_filename = str(new_uuid()) + filename
             file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
                                      unique_filename)
             uploaded_file.save(file_path)
             size = os.path.getsize(file_path)
             file_metadata = dict(name=filename, file=file_path, size=size)
             draft_field_list_add(current_user.get_id(), uuid,
                                  "files", file_metadata)
 
         # Save form values
-        for (field_name, value) in request.form.items():
-            if "submit" in field_name.lower():
-                continue
-            draft_field_set(current_user.get_id(), uuid, field_name, value)
+        form = get_form(current_user.get_id(), uuid, formdata=request.form)
 
-        form = get_form(current_user.get_id(), uuid)
         # Validate form
         if not form.validate():
             # render the form with error messages
             # the `workflow.get_output` function returns also the template
-            return render_template(**workflow.get_output(form_validation=True))
-
+            form.post_process()
+            save_form(current_user.get_id(), uuid, form)
+            return render_template(**workflow.get_output(form=form,
+                                                         form_validation=True))
         #Set the latest form status to finished
         set_form_status(current_user.get_id(), uuid,
                         CFG_DRAFT_STATUS['finished'])
+        save_form(current_user.get_id(), uuid, form)
 
     workflow.run()
     status = workflow.get_status()
     if status != CFG_WORKFLOW_STATUS.FINISHED and \
             status != CFG_WORKFLOW_STATUS.ERROR:
         # render current step of the workflow
         # the `workflow.get_output` function returns also the template
         return render_template(**workflow.get_output())
     elif status == CFG_WORKFLOW_STATUS.FINISHED:
-        flash(deposition_type + _(' deposition has been successfully finished.'),
-              'success')
+        msg = deposition_type + _(' deposition has been successfully finished.')
+        recid = workflow.get_data('recid')
+        if recid is not None:
+            msg += ' Record available <a href=/record/%s>here</a>.' % recid
+        flash(msg, 'success')
         return redirect(url_for('.index_deposition_types'))
     elif status == CFG_WORKFLOW_STATUS.ERROR:
         flash(deposition_type + _(' deposition %s has returned error.'), 'error')
         current_app.logger.error('Deposition: %s has returned error. %d' % uuid)
         return redirect(url_for('.index_deposition_types'))
diff --git a/modules/webdeposit/lib/webdeposit_config.py b/modules/webdeposit/lib/webdeposit_config.py
deleted file mode 100644
index 7f30ad48f..000000000
--- a/modules/webdeposit/lib/webdeposit_config.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# -*- coding: utf-8 -*-
-##
-## This file is part of Invenio.
-## Copyright (C) 2013 CERN.
-##
-## Invenio is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2 of the
-## License, or (at your option) any later version.
-##
-## Invenio is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Invenio; if not, write to the Free Software Foundation, Inc.,
-## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-from invenio.webinterface_handler_flask_utils import _
-
-
-"""
-WebDeposit Configuration
-
-Define here validators and autocomplete functions for fields
-to override the default ones.
-
-The structure must be in dictionaries as follows:
-
-Deposition name: Form type: 'fields': name of the field
-
-deposition:
-    collection:
-        The collection that the deposition belongs.
-
-form:
-    title:
-        string, the title to be shown to the user above the form.
-    file_cook:
-        define here a function if you want different handling in json's transformation
-        for the files of the form.
-    template:
-        the template to be used for the form.
-        if not defined, the default one is being used.
-
-fields:
-    label:
-        string, the field's label
-    validators:
-        list with path strings to be imported with werkzeug's `import_string`.
-        The validators of the field.
-    autocomplete:
-        path string to be imported with werkzeug's `import_string`.
-        The function that autocompletes the field.
-    recjson_key:
-        the association with BibField. Define here a mapping with a BibField's field.
-    widget:
-        path string to be imported with werkzeug's `import_string`.
-        WTField widget.
-
-Deposition name: Form type: 'fields': name of the field
-
-deposition:
-    collection:
-        The collection that the deposition belongs.
-
-form:
-    title:
-        string, the title to be shown to the user above the form.
-    file_cook:
-        define here a function if you want different handling in json's transformation
-        for the files of the form.
-
-fields:
-    label:
-        string, the field's label
-    validators:
-        list with path strings to be imported with werkzeug's `import_string`.
-        The validators of the field.
-    autocomplete:
-        path string to be imported with werkzeug's `import_string`.
-        The function that autocompletes the field.
-    recjson_key:
-        the association with BibField. Define here a mapping with a BibField's field.
-    widget:
-        path string to be imported with werkzeug's `import_string`.
-        WTField widget.
-
-"""
-
-config = {
-    'Article': {
-        'ArticleForm': {
-            'fields': {
-                'DOIField': {
-                    'label': 'DOI',
-                    'validators': ['invenio.webdeposit_validation_utils:datacite_doi_validate'],
-                    'recjson_key': 'publication_info.DOI'
-                },
-                'PublisherField': {
-                    'label': 'Publisher',
-                    'autocomplete': 'invenio.webdeposit_autocomplete_utils:sherpa_romeo_publishers',
-                    'validators': ['invenio.webdeposit_validation_utils:sherpa_romeo_publisher_validate'],
-                    'recjson_key': 'imprint.publisher_name'
-                },
-                'JournalField': {
-                    'label': 'Journal Title',
-                    'autocomplete': 'invenio.webdeposit_autocomplete_utils:sherpa_romeo_journals',
-                    'validators': ['invenio.webdeposit_validation_utils:sherpa_romeo_journal_validate']
-                },
-                'ISSNField': {
-                    'label': 'ISSN',
-                    'validators': ['invenio.webdeposit_validation_utils:sherpa_romeo_issn_validate'],
-                    'recjson_key': 'issn'
-                },
-                'TitleField': {
-                    'label': 'Document Title',
-                    'recjson_key': 'title.title'
-                },
-                'AuthorField': {
-                    'label': 'Author',
-                    'autocomplete': 'invenio.webdeposit_autocomplete_utils:orcid_authors',
-                    'recjson_key': 'authors[0].full_name'
-                },
-                'AbstractField': {
-                    'label': 'Abstract',
-                    'recjson_key': 'abstract.summary'
-                },
-                'PagesNumberField': {
-                    'label': 'Number of Pages',
-                    'validators': ['invenio.webdeposit_validation_utils:number_validate']
-                },
-                'LanguageField': {
-                    'label': 'Language',
-                    'recjson_key': 'invenio.webdeposit_cook_json_utils:cook_language'
-                },
-                'Date': {
-                    'label': 'Date of Document',
-                    'widget': 'invenio.webdeposit_field_widgets:date_widget',
-                    'recjson_key': 'imprint.date'
-                },
-                'NotesField': {
-                    'label': 'Notes or Comments',
-                    'recjson_key': 'comment'
-                },
-                'KeywordsField': {
-                    'label': 'Keywords'
-                },
-                'FileUploadField': {
-                    # The files of a form are handled by the FFT field
-                    'label': 'File',
-                    'validators': ['invenio.webdeposit_validation_utils:number_validate'],
-                    'widget': 'invenio.webdeposit_field_widgets:plupload_widget'
-                },
-                'SubmitField': {
-                    # The submit field accepts only label and widget configuration
-                    'label': 'Submit Article',
-                    'widget': 'invenio.webdeposit_field_widgets:bootstrap_submit'
-                }
-            },
-            'title': _('Submit an Article')
-        },
-        'collection': 'Article'
-    },
-    'Photo': {
-        'PhotoForm': {
-            'fields': {
-                'NotesField': {
-                    'recjson_key': 'comment'
-                }
-            },
-            'file_cook': 'invenio.webdeposit_cook_json_utils:cook_picture'
-        },
-        'collection': 'Picture'
-    }
-}
diff --git a/modules/webdeposit/lib/webdeposit_config_utils.py b/modules/webdeposit/lib/webdeposit_config_utils.py
deleted file mode 100644
index 521b6b8bd..000000000
--- a/modules/webdeposit/lib/webdeposit_config_utils.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# -*- coding: utf-8 -*-
-##
-## This file is part of Invenio.
-## Copyright (C) 2013 CERN.
-##
-## Invenio is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2 of the
-## License, or (at your option) any later version.
-##
-## Invenio is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Invenio; if not, write to the Free Software Foundation, Inc.,
-## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-from werkzeug.utils import import_string
-from invenio.cache import cache
-from invenio.sqlalchemyutils import db
-from invenio.webuser_flask import current_user
-from invenio.webdeposit_model import WebDepositDraft
-from invenio.webdeposit_cook_json_utils import cook_to_recjson
-from invenio.bibworkflow_model import Workflow
-from invenio.webinterface_handler_flask_utils import _
-from invenio.webdeposit_cook_json_utils import cook_to_recjson
-
-
-class WebDepositConfiguration(object):
-    """ Webdeposit configuration class
-        Returns configuration for fields based on runtime variables
-        or, if not defined, based on the parameters
-
-        @param deposition_type: initialize the class for a deposition type
-
-        @param form_name: initialize the class for a form
-            used when a form is defined to load validators and widgets
-
-        @param field_type: initialize the class for a field
-            used in the field pre_validate and autocomplete methods
-            to load and call them on runtime
-    """
-
-    def __init__(self, deposition_type=None, form_type=None, field_type=None):
-        self.config = import_string('invenio.webdeposit_config:config')
-        self.deposition_type = deposition_type
-        self.form_type = form_type
-        self.field_type = field_type
-        self._runtime_vars_init()
-
-    def _runtime_vars_init(self):
-        """ Initializes user_id, deposition type, uuid and form_type
-        """
-
-        self.user_id = current_user.get_id()
-
-        if self.deposition_type is None:
-
-            self.runtime_deposition_type = cache.get(str(self.user_id) +
-                                                     ":current_deposition_type")
-        else:
-            self.runtime_deposition_type = None
-
-            #  The uuid is always defined on runtime
-        self.uuid = cache.get(str(self.user_id) + ":current_uuid")
-
-        if self.uuid is not None and self.form_type is None:
-            webdeposit_draft_query = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == self.user_id,
-                       WebDepositDraft.uuid == self.uuid)
-            # get the draft with the max step
-            webdeposit_draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
-
-            self.runtime_form_type = webdeposit_draft.form_type
-        else:
-            self.runtime_form_type = None
-
-    #FIXME: Make the deposition_type, form_type and field_type an attribute
-    def get_deposition_type(self):
-        return self.runtime_deposition_type or self.deposition_type
-
-    def get_form_type(self):
-        return self.runtime_form_type or self.form_type
-
-    def get_field_type(self):
-        return self.field_type
-
-    def _parse_config(self, config_key, deposition_type=None, form_type=None,
-                      field_type=None):
-        if deposition_type in self.config:
-            deposition_config = self.config[deposition_type]
-            if form_type is None and config_key in deposition_config:
-                return deposition_config[config_key]
-
-            if form_type in deposition_config:
-                form_config = deposition_config[form_type]
-                if field_type is None and config_key in form_config:
-                    return form_config[config_key]
-
-                if field_type in form_config['fields']:
-                    field_config = form_config['fields'][field_type]
-                    if config_key in field_config:
-                        if config_key in field_config:
-                            return field_config[config_key]
-
-        return None
-
-
-    def get_form_title(self, form_type=None):
-        """ Returns the title of the form
-
-            @param form_type: the type of the form.
-                to use this function it must be defined here
-                or at the class construction
-        """
-
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-
-        title = self._parse_config('title',
-                                   deposition_type=deposition_type,
-                                   form_type=form_type)
-        if title is not None:
-            return _(title)
-        else:
-            return None
-
-    def get_label(self, field_type=None):
-        """ Returns the label of the field
-
-            @param field_type: the type of the field.
-                to use this function it must be defined here
-                or at the class construction
-        """
-
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-        field_type = field_type or self.get_field_type()
-
-        label = self._parse_config('label',
-                                  deposition_type=deposition_type,
-                                  form_type=form_type,
-                                  field_type=field_type)
-
-        if label is None:
-            return None
-        else:
-            return _(label)
-
-    def get_widget(self, field_type=None):
-        """ Returns the widget of the field
-
-            @param field_type: the type of the field.
-                to use this function it must be defined here
-                or at the class construction
-        """
-
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-        field_type = field_type or self.get_field_type()
-
-        widget = self._parse_config('widget',
-                                   deposition_type=deposition_type,
-                                   form_type=form_type,
-                                   field_type=field_type)
-
-        if widget is None:
-            return None
-        else:
-            return import_string(widget)
-
-    def get_autocomplete_function(self):
-        """ Returns an autocomplete function of the field
-        """
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-        field_type = self.get_field_type()
-
-        autocomplete = self._parse_config('autocomplete',
-                                          deposition_type=deposition_type,
-                                          form_type=form_type,
-                                          field_type=field_type)
-
-        if autocomplete is None:
-            return None
-        else:
-            return import_string(autocomplete)
-
-    def get_validators(self, field_type=None):
-        """ Returns validators function based of the field
-        """
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-        field_type = field_type or self.get_field_type()
-
-        vals = self._parse_config('validators',
-                                  deposition_type=deposition_type,
-                                  form_type=form_type,
-                                  field_type=field_type)
-
-        validators = []
-        if vals is None:
-            return []
-        else:
-            for validator in vals:
-                validators.append(import_string(validator))
-
-            return validators
-
-    def get_recjson_key(self, field_type=None):
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type()
-        field_type = field_type or self.get_field_type()
-
-        return self._parse_config('recjson_key',
-                                  deposition_type=deposition_type,
-                                  form_type=form_type,
-                                  field_type=field_type)
-
-    def get_cook_json_function(self, field_type=None):
-        recjson_key = self.get_recjson_key(field_type)
-        if recjson_key is not None:
-            return cook_to_recjson(recjson_key)
-
-
-    def get_template(self, form_type=None):
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type() or form_type
-
-        template = self._parse_config('template',
-                                       deposition_type=deposition_type,
-                                       form_type=form_type)
-
-        if template is None:
-            return None
-        else:
-            return template
-
-    def get_files_cook_function(self, form_type=None):
-        deposition_type = self.get_deposition_type()
-        form_type = self.get_form_type() or form_type
-
-        file_cook = self._parse_config('file_cook',
-                                       deposition_type=deposition_type,
-                                       form_type=form_type)
-
-        if file_cook is None:
-            return None
-        else:
-            return import_string(file_cook)
-
-    def get_collection(self, deposition_type=None):
-        deposition_type = deposition_type or self.get_deposition_type()
-
-        return self._parse_config('collection',
-                                  deposition_type=deposition_type)
diff --git a/modules/webdeposit/lib/webdeposit_cook_json_utils.py b/modules/webdeposit/lib/webdeposit_cook_json_utils.py
index 1c34d3a5b..89f4f94db 100644
--- a/modules/webdeposit/lib/webdeposit_cook_json_utils.py
+++ b/modules/webdeposit/lib/webdeposit_cook_json_utils.py
@@ -1,101 +1,107 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 
 """
 Cook Json Functions
 
 Functions to be used for transforming (back and forth) a webdeposit json
 (json representing a form) to rec json format using BibField's JsonReader
 """
 
 
 def cook_to_recjson(key):
     def cook(json_reader, value):
         json_reader[key] = value
         return json_reader
     return cook
 
 
+def add_author(json_reader, value):
+    if 'authors' in json_reader:
+        json_reader['authors'].append({'full_name': value})
+    else:
+        json_reader['authors[0].full_name'] = value
+
 """ Cooks for the deposition files """
 
 from invenio.bibdocfile import BibRecDocs
 
 
 def cook_files(json_reader, file_list):
     """ @param file_json: list (as created in blueprints)
                           containing dictionaries with files and their metadata
     """
 
     for file_json in file_list:
         filename = file_json['name']
         path = file_json['file']
 
         json_reader['fft[n]'] = {'path': path,
                                  'new_name': filename}
     return json_reader
 
 
 def uncook_files(webdeposit_json, recid=None, json_reader=None):
     if 'files' not in webdeposit_json:
         webdeposit_json['files'] = []
 
     if recid is None:
         for f in json_reader['url']:
             filename = f['url'].split('/')[-1]
             file_json = {
                 'name': filename
             }
             webdeposit_json['files'].append(file_json)
 
     else:
         for f in BibRecDocs(recid, human_readable=True).list_latest_files():
             filename = f.get_full_name()
             path = f.get_path()
             size = f.get_size()
             file_json = {
                 'name': filename,
                 'file': path,
                 'size': size
             }
             webdeposit_json['files'].append(file_json)
 
     return webdeposit_json
 
 
 def cook_icon(json_reader, icon_path):
     """ helper for adding an icon to a deposition
         e.g. Photo deposition """
     try:
         json_reader['fft[-1]']['icon_path'] = icon_path
     except IndexError:
         pass
     return json_reader
 
 
 def cook_picture(json_reader, file_list):
     """ Same as file cook with an additional icon cook
         It is assumed that its used for depositing one picture
     """
 
     if len(file_list) == 1:
         json_reader = cook_files(json_reader, file_list)
         json_reader = cook_icon(json_reader, file_list[0]['file'])
 
     return json_reader
diff --git a/modules/webdeposit/lib/webdeposit_field.py b/modules/webdeposit/lib/webdeposit_field.py
index d53188ce0..be78fb067 100644
--- a/modules/webdeposit/lib/webdeposit_field.py
+++ b/modules/webdeposit/lib/webdeposit_field.py
@@ -1,155 +1,265 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-from wtforms.validators import Required
-from invenio.webdeposit_config_utils import WebDepositConfiguration
+
+"""
+Validators
+----------
+Following is a short overview over how validators may be defined for fields.
+
+Inline validators (always executed)::
+
+    class MyForm(...):
+        myfield = MyField()
+
+        def validate_myfield(form, field):
+            raise ValidationError("Message")
+
+
+External validators (always executed)::
+
+    def my_validator(form, field):
+        raise ValidationError("Message")
+
+    class MyForm(...):
+            myfield = MyField(validators=[my_validator])
+
+
+Field defined validators (always executed)::
+
+    class MyField(...):
+        # ...
+        def pre_validate(self, form):
+            raise ValidationError("Message")
+
+Default field validators (executed only if external validators are not defined)::
+
+    class MyField(...):
+        def __init__(self, **kwargs):
+            defaults = dict(validators=[my_validator])
+            defaults.update(kwargs)
+            super(MyField, self).__init__(**defaults)
+
+
+See http://wtforms.simplecodes.com/docs/1.0.4/validators.html for how to
+write validators.
+
+Post-processors
+---------------
+Post processors follows the same pattern as validators. You may thus specify::
+
+ * Inline processors: Form.post_process_<field>(form, field)
+ * External processors: def my_processor(form, field) ... myfield = MyField(processors=[my_processor])
+ * Field defined processors (please method documentation): Field.post_process(self, form, extra_processors=[])
+
+Auto-complete
+-------------
+ * External auto-completion function: def my_autocomplete(form, field, limit=50) ... myfield = MyField(autocomplete=my_autocomplete)
+ * Field defined auto-completion function (please method documentation): Field.autocomplete(self, form, limit=50)
+
+Rec JSON key
+------------
+
+* External defined: myfield = MyField(recjson_key='...')
+* Default field defined::
+
+    class MyField(...):
+        def __init__(self, **kwargs):
+            defaults = {'recjson_key': '...'}
+            defaults.update(kwargs)
+            super(MyField, self).__init__(**defaults)
+"""
+
+from invenio.webdeposit_form import CFG_FIELD_FLAGS
+from invenio.webdeposit_cook_json_utils import cook_to_recjson
 
 __all__ = ['WebDepositField']
 
 
-def WebDepositField(key=None):
-    class WebDepositFieldClass(object):
+class WebDepositField(object):
+    """
+    Base field that all webdeposit fields must inherit from.
+    """
+
+    def __init__(self, **kwargs):
         """
-        Class that all webdeposit fields must inherit.
+        Initialize WebDeposit field.
+
+        Every field is associated with a marc field. To define this association you
+        have to specify the `recjson_key` for the bibfield's `JsonReader` or
+        the `cook_function` (for more complicated fields).
 
-        A helper to add attributes and methods to every webdeposit field.
+        @param placeholder: str, Placeholder text for input fields.
+        @param icon: Name of icon (rendering of the icon is done by templates)
+        @type icon: str
+        @param autocomplete: callable, A function to auto-complete values for field.
+        @param processors: list of callables, List of processors to run for field.
+        @param validators: list of callables, List of WTForm validators. If no validators are provided, validators defined in webdeposit_config will be loaded.
+        @param hidden: Set to true to hide field. Default: False
+        @type hidden: bool
+        @param disabled: Set to true to disable field. Default: False
+        @type disabled: bool
+        @param recjson_key: Name of recjson key
+        @type recjson_key: str
+        @param cook_function: the cook function
+        @type cook_function: function
+
+        @see http://wtforms.simplecodes.com/docs/1.0.4/validators.html for
+             how to write validators.
+        @see http://wtforms.simplecodes.com/docs/1.0.4/fields.html for further
+             keyword argument that can be provided on field initialization.
         """
+        # Pop WebDeposit specific kwargs before calling super()
+        self.placeholder = kwargs.pop('placeholder', None)
+        self.group = kwargs.pop('group', None)
+        self.icon = kwargs.pop('icon', None)
+        self.autocomplete = kwargs.pop('autocomplete', None)
+        self.processors = kwargs.pop('processors', None)
+        self.recjson_key = kwargs.pop('recjson_key', None)
+        self.cook_function = kwargs.pop('cook_function', None)
 
-        def __init__(self, **kwargs):
-            # Create our own Required data member
-            # for client-side use
-            if 'validators' in kwargs:
-                for v in kwargs.get("validators"):
-                    if type(v) is Required:
-                        self.required = True
-            if 'group' in kwargs:
-                self.group = kwargs.pop('group')
-            else:
-                self.group = None
-
-            super(WebDepositFieldClass, self).__init__(**kwargs)
-            self.config = WebDepositConfiguration(field_type=self.__class__.__name__)
-            self.recjson_key = self.config.get_recjson_key() or key
-
-        def merge_validation_json(self, json1, json2):
-            """ Merges 2 jsons returned from 2 validation functions
-
-                @param json1: the first json
-                @param json2: the second json
-                @returns: a dictionary with info, success and error messages,
-                          fields to be hidden/shown/disabled/enabled,
-                          and the dictionary with fields to be updated merged.
-                          Be carefull with jsons that update the same field!
-            """
-
-            json = {}
-
-            # Merge the messages of 2 dicts if they exist
-            def merge_msg(msg_exists, key, json1, json2):
-                if (json1.get(msg_exists) == 1 or json2.get(msg_exists) == 1):
-                    msg1 = (json1.get(key) or '')
-                    msg2 = (json2.get(key) or '')
-                    if msg1 == '':
-                        msg = msg2
-                    elif msg2 == '':
-                        msg == msg1
-                    else:
-                        msg = msg1 + '<br>' + msg2
-                    return 1, msg
-                else:
-                    return 0, ''
-
-            json['success'], json['success_message'] = \
-                merge_msg('success', 'success_message', json1, json2)
-
-            json['info'], json['info_message'] = \
-                merge_msg('info', 'info_message', json1, json2)
-
-            json['error'], json['error_message'] = \
-                merge_msg('error', 'error_message', json1, json2)
-
-
-            if 'fields' in json1 and 'fields' in json2:
-                """ Be carefull when the two validators change the
-                    value of the same field.
-                """
-                json['fields'] = dict(json1['fields'].items() +
-                                      json2['fields'].items())
-            elif 'fields' in json1:
-                json['fields'] = json1['fields']
-            elif 'fields' in json2:
-                json['fields'] = json2['fields']
-
-            # Create the union of the lists that specify UI actions on fields
-            concat_values = lambda key, json1, json2: \
-                            [i for i in json1.get(key) or []] + \
-                            [i for i in json2.get(key) or []]
-
-            json['hidden_fields'] = concat_values('hidden_fields',
-                                                  json1, json2)
-
-            json['visible_fields'] = concat_values('visible_fields',
-                                                   json1, json2)
-
-            json['enabled_fields'] = concat_values('enabled_fields',
-                                                   json1, json2)
-
-            json['disabled_fields'] = concat_values('disabled_fields',
-                                                    json1, json2)
-            return json
-
-        def has_recjson_key(self):
-            return self.recjson_key is not None
-
-        def cook_json(self, json_reader):
-            """
-            Fills a json_reader object with the field's value
-            based on the recjson key
-
-            @param json_reader: BibField's JsonReader object
-            """
-            cook_json_function = self.config.get_cook_json_function()
-            if cook_json_function is not None:
-                return cook_json_function(json_reader, self.data)
-            elif key is not None:  # Default behaviour
-                json_reader[key] = self.data
-
-            return json_reader
-
-        def uncook_json(self, json_reader, webdeposit_json):
-            """
-            The opposite of `cook_json` (duh)
-            Adds to the webdeposit_json the appropriate value
-            from the json_reader based on the recjson key
-
-            You have to retrieve the record with BibField and
-            instantiate a json_reader object before starting
-            the uncooking
-
-            @param json_reader: BibField's JsonReader object
-            @param webdeposit_json: a dictionary
-            @return the updated webdeposit_json
-            """
-
-            if self.has_recjson_key() and \
-                    self.recjson_key in json_reader:
-                webdeposit_json[self.name] = json_reader[self.recjson_key]
-            return webdeposit_json
-
-    return WebDepositFieldClass
+        # Initialize empty message variables, which are usually modified
+        # during the post-processing phases.
+        self.messages = []
+        self.message_state = ''
+
+        # Get flag values (e.g. hidden, disabled) before super() call.
+        # See CFG_FIELD_FLAGS for all defined flags.
+        flag_values = {}
+        for flag in CFG_FIELD_FLAGS:
+            flag_values[flag] = kwargs.pop(flag, False)
+
+        # Call super-constructor.
+        super(WebDepositField, self).__init__(**kwargs)
+
+        # Set flag values after super() call to ensure, flags set during
+        # super() are overwritten.
+        for flag, value in flag_values.items():
+            if value:
+                setattr(self.flags, flag, True)
+
+    def get_recjson_key(self):
+        return self.recjson_key
+
+    def has_cook_function(self):
+        return self.cook_function is not None
+
+    def has_recjson_key(self):
+        return self.recjson_key is not None
+
+    def cook_json(self, json_reader):
+        """
+        Fills a json_reader object with the field's value
+        based on the recjson key
+
+        @param json_reader: BibField's JsonReader object
+        """
+        cook = None
+        if self.has_recjson_key():
+            cook = cook_to_recjson(self.get_recjson_key())
+        elif self.has_cook_function():
+            cook = self.cook_function
+
+        if cook is not None:
+            return cook(json_reader, self.data)
+
+        return json_reader
+
+    def uncook_json(self, json_reader, webdeposit_json):
+        """
+        The opposite of `cook_json` (duh)
+        Adds to the webdeposit_json the appropriate value
+        from the json_reader based on the recjson key
+
+        You have to retrieve the record with BibField and
+        instantiate a json_reader object before starting
+        the uncooking
+
+        @param json_reader: BibField's JsonReader object
+        @param webdeposit_json: a dictionary
+        @return the updated webdeposit_json
+        """
+
+        if self.has_recjson_key() and \
+                self.recjson_key in json_reader:
+            webdeposit_json[self.name] = json_reader[self.recjson_key]
+        return webdeposit_json
+
+    def __call__(self, *args, **kwargs):
+        """
+        Set custom keyword arguments when rendering field
+        """
+        if 'placeholder' not in kwargs and self.placeholder:
+            kwargs['placeholder'] = self.placeholder
+        if 'disabled' not in kwargs and self.flags.disabled:
+            kwargs['disabled'] = "disabled"
+        return super(WebDepositField, self).__call__(*args, **kwargs)
+
+    def post_process(self, form, extra_processors=[], submit=False):
+        """
+        Post process form before saving.
+
+        Usually you can do some of the following tasks in the post
+        processing:
+
+         * Set field flags (e.g. self.flags.hidden = True or
+           form.<field>.flags.hidden = True).
+         * Set messages (e.g. self.messages.append('text') and
+           self.message_state = 'info').
+         * Set values of other fields (e.g. form.<field>.data = '').
+
+        Processors may stop the processing chain by raising StopIteration.
+
+        IMPORTANT: By default the method will execute custom post processors
+        defined in the webdeposit_config. If you override the method, be
+        sure to call this method to ensure extra processors are called::
+
+            super(MyField, self).post_process(form, extra_processors=extra_processors)
+        """
+        # Run post-processors (either defined)
+        stop = False
+        for p in (self.processors or []):
+            try:
+                p(form, self, submit)
+            except StopIteration:
+                stop = True
+                break
+
+        if not stop:
+            for p in (extra_processors or []):
+                p(form, self, submit)
+
+    def perform_autocomplete(self, form, term, limit=50):
+        """
+        Run auto-complete method for field. Use Form.autocomplete() to
+        perform auto-completion for a field, since it will take care of
+        preparing the field with data.
+        """
+        if self.autocomplete:
+            return self.autocomplete(form, term, limit=limit)
+        return []
+
+    def add_message(self, state, message):
+        """
+        Adds a message to display for the field.
+        The state can be info, error or success.
+        """
+        assert state in ['info', 'error', 'success']
+        self.message_state = state
+        self.messages.append(message)
diff --git a/modules/webdeposit/lib/webdeposit_field_widgets.py b/modules/webdeposit/lib/webdeposit_field_widgets.py
index 80d738764..f66170b1f 100644
--- a/modules/webdeposit/lib/webdeposit_field_widgets.py
+++ b/modules/webdeposit/lib/webdeposit_field_widgets.py
@@ -1,119 +1,135 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from wtforms.widgets import html_params, HTMLString
-
+from invenio.jinja2utils import render_template_to_string
 
 def date_widget(field, **kwargs):
     field_id = kwargs.pop('id', field.id)
-    html = [u'<input class="datepicker" %s value="" type="text">'
-            % html_params(id=field_id, name=field_id)]
+    html = [u'<input class="datepicker" %s type="text">'
+            % html_params(id=field_id, name=field_id, value=field.data or '')]
     field_class = kwargs.pop('class', '') or kwargs.pop('class_', '')
     kwargs['class'] = u'datepicker %s' % field_class
     kwargs['class'] = u'date %s' % field_class
     return HTMLString(u''.join(html))
 
 
 def plupload_widget(field, **kwargs):
     field_id = kwargs.pop('id', field.id)
-    # FIXME: Move html code in a template and initialize html variable
-    #        with the render_template_to_string function
-    html = [u' \
-            <div class="pluploader" %s > \
-                <div class="well" id="filebox">\
-                    <div id="drag_and_drop_text" style="text-align:center;z-index:-100;">\
-                        <h1><small>Drag and Drop files here</small></h1>\
-                    </div>\
-                </div> \
-                <table id="file-table" class="table table-striped table-bordered" style="display:none;">\
-                    <thead>\
-                        <tr>\
-                        <th>Filename</th>\
-                        <th>Size</th>\
-                        <th>Status</th>\
-                        <td></td>\
-                        </tr>\
-                    </thead>\
-                    <tbody id="filelist">\
-                    </tbody>\
-                </table>\
-                <a class="btn btn-primary" id="pickfiles" >Select files</a> \
-                <a class="btn btn-success disabled" id="uploadfiles"><i class="icon-upload icon-white"></i> Start upload</a>\
-                <a class="btn btn-danger" id="stopupload" style="display:none;"><i class="icon-stop icon-white"></i> Stop upload</a>\
-                <div id="upload-errors"></div>\
-            </div>' % html_params(id=field_id)]
     kwargs['class'] = u'plupload'
-    return HTMLString(u''.join(html))
+
+    return HTMLString(
+        render_template_to_string(
+            "webdeposit_widget_plupload.html",
+            field=field,
+            field_id=field_id,
+        )
+    )
 
 
 def bootstrap_submit(field, **kwargs):
     html = u'<input %s >' % html_params(style="float:right; width: 250px;",
                                         id="submitButton",
                                         class_="btn btn-primary btn-large",
                                         name="submitButton",
                                         type="submit",
                                         value=field.label.text,)
     html = [u'<div style="float:right;" >' + html + u'</div>']
     return HTMLString(u''.join(html))
 
 
 def ckeditor_widget(field, **kwargs):
     field.ckeditor = True
     field_id = kwargs.pop('id', field.id)
     html = [u'<textarea %s >'
-            % html_params(id=field_id, name=field_id)]
-    if field.data is not None:
-        html.append('%s</textarea>' % field.data)
-    else:
-        html.append('</textarea>')
-    return HTMLString(u''.join(html))
-
-    field_id = "ckeditor_" + field_id
-    html = [u'<textarea %s ></textarea>'
-            % html_params(id=field_id, name=field_id)]
+            % html_params(id=field_id, name=field_id, value=field.data or '')]
+    html.append('%s</textarea>' % field.data or '')
     return HTMLString(u''.join(html))
 
 
 def dropbox_widget(field, **kwargs):
     field_id = kwargs.pop('id', field.id)
     html = [u'<input type="dropbox-chooser"\
             name="fileurl"\
             style="visibility: hidden;"\
             data-link-type="direct"\
             id="db-chooser"/></br> \
         <div class="pluploader" %s > \
             <table id="file-table" class="table table-striped table-bordered" style="display:none;">\
                 <thead>\
                     <tr>\
                     <th>Filename</th>\
                     <th>Size</th>\
                     <th>Status</th>\
                     <td></td>\
                     </tr>\
                 </thead>\
                 <tbody id="filelist">\
                 </tbody>\
             </table>\
             <a class="btn btn-success disabled" id="uploadfiles"> \
                 <i class="icon-upload icon-white"></i> Start upload</a>\
             <a class="btn btn-danger" id="stopupload" style="display:none;">\
-                <i class="icon-stop icon-white"></i> Stop upload</a>\
+                <i class="icon-stop icon-white"></i> Cancel upload</a>\
+            <span id="upload_speed" class="pull-right"></span>\
             <div id="upload-errors"></div>\
         </div>' % html_params(id=field_id)]
     return HTMLString(u''.join(html))
+
+
+class ButtonWidget(object):
+    """
+    Renders a button.
+    """
+
+    def __init__(self, label="", tooltip=None, icon=None, **kwargs):
+        """
+        Note, the icons assume use of Twitter Bootstrap,
+        Font Awesome or some other icon library, that allows
+        inserting icons with a <i>-tag.
+
+        @param tooltip: str, Tooltip text for the button.
+        @param icon: str, Name of an icon, e.g. icon-barcode.
+        """
+        self.icon = icon
+        self.label = label
+        self.default_params = kwargs
+        self.default_params.setdefault('type', 'button')
+        if tooltip:
+            self.default_params.setdefault('data-toggle', 'tooltip')
+            self.default_params.setdefault('title', tooltip)
+        super(ButtonWidget, self).__init__()
+
+    def __call__(self, field, **kwargs):
+        params = self.default_params.copy()
+        params.update(kwargs)
+        params.setdefault('id', field.id)
+        params['class_'] = params.get('class_',"") + " form-button"
+
+        icon = ""
+        if self.icon:
+            icon = '<i class="%s"></i> ' % self.icon
+
+        state = ""
+        if field._value():
+            state = '<span class="text-success"> <i class="icon-ok"></i></span>'
+
+        return HTMLString(u'<button %s>%s%s</button><span %s>%s</span>' % (html_params(
+            name=field.name, **params), icon, self.label,
+            html_params(id=field.name+'-loader', class_='loader'), state))
diff --git a/modules/webdeposit/lib/webdeposit_filter_utils.py b/modules/webdeposit/lib/webdeposit_filter_utils.py
new file mode 100644
index 000000000..8b5a2fd80
--- /dev/null
+++ b/modules/webdeposit/lib/webdeposit_filter_utils.py
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Invenio.
+# Copyright (C) 2013 CERN.
+#
+# Invenio is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# Invenio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Invenio; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
+"""
+WTForm filters
+--------------
+Filters can be applied to incoming form data, after process_formdata() has run.
+
+See more information on:
+http://wtforms.simplecodes.com/docs/1.0.4/fields.html#wtforms.fields.Field.__init__
+"""
+
+
+def strip_string(value):
+    """
+    Remove leading and trailing spaces from string
+    """
+    if isinstance(value, basestring):
+        return value.strip()
+    else:
+        return value
+
+
+def splitlines_list(value):
+    """
+    Split string per line into a list
+    """
+    if isinstance(value, basestring):
+        newdata = []
+        for line in value.splitlines():
+            if line.strip():
+                newdata.append(line.strip().encode('utf8'))
+        return newdata
+    else:
+        return value
+
+
+def splitchar_list(c):
+    """
+    Return filter function that split string per char into a list.
+
+    @param c: Character to split on.
+    """
+    def _inner(value):
+        """
+        Split string per char into a list
+        """
+        if isinstance(value, basestring):
+            newdata = []
+            for item in value.split(c):
+                if item.strip():
+                    newdata.append(item.strip().encode('utf8'))
+            return newdata
+        else:
+            return value
+    return _inner
+
+
+def map_func(func):
+    """
+    Return filter function that map a function to each item of a list
+
+    @param func: Function to map.
+    """
+    # FIXME
+    def _mapper(data):
+        """
+        Map a function to each item of a list
+        """
+        if isinstance(data, list):
+            return map(func, data)
+        else:
+            return data
+    return _mapper
+
+
+def strip_prefixes(*prefixes):
+    """
+    Return a filter function that removes leading prefixes from a string
+    """
+    def _inner(value):
+        """
+        Remove a leading prefix from string
+        """
+        if isinstance(value, basestring):
+            for prefix in prefixes:
+                if value.lower().startswith(prefix):
+                    return value[len(prefix):]
+        return value
+    return _inner
\ No newline at end of file
diff --git a/modules/webdeposit/lib/webdeposit_form.js b/modules/webdeposit/lib/webdeposit_form.js
index 972563d77..314e0ab62 100644
--- a/modules/webdeposit/lib/webdeposit_form.js
+++ b/modules/webdeposit/lib/webdeposit_form.js
@@ -1,463 +1,682 @@
 /*
  * This file is part of Invenio.
  * Copyright (C) 2013 CERN.
  *
  * Invenio is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * Invenio is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with Invenio; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 
 
+/* Helpers */
+
+function unique_id() {
+    return Math.round(new Date().getTime() + (Math.random() * 100));
+}
+
 /*
- * Plupload
+ * Get settings for performing an AJAX request with $.ajax
+ * that will POST a JSON object to the given URL
+ *
+ * @param settings: A hash with the keys: url, data.
  */
+function json_options(settings){
+    // Perform AJAX request with JSON data.
+    return {
+        url: settings['url'],
+        type: 'POST',
+        cache: false,
+        data: JSON.stringify(settings['data']),
+        contentType: "application/json; charset=utf-8",
+        dataType: 'json'
+    };
+}
 
-function unique_ID() {
-    return Math.round(new Date().getTime() + (Math.random() * 100));
+/*
+ * Serialize a form into JSON
+ */
+function serialize_object(selector){
+    var o = {};
+    var a = $(selector).serializeArray();
+    $.each(a, function() {
+        if (o[this.name] !== undefined) {
+            if (!o[this.name].push) {
+                o[this.name] = [o[this.name]];
+            }
+            o[this.name].push(this.value || '');
+        } else {
+            o[this.name] = this.value || '';
+        }
+    });
+    return o;
 }
 
+function getBytesWithUnit(bytes){
+	if( isNaN( bytes ) ){
+        return '';
+    }
+	var units = [' bytes', ' KB', ' MB', ' GB'];
+	var amountOf2s = Math.floor( Math.log( +bytes )/Math.log(2) );
+	if( amountOf2s < 1 ){
+		amountOf2s = 0;
+	}
+	var i = Math.floor( amountOf2s / 10 );
+	bytes = +bytes / Math.pow( 2, 10*i );
+
+	// Rounds to 2 decimals places.
+    bytes_to_fixed = bytes.toFixed(2);
+    if( bytes.toString().length > bytes_to_fixed.toString().length ){
+        bytes = bytes_to_fixed;
+    }
+	return bytes + units[i];
+}
+
+/*
+ * Initialize PLUpload
+ */
 function webdeposit_init_plupload(selector, url, delete_url, get_file_url, db_files, dropbox_url) {
 
     uploader = new plupload.Uploader({
         // General settings
         runtimes : 'html5',
         url : url,
         max_file_size : '460mb',
         chunk_size : '1mb',
         //unique_names : true,
         browse_button : 'pickfiles',
-        drop_element : 'filebox'
+        drop_element : 'field-plupload_file'
 
         // Specify what files to browse for
         //filters : [
         //    {title : "Image files", extensions : "jpg,gif,png,tif"},
         //    {title : "Compressed files", extensions : "rar,zip,tar,gz"},
         //    {title : "PDF files", extensions : "pdf"}
         //]
     });
 
+    queue_progress = new plupload.QueueProgress();
+
     uploader.init();
 
     $(function() {
         if (!jQuery.isEmptyObject(db_files)) {
             $('#file-table').show('slow');
 
             $.each(db_files, function(i, file) {
                 // Simulate a plupload file object
-                id = unique_ID();
+                id = unique_id();
                 var plfile = new plupload.File({
                     id: id,
                     name: file.name,
                     size: file.size
                 });
                 // Dont touch it!
                 // For some reason the constructor doesn't initialize
                 // the data members
                 plfile.id = id;
                 plfile.name = file.name;
                 plfile.size = file.size;
-                plfile.loaded = file.size;
-                plfile.status = 5;
+                // loaded is set to 0 as a temporary fix plupload's  bug in
+                // calculating current upload speed. For checking if a file
+                // has been uploaded, check file.status
+                plfile.loaded = 0; //file.size;
+                plfile.status = 5; //status = plupload.DONE
                 plfile.percent = 100;
                 plfile.unique_filename = file.unique_filename;
                 ///////
                 uploader.files.push(plfile);
                 $('#filelist').append(
                     '<tr id="' + plfile.id + '" style="display:none;">' +
                         '<td><a href="' + get_file_url + "?filename=" + plfile.unique_filename + '">' + plfile.name + '</a></td>' +
-                        '<td>' + plupload.formatSize(plfile.size) + '</td>' +
+                        '<td>' +  getBytesWithUnit(plfile.size) + '</td>' +
                         '<td width="30%"><div class="progress active"><div class="bar" style="width: 100%;"></div></div></td>' +
                         '<td><a id="' + plfile.id + '_rm" class="rmlink"><i class="icon-trash"></i></a></td>' +
                     '</tr>');
                 $('#filelist #' + plfile.id).show('fast');
                 $("#" + plfile.id + "_rm").on("click", function(event) {
                     uploader.removeFile(plfile);
                 });
             });
         }
     });
 
     $('#uploadfiles').click(function(e) {
-        uploader.start();
-        $('#uploadfiles').hide();
+        $('#uploadfiles').addClass('disabled');
         $('#stopupload').show();
+        uploader.start();
         e.preventDefault();
 
         $.each(dropbox_files, function(i, file){
             $.ajax({
                 type: 'POST',
                 url: dropbox_url,
                 data: $.param({
                     name: file.name,
                     size: file.size,
                     url: file.url
                 })
             }).done(function(data){
                 $('#' + file.id + " .progress").removeClass("progress-striped");
                 $('#' + file.id + " .bar").css('width', "100%");
                 $('#' + file.id + '_link').html('<a href="' + get_file_url + "?filename=" + data + '">' + file.name + '</a>');
             });
         });
         dropbox_files = [];
-        $('#uploadfiles').addClass('disabled');
-        $('#stopupload').hide();
-        $('#uploadfiles').show();
     });
 
     $('#stopupload').click(function(d){
         uploader.stop();
         $('#stopupload').hide();
-        $('#uploadfiles').show();
+        $('#uploadfiles').removeClass('disabled');
         $.each(uploader.files, function(i, file) {
             if (file.loaded < file.size) {
                 $("#" + file.id + "_rm").show();
-                $('#' + file.id + " .bar").css('width', "0%");
+                //$('#' + file.id + " .bar").css('width', "0%");
             }
         });
+        $('#upload_speed').html('');
+        uploader.total.reset();
     });
 
     uploader.bind('FilesRemoved', function(up, files) {
         $.each(files, function(i, file) {
             $('#filelist #' + file.id).hide('fast');
-            if (file.loaded === file.size) {
+            if (file.status === plupload.DONE) { //If file has been successfully uploaded
                 $.ajax({
                     type: "POST",
                     url: delete_url,
                     data: $.param({
                         filename: file.unique_filename
                     })
                 });
             }
         });
         if(uploader.files.length === 0) {
             $('#uploadfiles').addClass("disabled");
             $('#file-table').hide('slow');
         }
     });
 
     uploader.bind('UploadProgress', function(up, file) {
         $('#' + file.id + " .bar").css('width', file.percent + "%");
+        upload_speed = getBytesWithUnit(up.total.bytesPerSec) + " per sec";
         console.log("Progress " + file.name + " - " + file.percent);
+        $('#upload_speed').html(upload_speed);
+        up.total.reset();
     });
 
+
+
     uploader.bind('UploadFile', function(up, file) {
         $('#' + file.id + "_rm").hide();
     });
 
 
     uploader.bind('FilesAdded', function(up, files) {
         $('#uploadfiles').removeClass("disabled");
         $('#file-table').show('slow');
+        up.total.reset();
         $.each(files, function(i, file) {
             $('#filelist').append(
                 '<tr id="' + file.id + '" style="display:none;z-index:-100;">' +
                 '<td id="' + file.id + '_link">' + file.name + '</td>' +
-                '<td>' + plupload.formatSize(file.size) + '</td>' +
-                '<td width="30%"><div class="progress progress-stri´ped active"><div class="bar" style="width: 0%;"></div></div></td>' +
+                '<td>' + getBytesWithUnit(file.size) + '</td>' +
+                '<td width="30%"><div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div></td>' +
                 '<td><a id="' + file.id + '_rm" class="rmlink"><i class="icon-trash"></i></a></td>' +
                 '</tr>');
             $('#filelist #' + file.id).show('fast');
             $('#' + file.id + '_rm').on("click", function(event){
                 uploader.removeFile(file);
             });
         });
     });
 
     uploader.bind('FileUploaded', function(up, file, responseObj) {
         console.log("Done " + file.name);
         $('#' + file.id + " .progress").removeClass("progress-striped");
         $('#' + file.id + " .bar").css('width', "100%");
         $('#' + file.id + '_rm').show();
         $('#' + file.id + '_link').html('<a href="' + get_file_url + "?filename=" + responseObj.response + '">' + file.name + '</a>');
         file.unique_filename = responseObj.response;
         if (uploader.total.queued === 0)
             $('#stopupload').hide();
 
+        file.loaded = 0;
+        $('#upload_speed').html('');
         $('#uploadfiles').addClass('disabled');
         $('#uploadfiles').show();
+        up.total.reset();
+    });
 
+    $("#filelist").sortable();
+    $("#filelist").disableSelection();
+}
+
+/*
+ * Initialize save-button
+ */
+function webdeposit_init_save(url, selector, form_selector) {
+    $(selector).click(function(e){
+        // Stop propagation of event to prevent form submission
+        e.preventDefault();
+
+        webdeposit_set_status(tpl_webdeposit_status_saving, {name: null, value: null});
+
+        $.ajax(
+            json_options({url: url, data: serialize_object(form_selector)})
+        ).done(function(data) {
+            var errors = false;
+            // FIXME- get errors from response
+            webdeposit_handle_response(data);
+            webdeposit_set_status(tpl_webdeposit_status_saved, {name: name, value: null});
+            if(errors) {
+                webdeposit_set_status(tpl_webdeposit_status_saved_with_errors, {name: name, value: null});
+                webdeposit_flash_message({state:'warning', message: tpl_message_errors.render({})});
+            } else {
+                webdeposit_set_status(tpl_webdeposit_status_saved, {name: name, value: value});
+                webdeposit_flash_message({state:'success', message: tpl_message_success.render({})});
+            }
+        }).fail(function() {
+            webdeposit_flash_message({state:'error', message: tpl_message_server_error.render({})});
+            check_empty_fields(name);
+            webdeposit_set_status(tpl_webdeposit_status_error, {name: name, value: value});
+        });
+
+        return false;
     });
+}
 
+
+/*
+ * Initialize submit-button
+ */
+function webdeposit_init_submit(url, selector, form_selector) {
+    $(selector).click(function(e){
+        e.preventDefault();
+        // webdeposit_set_status(tpl_webdeposit_status_saving, {});
+        // //emptyForm = checkEmptyFields(null);
+        // if (emptyForm[0] == 0){
+        //     $('#empty-fields-error').hide('slow');
+        //     webdeposit_set_status(tpl_webdeposit_status_saved, {});
+        // }
+        // else {
+        //     $('#empty-fields-error').html("<a class='close' data-dismiss='alert' href='#'>×</a>These fields are required:<ul>" + emptyForm[1] + "</ul>" );
+        //     $('#empty-fields-error').show('slow');
+        //     webdeposit_set_status(tpl_webdeposit_status_saved_with_errors, {});
+        // }
+    });
 }
 
 
 /* Error checking */
 var errors = 0;
 var oldJournal;
 
 
-function webdeposit_handle_field_data(name, value, data, url, required_fields) {
-    // handles a response from the server for the field
-    if (data.error == 1) {
-        errorMsg = data.error_message;
-        $('#error-' + name).html(errorMsg);
-        $('.error-list-' + name).hide('slow');
-        $('#error-' + name).show('slow');
-        $("#error-group-" + name).addClass('error');
-        errors++;
-    } else {
-        $('#error-' + name).hide('slow');
-        $('.error-list-' + name).hide('slow');
-        $("#error-group-" + name).removeClass('error');
-        if (errors > 0)
-            errors--;
-        emptyForm = checkEmptyFields(false, name, required_fields);
-        if (emptyForm[0] === 0) {
-            $('#empty-fields-error').hide('slow');
-        }
-        else {
-            $('#empty-fields-error').html("These fields are required!</br>" + emptyForm[1]);
-            $('#empty-fields-error').show();
-        }
-    }
-
-    dismiss = '<button type="button" class="close" data-dismiss="alert">&times;</button>';
-
-    if (data.success == 1) {
-        success = '<div class="alert alert-success help-inline" id="success-' + name + '" style="display:none;">' +
-                  dismiss + data.success_message +
-                  '</div>';
-        $('#success-' + name).remove();
-        $('#field-' + name).append(success);
-        $('#success-' + name).show('slow');
-    }
-    else {
-      $('#success-' + name).remove();
+/*
+ * Handle update of field message box.
+ *
+ * @return: True if message was set, False if no message was set.
+ */
+function webdeposit_handle_field_msg(name, data) {
+    if(!data) {
+        return false;
     }
 
-    if (data.info == 1) {
-        info = '<div class="alert alert-info help-inline" id="info-' + name + '" style="display:none;">' +
-               dismiss + data.info_message +
-               '</div>';
-        $('#info-' + name).remove();
-        $('#field-' + name).append(info);
-        $('#info-' + name).css('margin-top', '10px');
-        $('#info-' + name).css('clear', 'both');
-        $('#info-' + name).css('float', 'left');
-        $('#info-' + name).show('slow');
-    }
-    else {
-      $('#info-' + name).remove();
+    state = '';
+    if(data.state) {
+        state = data.state;
     }
 
-    if (data.fields) {
-        $.each(data.fields, function(name, value) {
-            if (name == 'files'){
-                $.each(value, function(i, file){
-                    id = unique_ID();
-
-                    new_file = {
-                        id: id,
-                        name: file.name,
-                        size: file.size
-                    };
-
-                    $('#filelist').append(
-                        '<tr id="' + id + '" style="display:none;">' +
-                            '<td id="' + id + '_link">' + file.name + '</td>' +
-                            '<td>' + plupload.formatSize(file.size) + '</td>' +
-                            '<td width="30%"><div class="progress active"><div class="bar" style="width: 100%;"></div></div></td>' +
-                        '</tr>');
-                    $('#filelist #' + id).show('fast');
-                });
-                $('#file-table').show('slow');
-            }
-            else {
-                $('#error-' + name).hide('slow');
-                errors--;
-                old_value = $('[name=' + name + ']').val();
-                if (old_value != value) {
-                    if (typeof ckeditor === 'undefined')
-                        $('[name=' + name + ']').val(value);
-                    else if (ckeditor.name == name)
-                            ckeditor.setData(value);
-                    webdeposit_handle_new_value(name, value, url, required_fields);
-                }
+    if(data.messages && data.messages.length !== 0) {
+        $('#state-' + name).html(
+            tpl_field_message.render({
+                name: name,
+                state: state,
+                messages: data.messages
+            })
+        );
+
+        ['info','warning','error','success'].map(function(s){
+            $("#state-group-" + name).removeClass(s);
+            $("#state-" + name).removeClass('alert-'+s);
+            if(s == state) {
+                $("#state-group-" + name).addClass(state);
+                $("#state-" + name).addClass('alert-'+state);
             }
         });
+
+        $('#state-' + name).show('fast');
+        return true;
+    } else {
+        webdeposit_clear_error(name);
+        return false;
     }
+}
 
-    if (data.disabled_fields) {
-        $.each(data.disabled_fields, function(i, field){
-            $('#'+field).attr('disabled','disabled');
+function webdeposit_clear_error(name){
+    $('#state-' + name).hide();
+    $('#state-' + name).html("");
+    ['info','warning','error','success'].map(function(s){
+        $("#state-group-" + name).removeClass(s);
+        $("#state-" + name).removeClass('alert-'+s);
+    });
+}
+
+function webdeposit_handle_field_values(name, value) {
+    if (name == 'files'){
+        $.each(value, function(i, file){
+            id = unique_id();
+
+            new_file = {
+                id: id,
+                name: file.name,
+                size: file.size
+            };
+
+            $('#filelist').append(
+                '<tr id="' + id + '" style="display:none;">' +
+                    '<td id="' + id + '_link">' + file.name + '</td>' +
+                    '<td>' + getBytesWithUnit(file.size) + '</td>' +
+                    '<td width="30%"><div class="progress active"><div class="bar" style="width: 100%;"></div></div></td>' +
+                '</tr>');
+            $('#filelist #' + id).show('fast');
         });
+        $('#file-table').show('slow');
+    } else {
+        webdeposit_clear_error(name);
+        errors--;
+        old_value = $('[name=' + name + ']').val();
+        if (old_value != value) {
+            if (typeof ckeditor === 'undefined')
+                $('[name=' + name + ']').val(value);
+            else if (ckeditor.name == name)
+                    ckeditor.setData(value);
+            //webdeposit_handle_new_value(name, value, url);
+        }
     }
+}
 
-    if (data.enabled_fields) {
-        $.each(data.enabled_fields, function(i, field){
-            $('#'+field).removeiAttr('disabled');
+/*
+ * Handle server response for multiple fields.
+ */
+function webdeposit_handle_response(data) {
+    if('messages' in data) {
+        $.each(data['messages'], webdeposit_handle_field_msg);
+    }
+    if('values' in data) {
+        $.each(data['values'], webdeposit_handle_field_values);
+    }
+    if('hidden_on' in data) {
+        $.each(data['hidden_on'], function(idx, field){
+            $('#state-group-'+field).hide("slow");
         });
     }
-
-    if (data.hidden_fields) {
-        $.each(data.hidden_fields, function(i, field){
-            $('#error-group-'+field).hide();
+    if('hidden_off' in data) {
+        $.each(data['hidden_off'], function(idx, field){
+            $('#state-group-'+field).show("slow");
         });
     }
-
-    if (data.visible_fields) {
-        $.each(data.visible_fields, function(i, field){
-            $('#error-group-'+field).show();
+    if('disabled_on' in data) {
+        $.each(data['disabled_on'], function(idx, field){
+            $('#'+field).attr('disabled','disabled');
+        });
+    }
+    if('disabled_off' in data) {
+        $.each(data['disabled_off'], function(idx, field){
+            $('#'+field).removeAttr('disabled');
         });
     }
+}
 
-  }
+/*
+ * Set value of status indicator in form (e.g. saving, saved, ...)
+ */
+function webdeposit_set_status(tpl, ctx) {
+    $('.status-indicator').show();
+    $('.status-indicator').html(tpl.render(ctx));
+}
+
+function webdeposit_set_loader(selector, tpl, ctx) {
+    $(selector).show();
+    $(selector).html(tpl.render(ctx));
+}
+
+/*
+ * Flash a message in the top.
+ */
+function webdeposit_flash_message(ctx) {
+    $('#flash-message').html(tpl_flash_message.render(ctx));
+    $('#flash-message').show();
+}
 
-function webdeposit_handle_new_value(name, value, url, required_fields) {
+function webdeposit_handle_new_value(name, value, url) {
   // sends an ajax request with the data
   $.getJSON(url, {
       name: name,
       attribute: value
   }, function(data){
-        webdeposit_handle_field_data(name, value, data, url, required_fields);
-        $('#status-indicator').html("Saved!");
+        webdeposit_handle_field_data(name, value, data, url);
+        webdeposit_set_status(tpl_webdeposit_status_saved, {name: name, value: value});
   });
 }
 
-function webdeposit_input_error_check(selector, url, required_fields) {
-  $(selector).change( function() {
+
+/*
+ * Save and check field values for errors.
+ */
+function webdeposit_input_error_check(selector, url) {
+    $(selector).change( function() {
         name = this.name;
         value = this.value;
-        $('#status-indicator').html("Saving " + $("label[for="+this.name+"]").html() + "...");
-        $.getJSON(url, {
-            name: name,
-            attribute: value
-        }, function(data){
-            webdeposit_handle_field_data(name, value, data, url, required_fields);
-            $('#status-indicator').html("Saved!");
+
+        webdeposit_set_status(tpl_webdeposit_status_saving, {name: name, value: value});
+
+        request_data = {};
+        request_data[name] = value;
+
+        $.ajax(
+            json_options({url: url, data: request_data})
+        ).done(function(data) {
+            webdeposit_handle_response(data);
+            webdeposit_set_status(tpl_webdeposit_status_saved, {name: name, value: value});
+        }).fail(function() {
+            check_empty_fields(name);
+            webdeposit_set_status(tpl_webdeposit_status_error, {name: name, value: value});
         });
-    return false;
-  });
+
+        return false;
+    });
+}
+
+/*
+ * Click form-button
+ */
+function webdeposit_button_click(selector, url) {
+    $(selector).click( function() {
+        name = this.name;
+        loader_selector = '#' + name + '-loader';
+
+        webdeposit_set_loader(loader_selector, tpl_loader, {name: name});
+
+        request_data = {};
+        request_data[name] = true;
+
+        $.ajax(
+            json_options({url: url, data: request_data})
+        ).done(function(data) {
+            webdeposit_handle_response(data);
+            webdeposit_set_loader(loader_selector, tpl_loader_success, {name: name});
+        }).fail(function() {
+            webdeposit_set_loader(loader_selector, tpl_loader_failed, {name: name});
+        });
+
+        return false;
+    });
 }
 
 
+
+
 /*
  * CKEditor
  */
 
-function webdeposit_ckeditor_init(selector, url, required_fields) {
+function webdeposit_ckeditor_init(selector, url) {
     CKEDITOR.replace(selector);
 
     ckeditor = CKEDITOR.instances[selector];
     ckeditor.on('blur',function(event){
-        webdeposit_handle_new_value(selector, ckeditor.getData(), url, required_fields);
+        webdeposit_handle_new_value(selector, ckeditor.getData(), url);
     });
 }
 
 /********************************************************/
+/*
+ * Check if required field is empty
+ *
+ * @param field: Name of field, or null to check all fields.
+ */
+function check_empty_fields(field) {
+    check_fields = [];
+    empty_fields = [];
+
+    if (field && $.inArray(field, required_fields)) {
+        check_fields = [field];
+    } else if (field === undefined) {
+        check_fields = required_fields;
+    }
 
+    check_fields.map(function(f){
+        label = $("label[for='"+f+"']").html() || '';
+        value = $('#'+f).val();
 
-function checkEmptyFields(all_fields, field, required_fields) {
-    var emptyFields = "";
-    var empty = 0;
-    $(":text, :file, :checkbox, select, textarea").each(function() {
-      // Run the checks only for fields that are required
-      if ($.inArray(this.name, required_fields) > -1) {
-        if(($(this).val() === "") || ($(this).val() === null)) {
-            emptyFields += "- " + $("label[for='"+this.name+"']").html() + "</br>";
-            if ( (all_fields === true) || (field == this.name)) {
-                $('#error-'+this.name).html($("label[for='"+this.name+"']").html() + " field is required!");
-                $('#error-'+this.name).show('slow');
-            }
-            empty = 1;
+        if(value === "" || value === null) {
+            webdeposit_handle_field_msg(field, {state: 'error', message: tpl_required_field_message.render({label: label.toString().trim(), value: value})});
+            empty_fields.push(f);
         } else {
-          $('#error-'+this.name).hide('slow');
+            webdeposit_handle_field_msg(field, {state: '', message: ''});
         }
-      }
     });
-    // Return the text only if all fields where requested
-    if ( (empty == 1) && all_fields)
-        return [1, emptyFields];
-    else
-        return [0, emptyFields];
+
+    return empty_fields;
 }
 
+// function checkEmptyFields(all_fields, field, required_fields) {
+//     var emptyFields = "";
+//     var empty = 0;
+//     $(":text, :file, :checkbox, select, textarea").each(function() {
+//       // Run the checks only for fields that are required
+//       if ($.inArray(this.name, required_fields) > -1) {
+//         if(($(this).val() === "") || ($(this).val() === null)) {
+//             emptyFields += "<li>" + $("label[for='"+this.name+"']").html() + "</li>";
+//             if ( (all_fields === true) || (field == this.name)) {
+//                 $('#error-'+this.name).html($("label[for='"+this.name+"']").html() + " field is required!");
+//                 $("#error-group-" + this.name).addClass('error');
+//                 $('#error-'+this.name).show('slow');
+//             }
+//             empty = 1;
+//         } else {
+//           $('#error-'+this.name).hide('slow');
+//         }
+//       }
+//     });
+//     // Return the text only if all fields where requested
+//     if ( (empty == 1) && all_fields)
+//         return [1, emptyFields];
+//     else
+//         return [0, emptyFields];
+// }
+
 var autocomplete_request = $.ajax();
 
 function webdeposit_field_autocomplete(selector, url) {
 
     var source = function(query) {
       $(selector).addClass('ui-autocomplete-loading');
       var typeahead = this;
       autocomplete_request.abort();
       autocomplete_request = $.ajax({
         type: 'GET',
         url: url,
         data: $.param({
           term: query
         })
       }).done(function(data) {
         typeahead.process(data.results);
         $(selector).removeClass('ui-autocomplete-loading');
       }).fail(function(data) {
         typeahead.process([query]);
         $(selector).removeClass('ui-autocomplete-loading');
       });
     };
 
     // FIXME: typeahead doesn't support a delay option
     //        so for every change an ajax request is
     //        being sent to the server.
     $(selector).typeahead({
       source: source,
       minLength: 5,
       items: 50
     });
 }
 
 
 function webdeposit_check_status(url){
     setInterval(function() {
         $.ajax({
             type: 'GET',
             url: url
         }).done(function(data) {
             if (data.status == 1)
                 location.reload();
         });
     }, 10000);
 }
 
 
 var dropbox_files = [];
 
 if (document.getElementById("db-chooser") !== null) {
     document.getElementById("db-chooser").addEventListener("DbxChooserSuccess",
         function(e) {
             $('#file-table').show('slow');
             $.each(e.files, function(i, file){
-                id = unique_ID();
+                id = unique_id();
 
                 dbfile = {
                     id: id,
                     name: file.name,
                     size: file.bytes,
                     url: file.link
                 };
 
                 $('#filelist').append(
                     '<tr id="' + id + '" style="display:none;">' +
                         '<td id="' + id + '_link">' + file.name + '</td>' +
-                        '<td>' + plupload.formatSize(file.bytes) + '</td>' +
+                        '<td>' + getBytesWithUnit(file.bytes) + '</td>' +
                         '<td width="30%"><div class="progress active"><div class="bar" style="width: 0%;"></div></div></td>' +
                         '<td><a id="' + id + '_rm" class="rmlink"><i class="icon-trash"></i></a></td>' +
                     '</tr>');
                 $('#filelist #' + id).show('fast');
                 $('#uploadfiles').removeClass("disabled");
+                $('#' + dbfile.id + '_rm').on("click", function(event){
+                    $('#' + dbfile.id).hide('fast');
+                });
 
                 dropbox_files.push(dbfile);
             });
         }, false);
 }
 
 
diff --git a/modules/webdeposit/lib/webdeposit_form.py b/modules/webdeposit/lib/webdeposit_form.py
index d8e01f051..9f58733c4 100644
--- a/modules/webdeposit/lib/webdeposit_form.py
+++ b/modules/webdeposit/lib/webdeposit_form.py
@@ -1,108 +1,260 @@
 # -*- coding: utf-8 -*-
-##
-## This file is part of Invenio.
-## Copyright (C) 2013 CERN.
-##
-## Invenio is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2 of the
-## License, or (at your option) any later version.
-##
-## Invenio is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Invenio; if not, write to the Free Software Foundation, Inc.,
-## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
-
-from wtforms import Label
+#
+# This file is part of Invenio.
+# Copyright (C) 2013 CERN.
+#
+# Invenio is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# Invenio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Invenio; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
 from invenio.wtforms_utils import InvenioForm as Form
-from invenio.webdeposit_config_utils import WebDepositConfiguration
 from invenio.webdeposit_cook_json_utils import cook_files, uncook_files
 
+CFG_GROUPS_META = {
+    'classes': None,
+    'indication': None,
+    'description': None
+}
+"""
+Default group metadata.
+"""
 
-class WebDepositForm(Form):
+CFG_FIELD_FLAGS = [
+    'hidden',
+    'disabled'
+]
+"""
+List of WTForm field flags to be saved in draft.
 
-    """ Generic WebDeposit Form class """
+See more about WTForm field flags on:
+http://wtforms.simplecodes.com/docs/1.0.4/fields.html#wtforms.fields.Field.flags
+"""
 
-    def __init__(self, **kwargs):
-        super(WebDepositForm, self).__init__(**kwargs)
+"""
+Form customization
 
-        # Load and apply configuration from config file
-        self.config = WebDepositConfiguration(form_type=self.__class__.__name__)
+you can customize the following for the form
 
-        custom_title = self.config.get_form_title(self.__class__.__name__)
-        if custom_title is not None:
-            self._title = custom_title
+_title: str, the title to be rendered on top of the form
+_subtitle: str/html. explanatory text to be shown under the title.
+_drafting: bool, show or hide the drafts at the right of the form
 
-        for field in self._fields.values():
-            custom_label = self.config.get_label(field.__class__.__name__)
-            if custom_label is not None:
-                setattr(field, 'label', Label(field.id, custom_label))
+"""
 
-            custom_widget = self.config.get_widget(field.__class__.__name__)
-            if custom_widget is not None:
-                setattr(field, 'widget', custom_widget)
+
+class WebDepositForm(Form):
+
+    """ Generic WebDeposit Form class """
+
+    def __init__(self, **kwargs):
+        super(WebDepositForm, self).__init__(**kwargs)
+        self._messages = None
 
         self.groups_meta = {}
         if hasattr(self, 'groups'):
-            for group in self.groups:
+            for idx, group in enumerate(self.groups):
                 group_name = group[0]
                 fields = group[1]
                 for field in fields:
                     setattr(self[field], 'group', group_name)
+
+                self.groups_meta[group_name] = CFG_GROUPS_META.copy()
                 if len(group) == 3:  # If group has metadata
-                    group_meta = group[2]
-                    self.groups_meta[group_name] = group_meta
+                    self.groups_meta[group_name].update(group[2])
+
+        if not hasattr(self, 'template'):
+            self.template = 'webdeposit_add.html'
+
+        if not hasattr(self, '_drafting'):
+            self._drafting = True
+
+        self.type = self.__class__.__name__
+
+    def reset_field_data(self, exclude=[]):
+        """
+        Reset the fields.data value to that of field.object_data.
+
+        Useful after initializing a form with both formdata and draftdata where
+        the formdata is missing field values (usually because we are saving a
+        single field).
+
+        @param exclude: List of field names to exclude.
+        """
+        for name, field in self._fields.items():
+            if name not in exclude:
+                field.data = field.object_data
 
     def cook_json(self, json_reader):
         for field in self._fields.values():
             try:
                 json_reader = field.cook_json(json_reader)
             except AttributeError:
                 # Some fields (eg. SubmitField) don't have a cook json function
                 pass
 
-        cook_files_function = self.config.get_files_cook_function() or cook_files
-        json_reader = cook_files_function(json_reader, self.files)
+        json_reader = cook_files(json_reader, self.files)
 
         return json_reader
 
     def uncook_json(self, json_reader, webdeposit_json, recid=None):
         for field in self._fields.values():
             if hasattr(field, 'uncook_json'):
                 # WTFields are not mapped with rec json
                 webdeposit_json = field.uncook_json(json_reader,
                                                     webdeposit_json)
 
         webdeposit_json = uncook_files(webdeposit_json, recid=recid,
                                        json_reader=json_reader)
         return webdeposit_json
 
     def get_groups(self):
-        groups = [({"name": 'Rest'}, [])]
-        # Just a dict for optimization
-        groups_hash = {}
+        """
+        Get a list of the (group metadata, list of fields)-tuples
+
+        The last element of the list has no group metadata (i.e. None),
+        and contains the list of fields not assigned to any group.
+        """
+        fields_included = set()
+        field_groups = []
+
+        if hasattr(self, 'groups'):
+            for group in self.groups:
+                group_obj = {
+                    'name': group[0],
+                    'meta': CFG_GROUPS_META.copy(),
+                }
+
+                fields = []
+                for field_name in group[1]:
+                    fields.append(self[field_name])
+                    fields_included.add(field_name)
+
+                if len(group) == 3:
+                    group_obj['meta'].update(group[2])
+
+                field_groups.append((group_obj, fields))
+
+        # Append missing fields not defined in groups
+        rest_fields = []
         for field in self:
-            if hasattr(field, 'group') and field.group is not None:
-                if not field.group in groups_hash:
-                    groups_hash[field.group] = len(groups)
-                    # Append group to the list
-                    groups.append(({"name": field.group}, []))
-                # Append field to group's field list
-                groups[groups_hash[field.group]][1].append(field)
-
-                if field.group in self.groups_meta:
-                    # Add group's meta (description etc)
-                    groups[groups_hash[field.group]][0]['meta'] = \
-                        self.groups_meta[field.group]
-            else:
-                # Append to Rest
-                groups[0][1].append(field)
-
-        # Append rest fields in the end
-        rest = groups.pop(0)
-        groups.append(rest)
-        return groups
+            if field.name not in fields_included:
+                rest_fields.append(field)
+        if rest_fields:
+            field_groups.append((None, rest_fields))
+
+        return field_groups
+
+    @property
+    def json_data(self):
+        """
+        Return form data in a format suitable for the standard JSON encoder, by
+        calling Field.json_data() on each field if it exists, otherwise is uses
+        the value of Field.data.
+        """
+        return dict(
+            (name, f.json_data() if getattr(f, 'json_data', None) else f.data)
+            for name, f in self._fields.items()
+        )
+
+    def get_template(self):
+        """
+        Get template to render this form.
+        Define a data member `template` to customize which template to use.
+
+        By default, it will render the template `webdeposit_add.html`
+
+        """
+
+        return [self.template]
+
+    def post_process(self, fields=[], submit=False):
+        """
+        Run form post-processing by calling `post_process` on each field,
+        passing any extra `Form.post_process_<fieldname>` processors to the
+        field.
+
+        If ``fields'' are specified, only the given fields' processors will be
+        run (which may touch all fields of the form).
+
+        The post processing allows the form to alter other fields in the form,
+        via e.g. contacting external services (e.g a DOI field could retrieve
+        title, authors from CrossRef/DataCite).
+        """
+        for name, field, in self._fields.items():
+            if not fields or name in fields:
+                inline = getattr(
+                    self.__class__, 'post_process_%s' % name, None)
+                if inline is not None:
+                    extra = [inline]
+                else:
+                    extra = []
+                field.post_process(self, extra_processors=extra, submit=False)
+
+    def autocomplete(self, field_name, term, limit=50):
+        """
+        Auto complete a form field.
+
+        Assumes that formdata has already been loaded by into the form, so that
+        the search term can be access by field.data.
+        """
+        if field_name in self._fields:
+            return self._fields[field_name].perform_autocomplete(
+                self,
+                term,
+                limit=limit,
+            )[:limit]
+        return []
+
+    @property
+    def messages(self):
+        """
+        Return a dictionary of form messages.
+        """
+        _messages = dict(
+            (
+                name,
+                {
+                    'state': f.message_state
+                             if hasattr(f, 'message_state') and f.message_state
+                             else '',
+                    'messages': f.messages,
+                }
+            ) for name, f in self._fields.items()
+        )
+
+        if self.errors:
+            _messages.update(dict(
+                (
+                    name,
+                    {
+                        'state': 'error',
+                        'messages': messages,
+                    }
+                ) for name, messages in self.errors.items()
+
+            ))
+        return _messages
+
+    @property
+    def flags(self):
+        """
+        Return dictionary of fields and their set flags
+
+        Note only flags from CFG_FIELD_FLAGS that is set to True are returned.
+        """
+        return dict(
+            (
+                name,
+                filter(lambda flag: getattr(f.flags, flag), CFG_FIELD_FLAGS)
+            ) for name, f in self._fields.items()
+        )
diff --git a/modules/webdeposit/lib/webdeposit_load_fields.py b/modules/webdeposit/lib/webdeposit_load_fields.py
index 53c9c9f74..6afb11ba9 100644
--- a/modules/webdeposit/lib/webdeposit_load_fields.py
+++ b/modules/webdeposit/lib/webdeposit_load_fields.py
@@ -1,59 +1,61 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 import os
 from pprint import pformat
 from wtforms import Field
 from invenio.config import CFG_PYLIBDIR, CFG_LOGDIR
 from invenio.pluginutils import PluginContainer
 
 
 def plugin_builder(plugin_name, plugin_code):
     if plugin_name == '__init__':
         return
     try:
+        candidates = []
         all = getattr(plugin_code, '__all__')
         for name in all:
             candidate = getattr(plugin_code, name)
             if issubclass(candidate, Field):
-                return candidate
+                candidates.append(candidate)
+        return candidates
     except AttributeError:
         pass
 
 CFG_FIELDS = PluginContainer(os.path.join(CFG_PYLIBDIR, 'invenio',
                                           'webdeposit_deposition_fields',
                                           '*_field.py'),
                              plugin_builder=plugin_builder)
 
-
 class Fields(object):
     pass
 
 fields = Fields()
 
-for field in CFG_FIELDS.itervalues():
-    ## Change the names of the fields from the file names to the class names.
-    if field is not None:
-        fields.__setattr__(field.__name__, field)
+for field_list in CFG_FIELDS.itervalues():
+    for field in field_list:
+        ## Change the names of the fields from the file names to the class names.
+        if field is not None:
+            fields.__setattr__(field.__name__, field)
 
 ## Let's report about broken plugins
 open(os.path.join(CFG_LOGDIR, 'broken-deposition-fields.log'), 'w').write(
     pformat(CFG_FIELDS.get_broken_plugins()))
 
 __all__ = ['fields']
diff --git a/modules/webdeposit/lib/webdeposit_validation_utils.py b/modules/webdeposit/lib/webdeposit_processor_utils.py
similarity index 52%
copy from modules/webdeposit/lib/webdeposit_validation_utils.py
copy to modules/webdeposit/lib/webdeposit_processor_utils.py
index 6b7e1e67b..343076297 100644
--- a/modules/webdeposit/lib/webdeposit_validation_utils.py
+++ b/modules/webdeposit/lib/webdeposit_processor_utils.py
@@ -1,204 +1,246 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
+# from wtforms.validators import ValidationError, StopValidation, Regexp
+from werkzeug import MultiDict
 from invenio.dataciteutils import DataciteMetadata
 from invenio.sherpa_romeo import SherpaRomeoSearch
 from invenio.bibfield import get_record
-
-#FIXME: make the functions to return functions so that
-#       in the config file we can define parameters
-#       eg. length(5,10)
-
-
-def datacite_doi_validate(field, dummy_form=None):
-    value = field.data
-    if value == "" or value.isspace():
-        return dict()
-    datacite = DataciteMetadata(value)
-    if datacite.error:
-        return dict(info=1, info_message="Couldn't retrieve doi metadata")
-
-    return dict(fields=dict(publisher=datacite.get_publisher(),
-                            title=datacite.get_titles(),
-                            date=datacite.get_dates(),
-                            abstract=datacite.get_description()),
-                success=1,
-                success_message='Datacite.org metadata imported successfully')
-
-
-def sherpa_romeo_issn_validate(field, dummy_form=None):
-    value = field.data
+#
+# General purpose processors
+#
+
+
+def replace_field_data(field_name):
+    """
+    Returns a processor, which will replace the given field names value with
+    the value from the field where the processor is installed.
+    """
+    def _inner(form, field, submit=False):
+        getattr(form, field_name).data = field.data
+    return _inner
+
+#
+# DOI-related processors
+#
+
+
+def datacite_dict_mapper(datacite, form, mapping):
+    """
+    Helper function to map DataCite metadata to form fields based on a mapping
+    """
+    for func_name, field_name in mapping.items():
+        setattr(form, field_name, getattr(datacite, func_name)())
+
+
+class DataCiteLookup(object):
+    """
+    Lookup DOI metadata in DataCite but only if DOI is not locally
+    administered.
+    """
+    def __init__(self, display_info=False, mapping=None,
+                 mapping_func=None, exclude_prefix='10.5072'):
+        self.display_info = display_info
+        self.mapping = mapping or dict(
+            get_publisher='publisher',
+            get_titles='title',
+            get_dates='date',
+            get_description='abstract',
+        )
+        self.mapping_func = mapping_func or datacite_dict_mapper
+        self.prefix = exclude_prefix
+
+    def __call__(self, form, field, submit=False):
+        if not field.errors and field.data and not field.data.startswith(self.prefix + '/'):
+            try:
+                datacite = DataciteMetadata(field.data)
+                if datacite.error:
+                    if self.display_info:
+                        field.add_message('info',
+                                          "DOI metadata could not be retrieved.")
+                    return
+                if self.mapping_func:
+                    self.mapping_func(datacite, form, self.mapping)
+                    if self.display_info:
+                        field.add_message('info',
+                                          "DOI metadata successfully imported from DataCite.")
+            except Exception:
+                # Ignore errors
+                pass
+
+
+datacite_lookup = DataCiteLookup
+
+
+def sherpa_romeo_issn_process(form, field, submit=False):
+    value = field.data or ''
     if value == "" or value.isspace():
         return dict(error=0, error_message='')
     s = SherpaRomeoSearch()
     s.search_issn(value)
     if s.error:
-        return dict(error=1, error_message=s.error_message)
+        field.add_message('info', s.error_message)
+        return
 
     if s.get_num_hits() == 1:
         journal = s.parser.get_journals(attribute='jtitle')
         journal = journal[0]
         publisher = s.parser.get_publishers(journal=journal)
         if publisher is not None and publisher != []:
-            return dict(error=0, error_message='',
-                        fields=dict(journal=journal,
-                                    publisher=publisher['name']))
+            if hasattr(form, 'journal'):
+                form.journal.data = journal
+
+            if hasattr(form, 'publisher'):
+                form.publisher.data = publisher['name']
+            return
         else:
-            return dict(error=0, error_message='',
-                        fields=dict(journal=journal))
+            if hasattr(form, 'journal'):
+                form.journal.data = journal
+            return
 
-    return dict(info=1, info_message="Couldn't find Journal")
+    field.add_message('info', "Couldn't find Journal.")
 
 
-def sherpa_romeo_publisher_validate(field, dummy_form=None):
-    value = field.data
+def sherpa_romeo_publisher_process(form, field, submit=False):
+    value = field.data or ''
     if value == "" or value.isspace():
-        return dict(error=0, error_message='')
+        return
     s = SherpaRomeoSearch()
     s.search_publisher(value)
     if s.error:
-        return dict(info=1, info_message=s.error_message)
+        field.add_message('info', s.error_message)
 
     conditions = s.parser.get_publishers(attribute='conditions')
     if conditions is not None and s.get_num_hits() == 1:
         conditions = conditions[0]
     else:
         conditions = []
     if conditions != []:
         conditions_html = "<u>Conditions</u><br><ol>"
         if isinstance(conditions['condition'], str):
             conditions_html += "<li>" + conditions['condition'] + "</li>"
         else:
             for condition in conditions['condition']:
                 conditions_html += "<li>" + condition + "</li>"
 
         copyright_links = s.parser.get_publishers(attribute='copyrightlinks')
         if copyright_links is not None and copyright_links != []:
             copyright_links = copyright_links[0]
         else:
             copyright_links = None
 
         if isinstance(copyright_links, list):
             copyright_links_html = ""
             for copyright_link in copyright_links['copyrightlink']:
                 copyright_links_html += '<a href="' + copyright_link['copyrightlinkurl'] + \
                                         '">' + copyright_link['copyrightlinktext'] + "</a><br>"
         elif isinstance(copyright_links, dict):
             if isinstance(copyright_links['copyrightlink'], list):
                 for copyright_link in copyright_links['copyrightlink']:
                     copyright_links_html = '<a href="' + copyright_link['copyrightlinkurl'] + \
                                            '">' + copyright_link['copyrightlinktext'] + "</a><br>"
             else:
                 copyright_link = copyright_links['copyrightlink']
                 copyright_links_html = '<a href="' + copyright_link['copyrightlinkurl'] + \
                                        '">' + copyright_link['copyrightlinktext'] + "</a><br>"
 
         home_url = s.parser.get_publishers(attribute='homeurl')
         if home_url is not None and home_url != []:
             home_url = home_url[0]
             home_url = '<a href="' + home_url + '">' + home_url + "</a>"
         else:
             home_url = None
 
         info_html = ""
         if home_url is not None:
             info_html += "<p>" + home_url + "</p>"
 
         if conditions is not None:
             info_html += "<p>" + conditions_html + "</p>"
 
         if copyright_links is not None:
             info_html += "<p>" + copyright_links_html + "</p>"
 
         if info_html != "":
-            return dict(error=0, error_message='',
-                        info=1, info_message=info_html)
-    return dict(error=0, error_message='')
+            field.add_message('info', info_html)
 
 
-def sherpa_romeo_journal_validate(field, dummy_form=None):
-    value = field.data
+def sherpa_romeo_journal_process(form, field, submit=False):
+    value = field.data or ''
     if value == "" or value.isspace():
-        return dict(error=0, error_message='')
+        return
 
     s = SherpaRomeoSearch()
     s.search_journal(value, 'exact')
     if s.error:
-        return dict(info=1, info_message=s.error_message)
+        field.add_message('info',  s.error_message)
+        return
 
     if s.get_num_hits() == 1:
         issn = s.parser.get_journals(attribute='issn')
         if issn != [] and issn is not None:
             issn = issn[0]
             publisher = s.parser.get_publishers(journal=value)
             if publisher is not None and publisher != []:
-                return dict(error=0, error_message='',
-                            fields=dict(issn=issn,
-                                        publisher=publisher['name']))
-            return dict(error=0, error_message='',
-                        info=1, info_message="Journal's Publisher not found",
-                        fields=dict(publisher="", issn=issn))
+                if hasattr(form, 'issn'):
+                    form.issn.data = issn
+
+                if hasattr(form, 'publisher'):
+                    form.publisher.data = publisher['name']
+                    form.publisher.post_process(form)
+                return
+
+            field.add_message('info', "Journal's Publisher not found")
+            if hasattr(form, 'issn'):
+                form.issn.data = issn
+            if hasattr(form, 'publisher'):
+                form.publisher.data = publisher
+                form.publisher.post_process(form)
         else:
-            return dict(info=1, info_message="Couldn't find ISSN")
-    return dict(error=0, error_message='')
+            field.add_message('info', "Couldn't find ISSN.")
 
 
-def number_validate(field, dummy_form=None, error_message='It must be a number!'):
-    value = field.data
+def record_id_process(form, field, submit=False):
+    value = field.data or ''
     if value == "" or value.isspace():
-        return dict(error=0, error_message='')
+        return
 
     def is_number(s):
         try:
             float(s)
             return True
         except ValueError:
             return False
 
-    if not is_number(value):
-        try:
-            field.errors.append(error_message)
-        except AttributeError:
-            field.errors = list(field.process_errors)
-            field.errors.append(error_message)
-        return dict(error=1,
-                    error_message=error_message)
-    else:
-        return dict(error=0, error_message='')
-
-
-def record_id_validate(field, form=None):
-    value = field.data
-    is_number = number_validate(field)['error'] == 0 \
-        and (value != "" or not value.isspace())
-
-    if is_number:
+    if is_number(field.data):
         json_reader = get_record(value)
     else:
-        return dict(error=1, error_message="Record id must be a number!")
+        field.add_message('error', "Record id must be a number!")
+        return
+
     if json_reader is not None:
         webdeposit_json = form.uncook_json(json_reader, {}, value)
-        #FIXME: update current json
+        #FIXME: update current json, past self, what do you mean?? :S
+
+        field.add_message('info', '<a href="/record/"' + value +
+                                 '>Record</a> was loaded successfully')
 
-        return dict(info=1,
-                    info_message='<a href="/record/"' + value +
-                                 '>Record</a> loaded successfully',
-                    fields=webdeposit_json)
+        form.process(MultiDict(webdeposit_json))
     else:
-        return dict(info=1, info_message="Record doesn't exist")
+        field.add_message('info', "Record doesn't exist")
diff --git a/modules/webdeposit/lib/webdeposit_regression_tests.py b/modules/webdeposit/lib/webdeposit_regression_tests.py
index e0934da7f..28675ac0d 100644
--- a/modules/webdeposit/lib/webdeposit_regression_tests.py
+++ b/modules/webdeposit/lib/webdeposit_regression_tests.py
@@ -1,219 +1,309 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from invenio.testutils import make_test_suite, run_test_suite, InvenioTestCase
 
 
 class TestWebDepositUtils(InvenioTestCase):
 
     def clear_tables(self):
         from invenio.bibworkflow_model import Workflow, WfeObject
-        from invenio.webdeposit_model import WebDepositDraft
         from invenio.sqlalchemyutils import db
 
         Workflow.query.delete()
         WfeObject.query.delete()
-        WebDepositDraft.query.delete()
         db.session.commit()
 
     def setUp(self):
         self.clear_tables()
         super(TestWebDepositUtils, self).setUp()
 
     def tearDown(self):
         self.clear_tables()
         super(TestWebDepositUtils, self).tearDown()
 
     def test_workflow_creation(self):
         from invenio.webdeposit_load_deposition_types import \
             deposition_metadata
         from invenio.bibworkflow_model import Workflow
         from invenio.webdeposit_workflow import DepositionWorkflow
         from invenio.webdeposit_utils import get_latest_or_new_workflow, \
             get_workflow, delete_workflow
         from invenio.sqlalchemyutils import db
         from invenio.webuser_flask import login_user
 
         login_user(1)
 
         number_of_dep_types = len(deposition_metadata)
         # Test for every deposition type
         for deposition_type in deposition_metadata.keys():
             # New workflow is created
             workflow = get_latest_or_new_workflow(deposition_type, user_id=1)
             assert workflow is not None
 
             # The just created workflow is retrieved as latest
             workflow2 = get_latest_or_new_workflow(deposition_type, user_id=1)
             assert workflow2 is not None
             assert str(workflow2.uuid) == str(workflow.uuid)
 
             # and also retrieved with its uuid
-            workflow = get_workflow(deposition_type, workflow.uuid)
+            workflow = get_workflow(workflow.uuid, deposition_type)
             assert workflow is not None
 
         # Test get_workflow function with random arguments
-        workflow = get_workflow('deposition_type_that_doesnt_exist',
-                                'some_uuid')
+        workflow = get_workflow('some_uuid',
+                                'deposition_type_that_doesnt_exist')
         assert workflow is None
 
         deposition_type = deposition_metadata.keys()[-1]
-        workflow = get_workflow(deposition_type,
-                                'some_uuid_that_doesnt_exist')
+        workflow = get_workflow('some_uuid_that_doesnt_exist', deposition_type)
         assert workflow is None
 
         # Create workflow without using webdeposit_utils
         wf = deposition_metadata[deposition_type]["workflow"]
         workflow = DepositionWorkflow(deposition_type=deposition_type,
                                       workflow=wf, user_id=1)
 
         # Test that the retrieved workflow is the same and not None
-        workflow2 = get_workflow(deposition_type, workflow.get_uuid())
+        workflow2 = get_workflow(workflow.get_uuid(), deposition_type)
         assert workflow2 is not None
         assert workflow2.get_uuid() == workflow.get_uuid()
 
         # Check the number of created workflows
         workflows = db.session.query(Workflow).all()
         assert len(workflows) == number_of_dep_types + 1
 
         uuid = workflow.get_uuid()
         delete_workflow(1, uuid)
-        workflow = get_workflow(deposition_type, uuid)
+        workflow = get_workflow(uuid, deposition_type)
         assert workflow is None
 
     def test_form_functions(self):
         from invenio.webdeposit_load_deposition_types import \
             deposition_metadata
         from invenio.webdeposit_load_forms import forms
-        from invenio.webdeposit_model import WebDepositDraft
         from invenio.webdeposit_workflow import DepositionWorkflow
-        from invenio.webdeposit_utils import get_current_form, get_form, \
-            get_form_status, CFG_DRAFT_STATUS
-        from invenio.sqlalchemyutils import db
+        from invenio.webdeposit_utils import get_form, \
+            get_form_status, set_form_status, CFG_DRAFT_STATUS
+        from invenio.bibworkflow_model import Workflow
         from invenio.webdeposit_workflow_utils import render_form, \
             wait_for_submission
         from invenio.cache import cache
 
         for metadata in deposition_metadata.values():
             for wf_function in metadata['workflow']:
                 if 'render_form' == wf_function.func_name:
                     break
 
         from invenio.webuser_flask import login_user
         login_user(1)
 
-
         wf = [render_form(forms.values()[0]),
               wait_for_submission()]
         deposition_workflow = DepositionWorkflow(deposition_type='TestWorkflow',
                                                  workflow=wf, user_id=1)
 
         uuid = deposition_workflow.get_uuid()
         cache.delete_many("1:current_deposition_type", "1:current_uuid")
         cache.add("1:current_deposition_type", 'TestWorkflow')
         cache.add("1:current_uuid", uuid)
 
         # Run the workflow to insert a form to the db
         deposition_workflow.run()
 
         # There is only one form in the db
-        drafts = db.session.query(WebDepositDraft)
-        assert len(drafts.all()) == 1
-
+        workflows = Workflow.get(module_name='webdeposit')
+        assert len(workflows.all()) == 1
+        assert len(workflows[0].extra_data['drafts']) == 1
 
         # Test that guest user doesn't have access to the form
-        uuid, form = get_current_form(0, deposition_type='TestWorkflow',
-                                      uuid=uuid)
+        form = get_form(0, uuid=uuid)
         assert form is None
 
         # Test that the current form has the right type
-        uuid, form = get_current_form(1, deposition_type='TestWorkflow',
-                                      uuid=deposition_workflow.get_uuid())
+        form = get_form(1, uuid=deposition_workflow.get_uuid())
         assert isinstance(form, forms.values()[0])
         assert str(uuid) == str(deposition_workflow.get_uuid())
 
         # Test that form is returned with get_form function
         form = get_form(1, deposition_workflow.get_uuid())
         assert form is not None
 
         form = get_form(1, deposition_workflow.get_uuid(), step=0)
         assert form is not None
 
         # Second step doesn't have a form
         form = get_form(1, deposition_workflow.get_uuid(), step=1)
         assert form is None
 
         form_status = get_form_status(1, deposition_workflow.get_uuid())
         assert form_status == CFG_DRAFT_STATUS['unfinished']
 
         form_status = get_form_status(1, deposition_workflow.get_uuid(),
                                       step=2)
         assert form_status is None
 
-        db.session.query(WebDepositDraft).\
-            update({'status': CFG_DRAFT_STATUS['finished']})
-
+        set_form_status(1, uuid, CFG_DRAFT_STATUS['finished'])
         form_status = get_form_status(1, deposition_workflow.get_uuid())
         assert form_status == CFG_DRAFT_STATUS['finished']
 
     def test_field_functions(self):
         from datetime import datetime
         from invenio.sqlalchemyutils import db
         from invenio.webdeposit_workflow import DepositionWorkflow
         from invenio.webdeposit_model import WebDepositDraft
         from invenio.webdeposit_workflow_utils import render_form
         from invenio.webdeposit_utils import draft_field_get
         from invenio.webdeposit_deposition_forms.article_form import ArticleForm
         from invenio.cache import cache
 
-
         wf = [render_form(ArticleForm)]
         user_id = 1
 
         workflow = DepositionWorkflow(workflow=wf,
                                       deposition_type='TestWorkflow',
                                       user_id=user_id)
 
         cache.delete_many("1:current_deposition_type", "1:current_uuid")
         cache.add("1:current_deposition_type", 'TestWorkflow')
         cache.add("1:current_uuid", workflow.get_uuid())
 
         workflow.run()  # Insert a form
         uuid = workflow.get_uuid()
 
         # Test for a field that's not there
         value = draft_field_get(user_id, uuid, 'field_that_doesnt_exist')
         assert value is None
 
         # Test for a field that hasn't been inserted in db yet
         value = draft_field_get(user_id, uuid, 'publisher')
         assert value is None
 
         values = {'publisher': 'Test Publishers Association'}
 
         db.session.query(WebDepositDraft).\
             filter(WebDepositDraft.uuid == uuid,
                    WebDepositDraft.step == 0).\
             update({"form_values": values,
                     "timestamp": datetime.now()})
 
+    def test_record_creation(self):
+        import os
+        from wtforms import TextAreaField
+        from datetime import datetime
+
+        from invenio.search_engine import record_exists
+        from invenio.cache import cache
+        from invenio.config import CFG_PREFIX
+        from invenio.webuser_flask import login_user
+        from invenio.bibworkflow_model import Workflow
+        from invenio.bibworkflow_config import CFG_WORKFLOW_STATUS
+        from invenio.bibsched_model import SchTASK
+
+        from invenio.webdeposit_utils import get_form, create_workflow, \
+            set_form_status, CFG_DRAFT_STATUS
+        from invenio.webdeposit_load_deposition_types import \
+            deposition_metadata
+        from invenio.webdeposit_workflow_utils import \
+            create_record_from_marc
+        from invenio.bibfield import get_record
+
+        login_user(1)
+        for deposition_type in deposition_metadata.keys():
+
+            deposition = create_workflow(deposition_type, 1)
+            assert deposition is not None
+
+            # Check if deposition creates a record
+            create_rec = create_record_from_marc()
+            function_exists = False
+            for workflow_function in deposition.workflow:
+                if create_rec.func_code == workflow_function .func_code:
+                    function_exists = True
+            if not function_exists:
+                # if a record is not created,
+                #continue with the next deposition
+                continue
+
+            uuid = deposition.get_uuid()
+
+            cache.delete_many("1:current_deposition_type", "1:current_uuid")
+            cache.add("1:current_deposition_type", deposition_type)
+            cache.add("1:current_uuid", uuid)
+
+            # Run the workflow
+            deposition.run()
+
+            # Create form's json based on the field name
+            form = get_form(1, uuid=uuid)
+            webdeposit_json = {}
+
+            # Fill the json with dummy data
+            for field in form:
+                if isinstance(field, TextAreaField):
+                    # If the field is associated with a marc field
+                    if field.has_recjson_key() or field.has_cook_function():
+                        webdeposit_json[field.name] = "test " + field.name
+
+            draft = dict(form_type=form.__class__.__name__,
+                         form_values=webdeposit_json,
+                         step=0,  # dummy step
+                         status=CFG_DRAFT_STATUS['finished'],
+                         timestamp=str(datetime.now()))
+
+            # Add a draft for the first step
+            Workflow.set_extra_data(user_id=1, uuid=uuid,
+                                    key='drafts', value={0: draft})
+
+            workflow_status = CFG_WORKFLOW_STATUS.RUNNING
+            while workflow_status != CFG_WORKFLOW_STATUS.FINISHED:
+                # Continue workflow
+                deposition.run()
+                set_form_status(1, uuid, CFG_WORKFLOW_STATUS.FINISHED)
+                workflow_status = deposition.get_status()
+
+            # Workflow is finished. Test if record is created
+            recid = deposition.get_data('recid')
+            assert recid is not None
+            # Test that record id exists
+            assert record_exists(recid) == 1
+
+            # Test that the task exists
+            task_id = deposition.get_data('task_id')
+            assert task_id is not None
+
+            bibtask = SchTASK.query.filter(SchTASK.id == task_id).first()
+            assert bibtask is not None
+
+            # Run bibupload, bibindex, webcoll manually
+            cmd = "%s/bin/bibupload %s" % (CFG_PREFIX, task_id)
+            assert not os.system(cmd)
+            rec = get_record(recid)
+            marc = rec.legacy_export_as_marc()
+            for field in form:
+                if isinstance(field, TextAreaField):
+                    # If the field is associated with a marc field
+                    if field.has_recjson_key() or field.has_cook_function():
+                        assert "test " + field.name in marc
+
+
 TEST_SUITE = make_test_suite(TestWebDepositUtils)
 
 if __name__ == "__main__":
     run_test_suite(TEST_SUITE)
diff --git a/modules/webdeposit/lib/webdeposit_templates.js b/modules/webdeposit/lib/webdeposit_templates.js
new file mode 100644
index 000000000..eed1c4e79
--- /dev/null
+++ b/modules/webdeposit/lib/webdeposit_templates.js
@@ -0,0 +1,13 @@
+var tpl_webdeposit_status_saved = Hogan.compile('Saved <i class="icon-ok"></i>');
+var tpl_webdeposit_status_saved_with_errors = Hogan.compile('<span class="text-warning">Saved, but with errors <i class="icon-warning-sign"></i></span>');
+var tpl_webdeposit_status_saving = Hogan.compile('Saving <img src="/css/images/ajax-loader.gif" />');
+var tpl_webdeposit_status_error = Hogan.compile('<span class="text-error">Not saved due to server error. Please try to reload your browser <i class="icon-warning-sign"></i></span>');
+var tpl_field_message = Hogan.compile('{{#messages}}<div>{{{.}}}</div>{{/messages}}');
+var tpl_required_field_message = Hogan.compile('{{{label}}} is required.');
+var tpl_flash_message = Hogan.compile('<div class="alert alert-{{state}}"><a class="close" data-dismiss="alert" href="#"">&times;</a>{{{message}}}</div>');
+var tpl_message_success = Hogan.compile('Successfully saved.');
+var tpl_message_errors = Hogan.compile('The form was saved, but there were errors. Please see below.');
+var tpl_message_server_error = Hogan.compile('The form could not be saved, due to a communication problem with the server. Please try to reload your browser <i class="icon-warning-sign"></i>');
+var tpl_loader = Hogan.compile('<img src="/css/images/ajax-loader.gif" />');
+var tpl_loader_success = Hogan.compile('<span class="text-success"> <i class="icon-ok"></i></span>');
+var tpl_loader_failed = Hogan.compile('<span class="muted"> <i class="icon-warning-sign"></i></span>');
diff --git a/modules/webdeposit/lib/webdeposit_utils.py b/modules/webdeposit/lib/webdeposit_utils.py
index 6912076c5..ab27f6b36 100644
--- a/modules/webdeposit/lib/webdeposit_utils.py
+++ b/modules/webdeposit/lib/webdeposit_utils.py
@@ -1,623 +1,852 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
+""" WebDeposit Utils
+Set of utilities to be used by blueprint, forms and fields.
+
+It contains functions to start a workflow, retrieve it and edit its data.
+The basic entities are the forms and fields which are stored in json.
+(forms are referred as drafts before they haven't been submitted yet.)
+
+The file field is handled separately and all the files are attached in the json
+as a list in the 'files' key.
+
+Some functions contain the keyword `preingest`. This refers to the json that is
+stored in the 'pop_obj' key, which is used to store data before running the
+workflow. This is being used e.g. in the wedbeposit api where the workflow is
+being run without a user submitting the forms, so this json is being used to
+preinsert data into the webdeposit workflow.
+"""
+
+
 import os
+import shutil
+from flask import request
+from glob import iglob
+from werkzeug.utils import secure_filename
+from werkzeug.exceptions import BadRequestKeyError
+from werkzeug import MultiDict
 from datetime import datetime
-from sqlalchemy import desc
-from wtforms import FormField
 from sqlalchemy.orm.exc import NoResultFound
 from uuid import uuid1 as new_uuid
 from urllib2 import urlopen, URLError
 
+from invenio.cache import cache
 from invenio.sqlalchemyutils import db
 from invenio.webdeposit_model import WebDepositDraft
 from invenio.bibworkflow_model import Workflow
 from invenio.bibworkflow_config import CFG_WORKFLOW_STATUS
 from invenio.webdeposit_load_forms import forms
+from invenio.webdeposit_form import CFG_FIELD_FLAGS
 from invenio.webuser_flask import current_user
 from invenio.webdeposit_load_deposition_types import deposition_metadata
 from invenio.webdeposit_workflow import DepositionWorkflow
+from invenio.webdeposit_workflow_utils import render_form
 from invenio.config import CFG_WEBDEPOSIT_UPLOAD_FOLDER
 
-""" Deposition Type Functions """
-
 
 CFG_DRAFT_STATUS = {
     'unfinished': 0,
     'finished': 1
 }
 
 
+#
+# Setters/Getters for bibworklflow
+#
+
+def draft_getter(step=None):
+    """Returns a json with the current form values.
+    If step is None, the latest draft is returned."""
+    def draft_getter_func(json):
+        try:
+            if step is None:
+                return json['drafts'][max(json['drafts'])]
+            else:
+                try:
+                    return json['drafts'][step]
+                except KeyError:
+                    pass
+
+                try:
+                    return json['drafts'][unicode(step)]
+                except KeyError:
+                    pass
+                raise NoResultFound
+        except KeyError:
+            try:
+                return {'timestamp': json['pop_obj']['timestamp']}
+            except KeyError:
+                # there is no pop object
+                return None
+    return draft_getter_func
+
+
+def draft_setter(step=None, key=None, value=None, data=None, field_setter=False):
+    """Alters a draft's specified value.
+    If the field_setter is true, it uses the key value to update
+    the dictionary `form_values` otherwise it updates the draft."""
+    def draft_setter_func(json):
+        try:
+            if step is None:
+                draft = json['drafts'][max(json['drafts'])]
+            else:
+                draft = json['drafts'][step]
+        except (ValueError, KeyError):
+            # There are no drafts or they are empty
+            return
+
+        if key:
+            if field_setter:
+                draft['form_values'][key] = value
+            else:
+                draft[key] = value
+
+        if data:
+            if field_setter:
+                draft['form_values'].update(data)
+            else:
+                draft.update(data)
+
+        draft['timestamp'] = str(datetime.now())
+    return draft_setter_func
+
+
+def add_draft(draft):
+    """ Adds a form draft. """
+    def setter(json):
+        step = draft.pop('step')
+        if not 'drafts' in json:
+            json['drafts'] = {}
+        if not step in json['drafts'] and \
+           not unicode(step) in json['drafts']:
+            json['drafts'][step] = draft
+    return setter
+
+
+def draft_field_list_setter(field_name, value):
+    def setter(json):
+        try:
+            draft = json['drafts'][max(json['drafts'])]
+        except (ValueError, KeyError):
+            # There are no drafts or they are empty
+            return
+        values = draft['form_values']
+        try:
+            if isinstance(values[field_name], list):
+                values[field_name].append(value)
+            else:
+                new_values_list = [values[field_name]]
+                new_values_list.append(value)
+                values[field_name] = new_values_list
+        except KeyError:
+            values[field_name] = [value]
+
+        draft['timestamp'] = str(datetime.now())
+    return setter
+
+
+#
+# Workflow functions
+#
+
 def get_latest_or_new_workflow(deposition_type, user_id=None):
     """ Creates new workflow or returns a new one """
 
     user_id = user_id or current_user.get_id()
     wf = deposition_metadata[deposition_type]["workflow"]
 
     # get latest draft in order to get workflow's uuid
-    latest_workflow = db.session.query(Workflow).\
-        filter(
+    try:
+        latest_workflow = Workflow.get_most_recent(
             Workflow.user_id == user_id,
             Workflow.name == deposition_type,
             Workflow.module_name == 'webdeposit',
-            Workflow.status != CFG_WORKFLOW_STATUS.FINISHED).\
-        order_by(db.desc(Workflow.modified)).\
-        first()
-
-    if latest_workflow is None:
+            Workflow.status != CFG_WORKFLOW_STATUS.FINISHED)
+    except NoResultFound:
         # We didn't find other workflows
         # Let's create a new one
         return DepositionWorkflow(deposition_type=deposition_type,
                                   workflow=wf)
 
     # Create a new workflow
     # based on the latest draft's uuid
-    uuid = latest_workflow .uuid
+    uuid = latest_workflow. uuid
     return DepositionWorkflow(deposition_type=deposition_type,
                               workflow=wf, uuid=uuid)
 
 
-def get_workflow(deposition_type, uuid):
+def get_workflow(uuid, deposition_type=None):
     """ Returns a workflow instance with uuid=uuid or None """
+
+    # Check if uuid exists first and get the deposition_type if None
+    try:
+        workflow = Workflow.get(uuid=uuid).one()
+        if deposition_type is None:
+            deposition_type = workflow.name
+    except NoResultFound:
+        return None
+
     try:
         wf = deposition_metadata[deposition_type]["workflow"]
     except KeyError:
         # deposition type not found
         return None
-    # Check if uuid exists first
-    try:
-        db.session.query(Workflow). \
-            filter_by(uuid=uuid).one()
-    except NoResultFound:
-        return None
     return DepositionWorkflow(uuid=uuid,
                               deposition_type=deposition_type,
                               workflow=wf)
 
 
 def create_workflow(deposition_type, user_id=None):
     """ Creates a new workflow and returns it """
     try:
         wf = deposition_metadata[deposition_type]["workflow"]
     except KeyError:
         # deposition type not found
         return None
 
     return DepositionWorkflow(deposition_type=deposition_type,
                               workflow=wf, user_id=user_id)
 
 
-def delete_workflow(user_id, uuid):
+def delete_workflow(dummy_user_id, uuid):
     """ Deletes all workflow related data
         (workflow and drafts)
     """
+    Workflow.delete(uuid=uuid)
 
-    db.session.query(Workflow). \
-        filter_by(uuid=uuid,
-                  user_id=user_id). \
-        delete()
-
-    db.session.query(WebDepositDraft). \
-        filter_by(uuid=uuid).\
-        delete()
-    db.session.commit()
 
-
-def get_current_form(user_id, deposition_type=None, uuid=None):
-    """Returns the latest draft(wtform object) of the deposition_type
-    or the form with the specific uuid.
-    if it doesn't exist, creates a new one
+#
+# Form loading and saving functions
+#
+def get_form(user_id, uuid, step=None, formdata=None, load_draft=True,
+             validate_draft=False):
     """
+    Returns the current state of the workflow in a form or a previous
+    state (step)
 
-    if user_id is None:
-        return None
+    @param user_id:
 
-    try:
-        if uuid is not None:
-            webdeposit_draft_query = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == user_id,
-                       WebDepositDraft.uuid == uuid)
-            # get the draft with the max step, the latest
-            try:
-                webdeposit_draft = max(webdeposit_draft_query.all(),
-                                       key=lambda w: w.step)
-            except ValueError:
-                # No drafts found
-                raise NoResultFound
-        elif deposition_type is not None:
-            webdeposit_draft = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == user_id,
-                       Workflow.name == deposition_type,
-                       WebDepositDraft.timestamp == db.func.max(
-                       WebDepositDraft.timestamp).select())[0]
-        else:
-            webdeposit_draft = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == user_id,
-                       WebDepositDraft.timestamp == db.func.max(
-                       WebDepositDraft.timestamp).select())[0]
-    except NoResultFound:
-        # No Form draft was found
-        return None, None
-
-    form = forms[webdeposit_draft.form_type]()
-    draft_data = webdeposit_draft.form_values
-
-    for field_name in form.data.keys():
-        if isinstance(form._fields[field_name], FormField) \
-                and field_name in draft_data:
-            subfield_names = \
-                form._fields[field_name]. \
-                form._fields.keys()
-            #upperfield_name, subfield_name = field_name.split('-')
-            for subfield_name in subfield_names:
-                if subfield_name in draft_data[field_name]:
-                    form._fields[field_name].\
-                        form._fields[subfield_name]. \
-                        process_data(draft_data[field_name][subfield_name])
-        elif field_name in draft_data:
-            form[field_name].process_data(draft_data[field_name])
-
-    return webdeposit_draft.uuid, form
-
-
-def get_form(user_id, uuid, step=None):
-    """ Returns the current state of the workflow in a form
-        or a previous state (step)
-    """
+    @param uuid:
 
-    #FIXME: merge with get_current_form
+    @param step:
 
-    if step is None:
-        webdeposit_draft_query = \
-            db.session.query(WebDepositDraft).\
-            join(Workflow).\
-            filter(Workflow.user_id == user_id,
-                   WebDepositDraft.uuid == uuid)
-        try:
-            # get the draft with the max step
-            webdeposit_draft = max(webdeposit_draft_query.all(),
-                                   key=lambda w: w.step)
-        except ValueError:
-            return None
-    else:
+    @param formdata:
+        Dictionary of formdata.
+    @param validate_draft:
+        If draft data exists, and no formdata is provided, the form will be
+        validated if this parameter is set to true.
+    """
+    # Get draft data
+    if load_draft:
         try:
+
             webdeposit_draft = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == user_id,
-                       WebDepositDraft.uuid == uuid,
-                       WebDepositDraft.step == step).one()
-        except NoResultFound:
+                Workflow.get_extra_data(user_id=user_id,
+                                        uuid=uuid,
+                                        getter=draft_getter(step))
+        except (ValueError, NoResultFound):
+            # No drafts found
             return None
 
-    form = forms[webdeposit_draft.form_type]()
-
-    draft_data = webdeposit_draft.form_values
-
-    for field_name in form.data.keys():
-        if isinstance(form._fields[field_name], FormField) \
-                and field_name in draft_data:
-            subfield_names = \
-                form._fields[field_name].\
-                form.fields.keys()
-            #upperfield_name, subfield_name = field_name.split('-')
-            for subfield_name in subfield_names:
-                if subfield_name in draft_data[field_name]:
-                    form._fields[field_name].\
-                        form._fields[subfield_name].\
-                        process_data(draft_data[field_name][subfield_name])
-        elif field_name in draft_data:
-            form[field_name].process_data(draft_data[field_name])
-
+    # If a field is not present in formdata, Form.process() will assume it is
+    # blank instead of using the draft_data value. Most of the time we are only
+    # submitting a single field in JSON via AJAX requests. We therefore reset
+    # non-submitted fields to the draft_data value.
+    draft_data = webdeposit_draft['form_values'] if load_draft else {}
+    if formdata:
+        formdata = MultiDict(formdata)
+    form = forms[webdeposit_draft['form_type']](formdata=formdata, **draft_data)
+    if formdata:
+        form.reset_field_data(exclude=formdata.keys())
+
+    # Set field flags
+    if load_draft:
+        for name, flags in webdeposit_draft.get('form_field_flags', {}).items():
+            for check_flags in CFG_FIELD_FLAGS:
+                if check_flags in flags:
+                    setattr(form[name].flags, check_flags, True)
+                else:
+                    setattr(form[name].flags, check_flags, False)
+
+    # Process files
     if 'files' in draft_data:
         # FIXME: sql alchemy(0.8.0) returns the value from the
         #        column form_values with keys and values in unicode.
         #        This creates problem when the dict is rendered
         #        in the page to be used by javascript functions. There must
         #        be a more elegant way than decoding the dict from unicode.
 
         draft_data['files'] = decode_dict_from_unicode(draft_data['files'])
         for file_metadata in draft_data['files']:
             # Replace the path with the unique filename
             if isinstance(file_metadata, basestring):
                 import json
                 file_metadata = json.loads(file_metadata)
             filepath = file_metadata['file'].split('/')
             unique_filename = filepath[-1]
             file_metadata['unique_filename'] = unique_filename
         form.__setattr__('files', draft_data['files'])
     else:
         form.__setattr__('files', {})
+
+    if validate_draft and draft_data and formdata is None:
+        form.validate()
+
     return form
 
 
-def get_form_status(user_id, uuid, step=None):
-    if step is None:
-        webdeposit_draft_query = \
-            db.session.query(WebDepositDraft).\
-            join(Workflow).\
-            filter(Workflow.user_id == user_id,
-                   WebDepositDraft.uuid == uuid)
-        try:
-            # get the draft with the max step
-            webdeposit_draft = max(webdeposit_draft_query.all(),
-                                   key=lambda w: w.step)
-        except ValueError:
-            return None
-    else:
-        try:
-            webdeposit_draft = \
-                db.session.query(WebDepositDraft).\
-                join(Workflow).\
-                filter(Workflow.user_id == user_id,
-                       WebDepositDraft.uuid == uuid,
-                       WebDepositDraft.step == step).one()
-        except NoResultFound:
-            return None
+def save_form(user_id, uuid, form):
+    """
+    Saves the draft form_values and form_field_flags of a form.
+    """
+    json_data = dict((key, value) for key, value in form.json_data.items()
+                if value is not None)
 
-    return webdeposit_draft.status
+    draft_data_update = {
+        'form_values': json_data,
+        'form_field_flags': form.flags,
+    }
 
+    Workflow.set_extra_data(
+        user_id=user_id,
+        uuid=uuid,
+        setter=draft_setter(data=draft_data_update)
+    )
 
-def set_form_status(user_id, uuid, status, step=None):
-    if step is None:
-        webdeposit_draft_query = \
-            db.session.query(WebDepositDraft).\
-            join(Workflow).\
-            filter(Workflow.user_id == user_id,
-                   WebDepositDraft.uuid == uuid)
-        try:
-            # get the draft with the max step
-            webdeposit_draft = max(webdeposit_draft_query.all(),
-                                   key=lambda w: w.step)
-        except ValueError:
-            return None
-    else:
+
+def get_form_status(user_id, uuid, step=None):
+    try:
         webdeposit_draft = \
-            db.session.query(WebDepositDraft).\
-            join(Workflow).\
-            filter(Workflow.user_id == user_id,
-                   WebDepositDraft.uuid == uuid,
-                   WebDepositDraft.step == step).one()
+            Workflow.get_extra_data(user_id=user_id,
+                                    uuid=uuid,
+                                    getter=draft_getter(step))
+    except ValueError:
+        # No drafts found
+        raise NoResultFound
+    except NoResultFound:
+        return None
+
+    return webdeposit_draft['status']
+
 
-    webdeposit_draft.status = status
-    db.session.commit()
+def set_form_status(user_id, uuid, status, step=None):
+    try:
+        Workflow.set_extra_data(user_id=user_id,
+                                uuid=uuid,
+                                setter=draft_setter(step, 'status', status))
+    except ValueError:
+        # No drafts found
+        raise NoResultFound
+    except NoResultFound:
+        return None
 
 
 def get_last_step(steps):
     if type(steps[-1]) is list:
         return get_last_step[-1]
     else:
         return steps[-1]
 
 
 def get_current_step(uuid):
-    webdep_workflow = \
-        db.session.query(Workflow). \
-        filter(Workflow.uuid == uuid). \
-        one()
+    webdep_workflow = Workflow.get(Workflow.uuid == uuid).one()
     steps = webdep_workflow.task_counter
 
     return get_last_step(steps)
 
 
 """ Draft Functions (or instances of forms)
-old implementation with redis cache of the functions is provided in comments
-(works only in the article form, needs to be generic)
 """
 
 
 def draft_field_get(user_id, uuid, field_name, subfield_name=None):
     """ Returns the value of a field
         or, in case of error, None
     """
 
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft).\
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               WebDepositDraft.uuid == uuid)
-    # get the draft with the max step
-    draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
-
-    values = draft.form_values
+    values = \
+        Workflow.get_extra_data(user_id=user_id, uuid=uuid,
+                                getter=draft_getter())['form_values']
 
     try:
         if subfield_name is not None:
             return values[field_name][subfield_name]
         return values[field_name]
     except KeyError:
         return None
 
 
-def draft_field_error_check(user_id, uuid, field_name, value):
-    """ Retrieves the form based on the uuid
-        and returns a json string evaluating the field's value
+def draft_form_autocomplete(form_type, field_name, term, limit):
     """
+    Auto-complete field value
+    """
+    try:
+        form = forms[form_type]()
+        return form.autocomplete(field_name, term, limit=limit)
+    except KeyError:
+        return []
 
-    form = get_form(user_id, uuid=uuid)
-
-    subfield_name = None
-    if '-' in field_name:  # check if its subfield
-        field_name, subfield_name = field_name.split('-')
-
-        form = form._fields[field_name].form
-        field_name = subfield_name
 
-    form._fields[field_name].process_data(value)
-    return form._fields[field_name].pre_validate(form)
+def draft_form_process_and_validate(user_id, uuid, data):
+    """
+    Process, validate and store incoming form data and return response.
+    """
+    # The form is initialized with form and draft data. The original draft_data
+    # is accessible in Field.object_data, Field.raw_data is the new form data
+    # and Field.data is the processed form data or the original draft data.
+    #
+    # Behind the scences, Form.process() is called, which in turns call
+    # Field.process_data(), Field.process_formdata() and any filters defined.
+    #
+    # Field.object_data contains the value of process_data(), while Field.data
+    # contains the value of process_formdata() and any filters applied.
+    form = get_form(user_id, uuid=uuid, formdata=data)
+
+    # Run form validation which will call Field.pre_valiate(), Field.validators,
+    # Form.validate_<field>() and Field.post_validate(). Afterwards Field.data
+    # has been validated and any errors will be present in Field.errors.
+    form.validate()
+
+    # Call Form.run_processors() which in turn will call Field.run_processors()
+    # that allow fields to set flags (hide/show) and values of other fields
+    # after the entire formdata has been processed and validated.
+    validated_flags, validated_data, validated_msgs = (
+        form.flags, form.data, form.messages
+    )
+    form.post_process(fields=data.keys())
+    post_processed_flags, post_processed_data, post_processed_msgs = (
+        form.flags, form.data, form.messages
+    )
+
+    # Save draft data
+    save_form(user_id, uuid, form)
+
+    ### Build result dictionary
+    process_field_names = data.keys()
+    # Determine if some fields where changed during post-processing.
+    changed_values = dict((name, value) for name, value in post_processed_data.items() if validated_data[name] != value)
+    # Determine changed flags
+    changed_flags = dict((name, flags) for name, flags in post_processed_flags.items() if validated_flags[name] != flags)
+    # Determine changed messages
+    changed_msgs = dict((name, messages) for name, messages in post_processed_msgs.items() if validated_msgs[name] != messages or name in process_field_names)
+
+    result = {}
+    if changed_msgs:
+        result['messages'] = changed_msgs
+    if changed_values:
+        result['values'] = changed_values
+    if changed_flags:
+        for flag in CFG_FIELD_FLAGS:
+            fields = [(name, flag in field_flags) for name, field_flags in changed_flags.items()]
+            result[flag+'_on'] = map(lambda x: x[0], filter(lambda x: x[1], fields))
+            result[flag+'_off'] = map(lambda x: x[0], filter(lambda x: not x[1], fields))
+
+    return result
 
 
 def draft_field_set(user_id, uuid, field_name, value):
     """ Alters the value of a field """
 
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft).\
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               WebDepositDraft.uuid == uuid)
-    # get the draft with the max step
-    draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
-    values = draft.form_values
-
-    subfield_name = None
-    if '-' in field_name:  # check if its subfield
-        field_name, subfield_name = field_name.split('-')
-
-    if subfield_name is not None:
-        try:
-            values[field_name][subfield_name] = value
-        except (KeyError, TypeError):
-            values[field_name] = dict()
-            values[field_name][subfield_name] = value
-    else:
-        values[field_name] = value  # change value
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft).\
-        filter(WebDepositDraft.uuid == uuid,
-               WebDepositDraft.step == draft.step).\
-        update({"form_values": values,
-                "timestamp": datetime.now()})
+    Workflow.set_extra_data(user_id=user_id, uuid=uuid,
+                            setter=draft_setter(key=field_name, value=value,
+                                                field_setter=True))
 
 
 def draft_field_list_add(user_id, uuid, field_name, value,
-                         subfield=None):
+                         dummy_subfield=None):
     """Adds value to field
     Used for fields that contain multiple values
     e.g.1: { field_name : value1 } OR
            { field_name : [value1] }
            -->
            { field_name : [value1, value2] }
     e.g.2  { }
            -->
            { field_name : [value] }
     e.g.3  { }
            -->
            { field_name : {key : value} }
     """
 
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft). \
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               WebDepositDraft.uuid == uuid)
-    # get the draft with the max step
-    draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
-    values = draft.form_values
+    Workflow.set_extra_data(user_id=user_id, uuid=uuid,
+                            setter=draft_field_list_setter(field_name, value))
 
-    try:
-        if isinstance(values[field_name], list):
-            values[field_name].append(value)
-        elif subfield is not None:
-            if not isinstance(values[field_name], dict):
-                values[field_name] = dict()
-            values[field_name][subfield] = value
+
+def preingest_form_data(user_id, form_data, uuid=None,
+                        append=False, cached_data=False):
+    """Used to insert form data to the workflow before running it
+    Creates an identical json structure to the draft json.
+    If cached_data is enabled, the data will be used by the next workflow
+    initiated by the user, so the uuid can be ommited in this case.
+
+    @param user_id: the user id
+
+    @param uuid: the id of the workflow
+
+    @param form_data: a json with field_name -> value structure
+
+    @param append: set to True if you want to append the values to the existing
+                   ones
+
+    @param cached_data: set to True if you want to cache the data.
+    """
+    def preingest_data(form_data, append):
+        def preingest(json):
+            if 'pop_obj' not in json:
+                json['pop_obj'] = {}
+            for field, value in form_data.items():
+                if append:
+                    try:
+                        if isinstance(json['pop_obj'][field], list):
+                            json['pop_obj'][field].append(value)
+                        else:
+                            new_values_list = [json['pop_obj'][field]]
+                            new_values_list.append(value)
+                            json['pop_obj'][field] = new_values_list
+                    except KeyError:
+                        json['pop_obj'][field] = [value]
+                else:
+                    json['pop_obj'][field] = value
+            json['pop_obj']['timestamp'] = str(datetime.now())
+        return preingest
+
+    if cached_data:
+        cache.set(str(user_id) + ':cached_form_data', form_data)
+    else:
+        Workflow.set_extra_data(user_id=user_id, uuid=uuid,
+                                setter=preingest_data(form_data, append))
+
+        # Ingest the data in the forms, in case there are any
+        if append:
+            for field_name, value in form_data.items():
+                draft_field_list_add(user_id, uuid, field_name, value)
         else:
-            new_values_list = [values[field_name]]
-            new_values_list.append(value)
-            values[field_name] = new_values_list
-    except KeyError:
-        values[field_name] = [value]
+            for field_name, value in form_data.items():
+                draft_field_set(user_id, uuid, field_name, value)
+
+
+def get_preingested_form_data(user_id, uuid=None, key=None, cached_data=False):
+    def get_preingested_data(key):
+        def getter(json):
+            if 'pop_obj' in json:
+                if key is None:
+                    return json['pop_obj']
+                else:
+                    return json['pop_obj'][key]
+            else:
+                return {}
+        return getter
+
+    if cached_data:
+        return cache.get(str(user_id) + ':cached_form_data')
+    return Workflow.get_extra_data(user_id, uuid=uuid,
+                                   getter=get_preingested_data(key))
+
+
+def validate_preingested_data(user_id, uuid, deposition_type=None):
+    """Validates all preingested data by trying to match the json with every
+    form. Then the validation function is being called for each form.
+    """
+    form_data = get_preingested_form_data(user_id, uuid)
 
-    db.session.query(WebDepositDraft).\
-        filter(WebDepositDraft.uuid == uuid,
-               WebDepositDraft.step == draft.step).\
-        update({"form_values": values,
-                "timestamp": datetime.now()})
+    deposition = get_workflow(uuid, deposition_type)
+
+    form_types = []
+    # Get all form types from workflow
+    for fun in deposition.workflow:
+        if '__form_type__' in fun.__dict__:
+            form_render = render_form(forms[fun.__form_type__])
+            if form_render.func_code == fun.func_code:
+                form_types.append(fun.__form_type__)
+
+    errors = {}
+    for form_type in form_types:
+        form = forms[form_type]()
+        for field in form:
+            if field.name in form_data:
+                field.data = form_data.pop(field.name)
+
+        form.validate()
+
+        errors.update(form.errors)
+
+    return errors
 
 
 def get_all_drafts(user_id):
+    """ Returns a dictionary with deposition types and their """
+    return dict(
+        db.session.
+        query(Workflow.name,
+              db.func.count(Workflow.uuid)).
+        filter(Workflow.status != CFG_WORKFLOW_STATUS.FINISHED,
+               Workflow.user_id == user_id).
+        group_by(Workflow.name).
+        all())
+
     drafts = dict(
         db.session.query(Workflow.name,
                          db.func.count(
                          db.func.distinct(WebDepositDraft.uuid))).
         join(WebDepositDraft.workflow).
         filter(db.and_(Workflow.user_id == user_id,
                        Workflow.status != CFG_WORKFLOW_STATUS.FINISHED)).
         group_by(Workflow.name).all())
 
     return drafts
 
 
 def get_draft(user_id, uuid, field_name=None):
     """ Returns draft values in a field_name => field_value dictionary
         or if field_name is defined, returns the associated value
     """
 
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft).\
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               WebDepositDraft.uuid == uuid)
-    # get the draft with the max step
-    draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
+    draft = Workflow.get(user_id=user_id, uuid=uuid)
 
-    form_values = draft.form_values
+    form_values = draft['form_values']
 
     if field_name is None:
         return form_values
     else:
         try:
             return form_values[field_name]
         except KeyError:  # field_name doesn't exist
             return form_values  # return whole row
 
 
-def delete_draft(user_id, deposition_type, uuid):
-    """ Deletes the draft with uuid=uuid
-        and returns the most recently used draft
-        if there is no draft left, returns None
-        (usage not recommended inside workflow context)
-    """
-
-    db.session.query(WebDepositDraft). \
-        filter_by(uuid=uuid, user_id=user_id). \
-        delete()
-    db.session.commit()
-
-    latest_draft = \
-        db.session.query(WebDepositDraft). \
-        filter_by(user_id=user_id,
-                  deposition_type=deposition_type). \
-        order_by(desc(WebDepositDraft.timestamp)). \
-        first()
-    if latest_draft is None:  # There is no draft left
-        return None
-    else:
-        return latest_draft.uuid
-
-
 def draft_field_get_all(user_id, deposition_type):
     """ Returns a list with values of the field_names specified
         containing all the latest drafts
         of deposition of type=deposition_type
     """
 
-    ## Select drafts with max step from each uuid.
-    subquery = \
-        db.session.query(WebDepositDraft.uuid,
-                         db.func.max(WebDepositDraft.step)). \
-        join(WebDepositDraft.workflow).\
-        filter(db.and_(Workflow.status != CFG_WORKFLOW_STATUS.FINISHED,
-                       Workflow.user_id == user_id,
-                       Workflow.name == deposition_type,
-                       Workflow.module_name == 'webdeposit')). \
-        group_by(WebDepositDraft.uuid)
-
-    drafts = \
-        WebDepositDraft.query. \
-        filter(db.tuple_(WebDepositDraft.uuid, WebDepositDraft.step).
-               in_(subquery)). \
-        order_by(db.desc(WebDepositDraft.timestamp)). \
-        all()
-    return drafts
-
+    ## Select drafts with max step workflow.
+    workflows = Workflow.get(Workflow.status != CFG_WORKFLOW_STATUS.FINISHED,
+                             Workflow.user_id == user_id,
+                             Workflow.name == deposition_type,
+                             Workflow.module_name == 'webdeposit').all()
 
-def set_current_draft(user_id, uuid):
-    webdeposit_draft_query = \
-        db.session.query(WebDepositDraft).\
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               WebDepositDraft.uuid == uuid)
-    # get the draft with the max step
-    draft = max(webdeposit_draft_query.all(), key=lambda w: w.step)
+    drafts = []
+    get_max_draft = draft_getter()
 
-    draft.timestamp = datetime.now()
-    db.session.commit()
+    class Draft(object):
+        def __init__(self, dictionary, workflow):
+            for k, v in dictionary.items():
+                setattr(self, k, v)
+            setattr(self, 'workflow', workflow)
+            setattr(self, 'uuid', workflow.uuid)
 
+    for workflow in workflows:
+        max_draft = get_max_draft(workflow.extra_data)
+        if max_draft is not None:
+            drafts.append(Draft(max_draft, workflow))
 
-def get_current_draft(user_id, deposition_type):
-    webdeposit_draft = \
-        db.session.query(WebDepositDraft).\
-        join(Workflow).\
-        filter(Workflow.user_id == user_id,
-               Workflow.name == deposition_type).\
-        order_by(desc(WebDepositDraft.timestamp)). \
-        first()
-    return webdeposit_draft
+    drafts = sorted(drafts, key=lambda d: d.timestamp, reverse=True)
+    return drafts
 
 
 def create_user_file_system(user_id, deposition_type, uuid):
     # Check if webdeposit folder exists
     if not os.path.exists(CFG_WEBDEPOSIT_UPLOAD_FOLDER):
         os.makedirs(CFG_WEBDEPOSIT_UPLOAD_FOLDER)
 
     # Create user filesystem
     # user/deposition_type/uuid/files
     CFG_USER_WEBDEPOSIT_FOLDER = os.path.join(CFG_WEBDEPOSIT_UPLOAD_FOLDER,
                                               "user_" + str(user_id))
     if not os.path.exists(CFG_USER_WEBDEPOSIT_FOLDER):
         os.makedirs(CFG_USER_WEBDEPOSIT_FOLDER)
 
     CFG_USER_WEBDEPOSIT_FOLDER = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
                                               deposition_type)
     if not os.path.exists(CFG_USER_WEBDEPOSIT_FOLDER):
         os.makedirs(CFG_USER_WEBDEPOSIT_FOLDER)
 
     CFG_USER_WEBDEPOSIT_FOLDER = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
                                               uuid)
     if not os.path.exists(CFG_USER_WEBDEPOSIT_FOLDER):
         os.makedirs(CFG_USER_WEBDEPOSIT_FOLDER)
 
     return CFG_USER_WEBDEPOSIT_FOLDER
 
 
 def decode_dict_from_unicode(unicode_input):
     if isinstance(unicode_input, dict):
         return dict((decode_dict_from_unicode(key),
                      decode_dict_from_unicode(value))
                     for key, value in unicode_input.iteritems())
     elif isinstance(unicode_input, list):
         return [decode_dict_from_unicode(element) for element in unicode_input]
     elif isinstance(unicode_input, unicode):
         return unicode_input.encode('utf-8')
     else:
         return unicode_input
 
 
 def url_upload(user_id, deposition_type, uuid, url, name=None, size=None):
 
     try:
         data = urlopen(url).read()
     except URLError:
         return "Error"
 
     CFG_USER_WEBDEPOSIT_FOLDER = create_user_file_system(user_id,
                                                          deposition_type,
                                                          uuid)
     unique_filename = str(new_uuid()) + name
     file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
                              unique_filename)
     f = open(file_path, 'wb')
     f.write(data)
 
     if size is None:
         size = os.path.getsize(file_path)
     if name is None:
         name = url.split('/')[-1]
     file_metadata = dict(name=name, file=file_path, size=size)
     draft_field_list_add(current_user.get_id(), uuid,
                          "files", file_metadata)
 
     return unique_filename
+
+
+def deposit_files(user_id, deposition_type, uuid, preingest=False):
+    """Attach files to a workflow
+    Upload a single file or a file in chunks.
+    Function must be called within a blueprint function that handles file
+    uploading.
+
+    Request post parameters:
+        chunks: number of chunks
+        chunk: current chunk number
+        name: name of the file
+
+    @param user_id: the user id
+
+    @param deposition_type: the deposition the files will be attached
+
+    @param uuid: the id of the deposition
+
+    @param preingest: set to True if you want to store the file metadata in the
+                      workflow before running the workflow, i.e. to bind the
+                      files to the workflow and not in the last form draft.
+
+    @return: the path of the uploaded file
+    """
+    if request.method == 'POST':
+        try:
+            chunks = request.form['chunks']
+            chunk = request.form['chunk']
+        except KeyError:
+            chunks = None
+            pass
+
+        current_chunk = request.files['file']
+        try:
+            name = request.form['name']
+        except BadRequestKeyError:
+            name = current_chunk.filename
+        try:
+            filename = secure_filename(name) + "_" + chunk
+        except UnboundLocalError:
+            filename = secure_filename(name)
+
+        CFG_USER_WEBDEPOSIT_FOLDER = create_user_file_system(user_id,
+                                                             deposition_type,
+                                                             uuid)
+
+        # Save the chunk
+        current_chunk.save(os.path.join(CFG_USER_WEBDEPOSIT_FOLDER, filename))
+
+        unique_filename = ""
+
+        if chunks is None:  # file is a single chunk
+            unique_filename = str(new_uuid()) + filename
+            old_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER, filename)
+            file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
+                                     unique_filename)
+            os.rename(old_path, file_path)  # Rename the chunk
+            if current_chunk.content_length != 0:
+                size = current_chunk.content_length
+            else:
+                size = os.path.getsize(file_path)
+            content_type = current_chunk.content_type or ''
+            file_metadata = dict(name=name, file=file_path,
+                                 content_type=content_type, size=size)
+            if preingest:
+                preingest_form_data(user_id, uuid, {'files': file_metadata})
+            else:
+                draft_field_list_add(user_id, uuid,
+                                     "files", file_metadata)
+        elif int(chunk) == int(chunks) - 1:
+            '''All chunks have been uploaded!
+                start merging the chunks'''
+            filename = secure_filename(name)
+            chunk_files = []
+            for chunk_file in iglob(os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
+                                                 filename + '_*')):
+                chunk_files.append(chunk_file)
+
+            # Sort files in numerical order
+            chunk_files.sort(key=lambda x: int(x.split("_")[-1]))
+
+            unique_filename = str(new_uuid()) + filename
+            file_path = os.path.join(CFG_USER_WEBDEPOSIT_FOLDER,
+                                     unique_filename)
+            destination = open(file_path, 'wb')
+            for chunk in chunk_files:
+                shutil.copyfileobj(open(chunk, 'rb'), destination)
+                os.remove(chunk)
+            destination.close()
+            size = os.path.getsize(file_path)
+            file_metadata = dict(name=name, file=file_path, size=size)
+            if preingest:
+                preingest_form_data(user_id, uuid, {'files': file_metadata},
+                                    append=True)
+            else:
+                draft_field_list_add(user_id, uuid,
+                                     "files", file_metadata)
+    return unique_filename
+
+
+def delete_file(user_id, uuid, preingest=False):
+    if request.method == 'POST':
+        files = draft_field_get(user_id, uuid, "files")
+        result = "File Not Found"
+        filename = request.form['filename']
+        if preingest:
+            files = get_preingested_form_data(user_id, uuid, 'files')
+        else:
+            files = draft_field_get(user_id, uuid, "files")
+
+        for i, f in enumerate(files):
+            if filename == f['file'].split('/')[-1]:
+                # get the unique name from the path
+                os.remove(f['file'])
+                del files[i]
+                result = str(files) + "              "
+                if preingest:
+                    preingest_form_data(user_id, uuid, files)
+                else:
+                    draft_field_set(current_user.get_id(), uuid,
+                                    "files", files)
+                result = "File " + f['name'] + " Deleted"
+                break
+    return result
diff --git a/modules/webdeposit/lib/webdeposit_validation_utils.py b/modules/webdeposit/lib/webdeposit_validation_utils.py
index 6b7e1e67b..6053644f7 100644
--- a/modules/webdeposit/lib/webdeposit_validation_utils.py
+++ b/modules/webdeposit/lib/webdeposit_validation_utils.py
@@ -1,204 +1,163 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-from invenio.dataciteutils import DataciteMetadata
-from invenio.sherpa_romeo import SherpaRomeoSearch
-from invenio.bibfield import get_record
-
-#FIXME: make the functions to return functions so that
-#       in the config file we can define parameters
-#       eg. length(5,10)
-
-
-def datacite_doi_validate(field, dummy_form=None):
-    value = field.data
-    if value == "" or value.isspace():
-        return dict()
-    datacite = DataciteMetadata(value)
-    if datacite.error:
-        return dict(info=1, info_message="Couldn't retrieve doi metadata")
-
-    return dict(fields=dict(publisher=datacite.get_publisher(),
-                            title=datacite.get_titles(),
-                            date=datacite.get_dates(),
-                            abstract=datacite.get_description()),
-                success=1,
-                success_message='Datacite.org metadata imported successfully')
-
-
-def sherpa_romeo_issn_validate(field, dummy_form=None):
-    value = field.data
-    if value == "" or value.isspace():
-        return dict(error=0, error_message='')
-    s = SherpaRomeoSearch()
-    s.search_issn(value)
-    if s.error:
-        return dict(error=1, error_message=s.error_message)
-
-    if s.get_num_hits() == 1:
-        journal = s.parser.get_journals(attribute='jtitle')
-        journal = journal[0]
-        publisher = s.parser.get_publishers(journal=journal)
-        if publisher is not None and publisher != []:
-            return dict(error=0, error_message='',
-                        fields=dict(journal=journal,
-                                    publisher=publisher['name']))
-        else:
-            return dict(error=0, error_message='',
-                        fields=dict(journal=journal))
-
-    return dict(info=1, info_message="Couldn't find Journal")
-
-
-def sherpa_romeo_publisher_validate(field, dummy_form=None):
-    value = field.data
-    if value == "" or value.isspace():
-        return dict(error=0, error_message='')
-    s = SherpaRomeoSearch()
-    s.search_publisher(value)
-    if s.error:
-        return dict(info=1, info_message=s.error_message)
-
-    conditions = s.parser.get_publishers(attribute='conditions')
-    if conditions is not None and s.get_num_hits() == 1:
-        conditions = conditions[0]
-    else:
-        conditions = []
-    if conditions != []:
-        conditions_html = "<u>Conditions</u><br><ol>"
-        if isinstance(conditions['condition'], str):
-            conditions_html += "<li>" + conditions['condition'] + "</li>"
-        else:
-            for condition in conditions['condition']:
-                conditions_html += "<li>" + condition + "</li>"
-
-        copyright_links = s.parser.get_publishers(attribute='copyrightlinks')
-        if copyright_links is not None and copyright_links != []:
-            copyright_links = copyright_links[0]
-        else:
-            copyright_links = None
-
-        if isinstance(copyright_links, list):
-            copyright_links_html = ""
-            for copyright_link in copyright_links['copyrightlink']:
-                copyright_links_html += '<a href="' + copyright_link['copyrightlinkurl'] + \
-                                        '">' + copyright_link['copyrightlinktext'] + "</a><br>"
-        elif isinstance(copyright_links, dict):
-            if isinstance(copyright_links['copyrightlink'], list):
-                for copyright_link in copyright_links['copyrightlink']:
-                    copyright_links_html = '<a href="' + copyright_link['copyrightlinkurl'] + \
-                                           '">' + copyright_link['copyrightlinktext'] + "</a><br>"
-            else:
-                copyright_link = copyright_links['copyrightlink']
-                copyright_links_html = '<a href="' + copyright_link['copyrightlinkurl'] + \
-                                       '">' + copyright_link['copyrightlinktext'] + "</a><br>"
-
-        home_url = s.parser.get_publishers(attribute='homeurl')
-        if home_url is not None and home_url != []:
-            home_url = home_url[0]
-            home_url = '<a href="' + home_url + '">' + home_url + "</a>"
-        else:
-            home_url = None
-
-        info_html = ""
-        if home_url is not None:
-            info_html += "<p>" + home_url + "</p>"
-
-        if conditions is not None:
-            info_html += "<p>" + conditions_html + "</p>"
-
-        if copyright_links is not None:
-            info_html += "<p>" + copyright_links_html + "</p>"
-
-        if info_html != "":
-            return dict(error=0, error_message='',
-                        info=1, info_message=info_html)
-    return dict(error=0, error_message='')
-
-
-def sherpa_romeo_journal_validate(field, dummy_form=None):
-    value = field.data
-    if value == "" or value.isspace():
-        return dict(error=0, error_message='')
-
-    s = SherpaRomeoSearch()
-    s.search_journal(value, 'exact')
-    if s.error:
-        return dict(info=1, info_message=s.error_message)
-
-    if s.get_num_hits() == 1:
-        issn = s.parser.get_journals(attribute='issn')
-        if issn != [] and issn is not None:
-            issn = issn[0]
-            publisher = s.parser.get_publishers(journal=value)
-            if publisher is not None and publisher != []:
-                return dict(error=0, error_message='',
-                            fields=dict(issn=issn,
-                                        publisher=publisher['name']))
-            return dict(error=0, error_message='',
-                        info=1, info_message="Journal's Publisher not found",
-                        fields=dict(publisher="", issn=issn))
-        else:
-            return dict(info=1, info_message="Couldn't find ISSN")
-    return dict(error=0, error_message='')
-
-
-def number_validate(field, dummy_form=None, error_message='It must be a number!'):
-    value = field.data
+"""
+Validation functions
+"""
+
+import re
+from wtforms.validators import ValidationError, StopValidation, Regexp
+from invenio.config import CFG_SITE_NAME
+
+
+#
+# General purpose validators
+#
+class RequiredIf(object):
+    """
+    Require field if value of another field is set to a certain value.
+    """
+    def __init__(self, other_field_name, values, message=None):
+        self.other_field_name = other_field_name
+        self.values = values
+        self.message = message
+
+    def __call__(self, form, field):
+        try:
+            other_field = getattr(form, self.other_field_name)
+            other_val = other_field.data
+            if other_val in self.values:
+                if not field.data or isinstance(field.data, basestring) \
+                   and not field.data.strip():
+                    if self.message is None:
+                        self.message = 'This field is required.'
+                    field.errors[:] = []
+                    raise StopValidation(self.message % {
+                        'other_field': other_field.label.text,
+                        'value': other_val
+                    })
+        except AttributeError:
+            pass
+
+
+#
+# DOI-related validators
+#
+doi_syntax_validator = Regexp(
+    "(^$|(doi:)?10\.\d+(.\d+)*/.*)",
+    flags=re.I,
+    message="The provided DOI is invalid - it should look similar to "
+            "'10.1234/foo.bar'."
+)
+
+"""
+DOI syntax validator
+"""
+
+
+class InvalidDOIPrefix(object):
+    """
+    Validates if DOI
+    """
+    def __init__(self, prefix='10.5072', message=None,
+                 message_testing=None):
+        """
+        @param doi_prefix: DOI prefix, e.g. 10.5072
+        """
+        self.doi_prefix = prefix
+        # Remove trailing slash
+        if self.doi_prefix[-1] == '/':
+            self.doi_prefix = self.doi_prefix[:-1]
+
+        if not message_testing:
+            self.message_testing = "The prefix 10.5072 is invalid. The prefix" \
+                "is only used for testing purposes, and no DOIs with this " \
+                "prefix are attached to any meaningful content."
+        if not message:
+            self.message = 'The prefix %(prefix)s is ' \
+                'administered automatically by %(CFG_SITE_NAME)s.'
+
+        ctx = dict(
+            prefix=prefix,
+            CFG_SITE_NAME=CFG_SITE_NAME
+        )
+        self.message = self.message % ctx
+        self.message_testing = self.message_testing % ctx
+
+    def __call__(self, form, field):
+        value = field.data
+
+        # Defined prefix
+        if value:
+            if value.startswith("%s/" % self.doi_prefix):
+                raise ValidationError(self.message)
+
+            # Testing name space
+            if self.doi_prefix != "10.5072" and value.startswith("10.5072/"):
+                raise ValidationError(self.message_testing)
+
+
+class PreReservedDOI(object):
+    """
+    Validate that user did not edit pre-reserved DOI.
+    """
+    def __init__(self, field_name, message=None, prefix='10.5072'):
+        self.field_name = field_name
+        self.message = message or 'You are not allowed to edit a ' \
+                                  'pre-reserved DOI. Click the Pre-reserve ' \
+                                  'DOI button to resolve the problem.'
+        self.prefix = prefix
+
+    def __call__(self, form, field):
+        attr_value = getattr(form, self.field_name).data
+        if attr_value and field.data and field.data != attr_value and field.data.startswith("%s/" % self.prefix):
+            raise StopValidation(self.message)
+        # Stop further validation if DOI equals pre-reserved DOI.
+        if attr_value and field.data and field.data == attr_value:
+            raise StopValidation()
+
+
+#
+# Aliases
+#
+required_if = RequiredIf
+invalid_doi_prefix_validator = InvalidDOIPrefix
+pre_reserved_doi_validator = PreReservedDOI
+
+
+def number_validate(form, field, submit=False, error_message='It must be a number!'):
+    value = field.data or ''
     if value == "" or value.isspace():
-        return dict(error=0, error_message='')
+        return
 
     def is_number(s):
         try:
             float(s)
             return True
         except ValueError:
             return False
 
     if not is_number(value):
         try:
             field.errors.append(error_message)
         except AttributeError:
             field.errors = list(field.process_errors)
             field.errors.append(error_message)
-        return dict(error=1,
-                    error_message=error_message)
-    else:
-        return dict(error=0, error_message='')
-
-
-def record_id_validate(field, form=None):
-    value = field.data
-    is_number = number_validate(field)['error'] == 0 \
-        and (value != "" or not value.isspace())
-
-    if is_number:
-        json_reader = get_record(value)
-    else:
-        return dict(error=1, error_message="Record id must be a number!")
-    if json_reader is not None:
-        webdeposit_json = form.uncook_json(json_reader, {}, value)
-        #FIXME: update current json
-
-        return dict(info=1,
-                    info_message='<a href="/record/"' + value +
-                                 '>Record</a> loaded successfully',
-                    fields=webdeposit_json)
-    else:
-        return dict(info=1, info_message="Record doesn't exist")
+        field.add_message('error', error_message)
+        return
diff --git a/modules/webdeposit/lib/webdeposit_workflow.py b/modules/webdeposit/lib/webdeposit_workflow.py
index e38edea3a..b2e8c895f 100644
--- a/modules/webdeposit/lib/webdeposit_workflow.py
+++ b/modules/webdeposit/lib/webdeposit_workflow.py
@@ -1,217 +1,229 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 from invenio.bibworkflow_engine import BibWorkflowEngine
 from invenio.bibworkflow_model import Workflow, BibWorkflowObject
 from invenio.bibworkflow_client import restart_workflow
 from invenio.bibfield_jsonreader import JsonReader
 from uuid import uuid1 as new_uuid
 
 
 class DepositionWorkflow(object):
     """ class for running webdeposit workflows using the BibWorkflow engine
 
         The user_id and workflow must always be defined
         If the workflow has been initialized before,
         the appropriate uuid must be passed as a parameter.
         Otherwise a new workflow will be created
 
         The workflow functions must have the following structure:
 
         def function_name(arg1, arg2):
             def fun_name2(obj, eng):
                 # do stuff
             return fun_name2
     """
 
     def __init__(self, engine=None, workflow=[],
                  uuid=None, deposition_type=None, user_id=None):
 
         self.obj = {}
         self.set_user_id(user_id)
         self.set_uuid(uuid)
 
         self.deposition_type = deposition_type
 
         self.current_step = 0
         self.set_engine(engine)
         self.set_workflow(workflow)
         self.set_object()
 
     def set_uuid(self, uuid=None):
         """ Sets the uuid or obtains a new one """
         if uuid is None:
             uuid = new_uuid()
             self.uuid = uuid
         else:
             self.uuid = uuid
 
     def get_uuid(self):
         return self.uuid
 
     def set_engine(self, engine=None):
         """ Initializes the BibWorkflow engine """
         if engine is None:
             engine = BibWorkflowEngine(name=self.get_deposition_type(),
                                        uuid=self.get_uuid(),
                                        user_id=self.get_user_id(),
                                        module_name="webdeposit")
         self.eng = engine
         self.eng.save()
 
     def set_workflow(self, workflow):
         """ Sets the workflow """
 
         self.eng.setWorkflow(workflow)
         self.workflow = workflow
         self.steps_num = len(workflow)
         self.obj['steps_num'] = self.steps_num
 
     def set_object(self):
-        self.db_workflow_obj = \
-            WfeObject.query.filter(WfeObject.workflow_id == self.get_uuid()). \
-            first()
+        db_workflow_objects = \
+            WfeObject.query.filter(WfeObject.workflow_id == self.get_uuid())
+        try:
+            self.db_workflow_obj = max(db_workflow_objects.all(),
+                                       key=lambda w: w.id)
+        except ValueError:
+            self.db_workflow_obj = None
+
         if self.db_workflow_obj is None:
             self.bib_obj = BibWorkflowObject(data=self.obj,
                                              workflow_id=self.get_uuid(),
                                              user_id=self.get_user_id())
         else:
             self.bib_obj = BibWorkflowObject(wfobject_id=self.db_workflow_obj.id,
                                              workflow_id=self.get_uuid(),
                                              user_id=self.get_user_id())
 
     def get_object(self):
         return self.bib_obj
 
     def set_deposition_type(self, deposition_type=None):
         if deposition_type is not None:
             self.obj['deposition_type'] = deposition_type
 
     def get_deposition_type(self):
         return self.obj['deposition_type']
 
     deposition_type = property(get_deposition_type, set_deposition_type)
 
     def set_user_id(self, user_id=None):
         if user_id is not None:
             self.user_id = user_id
         else:
             from invenio.webuser_flask import current_user
             self.user_id = current_user.get_id()
 
         self.obj['user_id'] = self.user_id
 
     def get_user_id(self):
         return self.user_id
 
     def get_status(self):
         """ Returns the status of the workflow
             (check CFG_WORKFLOW_STATUS from bibworkflow_engine)
         """
         status = \
             Workflow.query. \
             filter(Workflow.uuid == self.get_uuid()).\
             one().status
 
         return status
 
-    def get_output(self, form_validation=None):
+    def get_data(self, key):
+        if key in self.bib_obj.data:
+            return self.bib_obj.data[key]
+        else:
+            self.set_object()  # refresh the current object and check again
+            if key in self.bib_obj.data:
+                return self.bib_obj.data[key]
+            return None
+
+    def get_output(self, form=None, form_validation=False):
         """ Returns a representation of the current state of the workflow
             (a dict with the variables to fill the jinja template)
         """
+        from invenio.webdeposit_utils import get_form, \
+            draft_field_get_all
+
         user_id = self.user_id
         uuid = self.get_uuid()
 
-        from invenio.webdeposit_utils import get_form, \
-            draft_field_get_all
-        form = get_form(user_id, uuid)
+        if form is None:
+            form = get_form(
+                user_id, uuid, validate_draft=not form_validation
+            )
 
         deposition_type = self.obj['deposition_type']
         drafts = draft_field_get_all(user_id, deposition_type)
 
         if form_validation:
             form.validate()
 
-        # Get the template from configuration for this form
-        template = form.config.get_template() or 'webdeposit_add.html'
+        # Get the template for this form
+        template = form.get_template()
 
         return dict(template_name_or_list=template,
                     workflow=self,
                     deposition_type=deposition_type,
                     form=form,
                     drafts=drafts,
                     uuid=uuid)
 
     def run(self):
         """ Runs or resumes the workflow """
         finished = self.eng.db_obj.counter_finished > 1
         if finished:
             # The workflow is finished, nothing to do
             return
         wfobjects = \
             WfeObject.query. \
             filter(WfeObject.workflow_id == self.get_uuid())
         wfobject = max(wfobjects.all(), key=lambda w: w.modified)
         starting_point = wfobject.task_counter
         restart_workflow(self.eng, [self.bib_obj],
                          starting_point, stop_on_halt=True)
 
     def run_next_step(self):
         if self.current_step >= self.steps_num:
             self.obj['break'] = True
             return
         function = self.workflow[self.current_step]
         function(self.obj, self)
         self.current_step += 1
         self.obj['step'] = self.current_step
 
     def jump_forward(self):
         restart_workflow(self.eng, [self.bib_obj], 'next', stop_on_halt=True)
 
     def jump_backwards(self, dummy_synchronize=False):
         if self.current_step > 1:
             self.current_step -= 1
         else:
             self.current_step = 1
 
     def get_workflow_from_db(self):
         return Workflow.query.filter(Workflow.uuid == self.get_uuid()).first()
 
     def cook_json(self):
         user_id = self.obj['user_id']
         uuid = self.get_uuid()
 
         from invenio.webdeposit_utils import get_form
 
         json_reader = JsonReader()
         for step in range(self.steps_num):
             try:
                 form = get_form(user_id, uuid, step)
                 json_reader = form.cook_json(json_reader)
             except:
                 # some steps don't have any form ...
                 pass
 
         return json_reader
-
-    def get_data(self, key):
-        if key in self.bib_obj.data:
-            return  self.bib_obj.data[key]
-        else:
-            return None
diff --git a/modules/webdeposit/lib/webdeposit_workflow_utils.py b/modules/webdeposit/lib/webdeposit_workflow_utils.py
index 1c693ca91..ea07909ca 100644
--- a/modules/webdeposit/lib/webdeposit_workflow_utils.py
+++ b/modules/webdeposit/lib/webdeposit_workflow_utils.py
@@ -1,141 +1,228 @@
 # -*- coding: utf-8 -*-
 ##
 ## This file is part of Invenio.
 ## Copyright (C) 2012, 2013 CERN.
 ##
 ## Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 import os
 import time
-from sqlalchemy import func
+from datetime import datetime
 from invenio.sqlalchemyutils import db
-from invenio.webdeposit_config_utils import WebDepositConfiguration
-from invenio.webdeposit_model import WebDepositDraft
 from invenio.bibworkflow_model import Workflow
 from invenio.bibfield_jsonreader import JsonReader
 from tempfile import mkstemp
 from invenio.bibtask import task_low_level_submission
-from invenio.config import CFG_TMPSHAREDDIR
+from invenio.config import CFG_TMPSHAREDDIR, CFG_PREFIX
+from invenio.dbquery import run_sql
 
 """
     Functions to implement workflows
 
     The workflow functions must have the following structure:
 
     def function_name(arg1, arg2):
             def fun_name2(obj, eng):
                 # do stuff
             return fun_name2
 """
 
 
 def authorize_user(user_id=None):
     def user_auth(obj, dummy_eng):
         if user_id is not None:
             obj.data['user_id'] = user_id
         else:
             from invenio.webuser_flask import current_user
             obj.data['user_id'] = current_user.get_id()
     return user_auth
 
 
+def populate_form_data(form_data):
+    """ Pass a json to initialize the values of the forms.
+        If two forms use the same name for a field,
+        the value is passed to the one that is rendered first."""
+    def populate(obj, eng):
+        obj.data['form_values'] = form_data
+    return populate
+
+
 def render_form(form):
     def render(obj, eng):
+        from invenio.webdeposit_utils import get_last_step, CFG_DRAFT_STATUS, \
+            add_draft,  get_preingested_form_data, preingest_form_data
+
         uuid = eng.uuid
-        # TODO: get the current step from the object
-        step = max(obj.db_obj.task_counter)  # data['step']
+        user_id = obj.data['user_id']
+        #TODO: create out of the getCurrTaskId() which is a list
+        # an incremental key that represents also steps in complex workflows.
+        step = get_last_step(eng.getCurrTaskId())
         form_type = form.__name__
-        from invenio.webdeposit_utils import CFG_DRAFT_STATUS
-        webdeposit_draft = WebDepositDraft(uuid=uuid,
-                                           form_type=form_type,
-                                           form_values={},
-                                           step=step,
-                                           status=CFG_DRAFT_STATUS['unfinished'],
-                                           timestamp=func.current_timestamp())
-        db.session.add(webdeposit_draft)
-        db.session.commit()
+
+        if obj.data.has_key('form_values') and obj.data['form_values'] is not None:
+            form_values = obj.data['form_values']
+        else:
+            form_values = {}
+        # Prefill the form from cache
+        cached_form = get_preingested_form_data(user_id, cached_data=True)
+
+        # Check for preingested data from webdeposit API
+        preingested_form_data = get_preingested_form_data(user_id, uuid)
+        if preingested_form_data != {} and preingested_form_data is not None:
+            form_data = preingested_form_data
+        elif cached_form is not None:
+            form_data = cached_form
+            # Clear cache
+            preingest_form_data(user_id, None, cached_data=True)
+        else:
+            form_data = {}
+
+        # Filter the form_data to match the current form
+        for field in form():
+            if field.name in form_data:
+                form_values[field.name] = form_data[field.name]
+
+        draft = dict(form_type=form_type,
+                     form_values=form_values,
+                     status=CFG_DRAFT_STATUS['unfinished'],
+                     timestamp=str(datetime.now()),
+                     step=step)
+
+        Workflow.set_extra_data(user_id=user_id, uuid=uuid,
+                                setter=add_draft(draft))
+    render.__form_type__ = form.__name__
     return render
 
 
 def wait_for_submission():
     def wait(obj, eng):
         user_id = obj.data['user_id']
         uuid = eng.uuid
         from invenio.webdeposit_utils import CFG_DRAFT_STATUS, get_form_status
         status = get_form_status(user_id, uuid)
         if status == CFG_DRAFT_STATUS['unfinished']:
             # If form is unfinished stop the workflow
             eng.halt('Waiting for form submission.')
         else:
             # If form is completed, continue with next step
             eng.jumpCallForward(1)
     return wait
 
 
 def export_marc_from_json():
+    """ Exports marc from json using BibField """
     def export(obj, eng):
         user_id = obj.data['user_id']
         uuid = eng.uuid
         steps_num = obj.data['steps_num']
 
         from invenio.webdeposit_utils import get_form
         json_reader = JsonReader()
+
+        try:
+            pop_obj = Workflow.get_extra_data(user_id=user_id, uuid=uuid,
+                                              key='pop_obj')
+        except KeyError:
+            pop_obj = None
+
+        form_data = {}
+        if 'form_values' in obj.data or pop_obj is not None:
+
+            # copy the form values to be able to
+            # delete the fields in the workflow object during iteration
+            form_data = pop_obj or obj.data['form_values']
+
+        # Populate the form with data
         for step in range(steps_num):
             form = get_form(user_id, uuid, step)
+
             # Insert the fields' values in bibfield's rec_json dictionary
             if form is not None:  # some steps don't have any form ...
+                # Populate preingested data
+                for field in form:
+                    if field.name in form_data:
+                        field.data = form_data.pop(field.name)
                 json_reader = form.cook_json(json_reader)
 
         deposition_type = \
             db.session.query(Workflow.name).\
             filter(Workflow.user_id == user_id,
                    Workflow.uuid == uuid).\
             one()[0]
 
         # Get the collection from configuration
-        deposition_conf = WebDepositConfiguration(deposition_type=deposition_type)
-        # or if it's not there, name the collection after the deposition type
-        json_reader['collection.primary'] = \
-            deposition_conf.get_collection() or deposition_type
-
-        if 'recid' in json_reader or 'record ID' in json_reader:
-            obj.data['update_record'] = True
+        # FIXME: Collection should be fully configurable.
+        json_reader['collection.primary'] = deposition_type
+
+        if 'recid' not in json_reader or 'record ID' not in json_reader:
+            # Record is new, reserve record id
+            recid = run_sql("INSERT INTO bibrec (creation_date, modification_date) VALUES (NOW(), NOW())")
+            json_reader['recid'] = recid
+            obj.data['recid'] = recid
         else:
-            obj.data['update_record'] = False
+            obj.data['recid'] = json_reader['recid']
+            obj.data['title'] = json_reader['title.title']
+
+        workflow = Workflow.query.filter(Workflow.uuid == uuid).one()
+        workflow.extra_data['recid'] = obj.data['recid']
+        Workflow.query.\
+            filter(Workflow.uuid == uuid).\
+            update({'extra_data': workflow.extra_data})
+
         marc = json_reader.legacy_export_as_marc()
         obj.data['marc'] = marc
     return export
 
 
 def create_record_from_marc():
+    """ Generates the record from marc.
+    The function requires the marc to be generated,
+    so the function export_marc_from_json must have been called successfully
+    before
+    """
     def create(obj, dummy_eng):
         marc = obj.data['marc']
         tmp_file_fd, tmp_file_name = mkstemp(suffix='.marcxml',
                                              prefix="webdeposit_%s" %
                                              time.strftime("%Y-%m-%d_%H:%M:%S"),
                                              dir=CFG_TMPSHAREDDIR)
         os.write(tmp_file_fd, marc)
         os.close(tmp_file_fd)
         os.chmod(tmp_file_name, 0644)
 
-        if obj.data['update_record']:
-            obj.data['task_id'] = task_low_level_submission('bibupload',
-                                                            'webdeposit', '-r',
-                                                            tmp_file_name)
-        else:
-            obj.data['task_id'] = task_low_level_submission('bibupload',
-                                                            'webdeposit', '-i',
-                                                            tmp_file_name)
+        obj.data['task_id'] = task_low_level_submission('bibupload',
+                                                        'webdeposit', '-r',
+                                                        tmp_file_name)
     return create
+
+
+def bibindex():
+    """ Runs BibIndex """
+    def bibindex_task(obj, eng):
+        cmd = "%s/bin/bibindex -u admin" % CFG_PREFIX
+        if os.system(cmd):
+            eng.log.error("BibIndex task failed.")
+
+    return bibindex_task
+
+
+def webcoll():
+    """ Runs WebColl """
+    def webcoll_task(obj, eng):
+        cmd = "%s/bin/webcoll -u admin" % CFG_PREFIX
+        if os.system(cmd):
+            eng.log.error("WebColl task failed.")
+
+    return webcoll_task