Tweaked the metadata edit screen to run jsonschema validators against the data.
authortilly-Q <nattilypigeonfowl@gmail.com>
Wed, 14 May 2014 15:51:13 +0000 (11:51 -0400)
committertilly-Q <nattilypigeonfowl@gmail.com>
Wed, 14 May 2014 15:51:13 +0000 (11:51 -0400)
mediagoblin/edit/forms.py
mediagoblin/edit/views.py
mediagoblin/static/css/base.css
mediagoblin/templates/mediagoblin/edit/metadata.html
mediagoblin/templates/mediagoblin/utils/wtforms.html

index c235598059f60efd444c6839d02246909c93f0a3..7c390a3faa6c89ccfd466ef21609503ad5a85f2c 100644 (file)
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import wtforms
+from jsonschema import Draft4Validator
 
 from mediagoblin.tools.text import tag_length_validator
 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
 from mediagoblin.tools.licenses import licenses_as_choices
+from mediagoblin.tools.metadata import DEFAULT_SCHEMA, DEFAULT_CHECKER
 from mediagoblin.auth.tools import normalize_user_or_email_field
 
 
@@ -123,11 +125,37 @@ class ChangeEmailForm(wtforms.Form):
         description=_(
             "Enter your password to prove you own this account."))
 
+class MetaDataValidator(object):
+    """
+    Custom validator which runs form data in a MetaDataForm through a jsonschema
+    validator and passes errors recieved in jsonschema to wtforms.
+
+    :param  schema              The json schema to validate the data against. By
+                                default this uses the DEFAULT_SCHEMA from
+                                mediagoblin.tools.metadata.
+    :param  format_checker      The FormatChecker object that limits which types
+                                jsonschema can recognize. By default this uses
+                                DEFAULT_CHECKER from mediagoblin.tools.metadata.
+    """
+    def __init__(self, schema=DEFAULT_SCHEMA, format_checker=DEFAULT_CHECKER):
+        self.schema = schema
+        self.format_checker = format_checker
+
+    def __call__(self, form, field):
+        metadata_dict = {field.data:form.value.data}
+        validator = Draft4Validator(self.schema,
+                        format_checker=self.format_checker)
+        errors = [e.message
+            for e in validator.iter_errors(metadata_dict)]
+        if len(errors) >= 1:
+            raise wtforms.validators.ValidationError(
+                errors.pop())
+
 class MetaDataForm(wtforms.Form):
-    identifier = wtforms.TextField(_(u'Identifier'))
+    identifier = wtforms.TextField(_(u'Identifier'),[MetaDataValidator()])
     value = wtforms.TextField(_(u'Value'))
 
 class EditMetaDataForm(wtforms.Form):
     media_metadata = wtforms.FieldList(
-        wtforms.FormField(MetaDataForm, label="")
+        wtforms.FormField(MetaDataForm, ""),
     )
index 3402125712ea326b1bf5aa7ce64c5e20f64ae300..cfbaf2fa88601db1540ef5e249632d8912651d3c 100644 (file)
@@ -20,6 +20,7 @@ from itsdangerous import BadSignature
 from pyld import jsonld
 from werkzeug.exceptions import Forbidden
 from werkzeug.utils import secure_filename
+from jsonschema import ValidationError, Draft4Validator
 
 from mediagoblin import messages
 from mediagoblin import mg_globals
@@ -33,7 +34,8 @@ from mediagoblin.decorators import (require_active_login, active_user_from_url,
                             get_user_collection, user_has_privilege,
                             user_not_banned)
 from mediagoblin.tools.crypto import get_timed_signer_url
-from mediagoblin.tools.metadata import compact_and_validate
+from mediagoblin.tools.metadata import (compact_and_validate, DEFAULT_CHECKER,
+                                        DEFAULT_SCHEMA)
 from mediagoblin.tools.mail import email_debug_message
 from mediagoblin.tools.response import (render_to_response,
                                         redirect, redirect_obj, render_404)
@@ -444,24 +446,19 @@ def edit_metadata(request, media):
     if request.method == "POST" and form.validate():
         metadata_dict = dict([(row['identifier'],row['value'])
                             for row in form.media_metadata.data])
+        json_ld_metadata = None
         json_ld_metadata = compact_and_validate(metadata_dict)
         media.media_metadata = json_ld_metadata
         media.save()
         return redirect_obj(request, media)
 
-    if media.media_metadata:
+    if media.media_metadata and len(form.media_metadata) == 0:
         for identifier, value in media.media_metadata.iteritems():
             if identifier == "@context": continue
             form.media_metadata.append_entry({
                 'identifier':identifier,
                 'value':value})
-    else:
-        form.media_metadata.append_entry({
-            'identifier':"",
-            'value':""})
-        form.media_metadata.append_entry({
-            'identifier':"",
-            'value':""})
+
     return render_to_response(
         request,
         'mediagoblin/edit/metadata.html',
index a3b564ea1a4310873c5b3a0f0017c5897c2b83b2..9087034b51d3b55c0c0ed45cea24e79d4cf5a1e7 100644 (file)
@@ -940,18 +940,13 @@ p.verifier {
 
 /* for the media metadata editing table */
 table.metadata_editor {
-
     margin: 10px auto;
-    width: 1000px;
-}
-
-table.metadata_editor tr th {
-    width:100px;
+    width: 800px;
 }
 
 table.metadata_editor tr td {
-    width:300px;
+    width:350px;
 }
 table.metadata_editor tr td.form_field_input input {
-    width:300px;
+    width:350px;
 }
index b5a52e5fbe34a24ae55fcb3ee5df984728795999..21eb27b1ca410242a276438f8cfaea65ac6ab3f5 100644 (file)
@@ -69,7 +69,7 @@
   <form action="" method="POST" id="metadata_form">
 
 <!-- This table holds all the information about the media entry's metadata -->
-  <h3>{% trans %}Data{% endtrans %}</h3>
+  <h3>{% trans %}MetaData{% endtrans %}</h3>
   <table class="metadata_editor" id="metadata_list" >
     {{ wtforms_util.render_fieldlist_as_table_rows(form.media_metadata) }}
   </table>
 <!-- These are the buttons you use to control the form -->
   <table class="metadata_editor" id="buttons_bottom">
     <tr>
-      <th></th>
       <td><input type=button value="{% trans %}Add new Row{% endtrans %}"
         class="button_action" id="add_new_metadata_row" />
       </td>
-      <th></th>
       <td><input type=submit value="{% trans %}Update Metadata{% endtrans %}"
         class="button_action_highlight" /></td>
     </tr>
     <tr>
-      <th></th>
       <td><input type=button value="{% trans %}Clear empty Rows{% endtrans %}"
         class="button_action" id="clear_empty_rows" /></td>
     </tr>
index c83d53f11fc9d0c5d21ced32b1c2d0b43d83235a..7e16708ca1ca7d401f7da5a9e545e6e16120d25b 100644 (file)
 {% macro render_form_as_table_row(form) %}
   <tr>
   {%- for field in form %}
-    <th>{{ render_label_p(field) }}</th>
     <td class="form_field_input">
       {{field}}
-      {%- if field.errors -%}
-        <br />
-        <ul class="errors">
-          {% for error in field.errors %}
-            <li>{{error}}</li>
-          {%- endfor %}
-        </ul>
-      {%- endif -%}
     </td>
   {%- endfor %}
   </tr>
+  <tr>
+  {%- for field in form %}
+      {% for error in field.errors %}
+      <tr>
+        <td>
+          <p class="form_field_error">{{error}}</p>
+        </td>
+      </tr>
+      {%- endfor %}
+  {%- endfor %}
 {%- endmacro %}
 
 {% macro render_field_as_table_row(field) %}
     <th>{{ field.label.text }}</th>
     <td>
       {{field}}
-      {% if field.errors %}
-        <br />
-        <ul class="errors">
-          {% for error in field.errors %}
-            <li>{{error}}</li>
-          {% endfor %}
-        </ul>
-      {% endif %}
     </td>
   </tr>
+  {% for error in field.errors %}
+  <tr>
+    <td>
+      <p class="form_field_error">{{error}}</p>
+    </td>
+  </tr>
+  {%- endfor %}
 {% endmacro %}
 
 {% macro render_fieldlist_as_table_rows(fieldlist) %}