Repository: internetarchive/openlibrary

Issue:
Add `HTML` validation and remove `jQuery` validation from registration form
<!-- IMPORTANT: Before posting, be sure to redact or remove sensitive data, such as passwords, secret keys, session cookies, etc. -->

<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
Dependency to `epic` [#7694](https://github.com/internetarchive/openlibrary/issues/7694). Sub-task of [#9205](https://github.com/internetarchive/openlibrary/issues/9205).

### Describe the problem that you'd like solved
<!-- A clear and concise description of what you want to happen. -->
While the new real-time validation for formatting errors added in [#2055](https://github.com/internetarchive/openlibrary/issues/2055) shows very helpful errors to the user, it does not actually prevent users from submitting forms with badly formatted inputs.

### Proposal & Constraints
<!-- What is the proposed solution / implementation? Is there a precedent of this approach succeeding elsewhere? -->
While in most cases, this problem could be solved speedily by adding relevant HTML attributes to the inputs, this particular form is generated via the forms library in `form.py`:
In the HTML:
https://github.com/internetarchive/openlibrary/blob/ca46cbfe87af6e81dabc966baa5b75c827097879/openlibrary/templates/account/create.html#L53-L61
In the Python:
https://github.com/internetarchive/openlibrary/blob/ca46cbfe87af6e81dabc966baa5b75c827097879/openlibrary/plugins/upstream/forms.py#L74-L82):

However, luckily it is fairly straightforward to add any desired HTML attributes to the attribute list above, which translate to the correct attributes in the final rendered HTML.

One other issue here, which we also encountered in [#8871](https://github.com/internetarchive/openlibrary/pull/8871), is that the jQuery `validate` plugin, called via the `validate` class in the form, starts adding extra error messages to the email field on key-up. 

Since the `validate` class has no other effect on the form, as validation is handled by `init_realtime_validation` and `forms.py` validators, I propose removing it.

<!-- Which suggestions or requirements should be considered for how feature needs to appear or be implemented? -->

### Additional context
<!-- Add any other context or screenshots about the feature request here. -->
- Form library: [utils/form.py](https://github.com/internetarchive/openlibrary/blob/master/openlibrary/utils/form.py)
- Registration form set-up: [plugins/upstream/forms.py](https://github.com/internetarchive/openlibrary/blob/master/openlibrary/plugins/upstream/forms.py)
- Registration form HTML: [templates/account/create.html](https://github.com/internetarchive/openlibrary/blob/master/openlibrary/templates/account/create.html)

### Stakeholders
<!-- @ tag stakeholders of this bug -->
@cdrini




Discussion:

Resolving patch:
diff --git a/openlibrary/plugins/upstream/forms.py b/openlibrary/plugins/upstream/forms.py
--- a/openlibrary/plugins/upstream/forms.py
+++ b/openlibrary/plugins/upstream/forms.py
@@ -6,6 +6,7 @@
 from openlibrary.utils.form import (
     Form,
     Textbox,
+    Email,
     Password,
     Checkbox,
     Hidden,
@@ -54,7 +55,7 @@ def find_ia_account(email=None):
 )
 
 vlogin = RegexpValidator(
-    r"^[A-Za-z0-9-_]{3,20}$", _('Must be between 3 and 20 letters and numbers')
+    r"^[A-Za-z0-9\-_]{3,20}$", _('Must be between 3 and 20 letters and numbers')
 )
 vpass = RegexpValidator(r".{3,20}", _('Must be between 3 and 20 characters'))
 vemail = RegexpValidator(r".*@.*", _("Must be a valid email address"))
@@ -73,11 +74,12 @@ def valid(self, value):
 
 class RegisterForm(Form):
     INPUTS = [
-        Textbox(
+        Email(
             'email',
             description=_('Your email address'),
             klass='required',
             id='emailAddr',
+            required="true",
             validators=[
                 vemail,
                 email_not_already_used,
@@ -95,12 +97,18 @@ class RegisterForm(Form):
             help=_("Letters and numbers only please, and at least 3 characters."),
             autocapitalize="off",
             validators=[vlogin, username_validator],
+            pattern=vlogin.rexp.pattern,
+            title=vlogin.msg,
+            required="true",
         ),
         Password(
             'password',
             description=_('Choose a password'),
             klass='required',
             validators=[vpass],
+            minlength="3",
+            maxlength="20",
+            required="true",
         ),
         Checkbox(
             'ia_newsletter',
diff --git a/openlibrary/utils/form.py b/openlibrary/utils/form.py
--- a/openlibrary/utils/form.py
+++ b/openlibrary/utils/form.py
@@ -97,6 +97,17 @@ def get_type(self):
         return "password"
 
 
+class Email(Input):
+    """Email input.
+
+    >>> Email("email", value='joe@archive.org').render()
+    '<input type="email" id="email" value="joe@archive.org" name="email" />'
+    """
+
+    def get_type(self):
+        return "email"
+
+
 class Checkbox(Input):
     """Checkbox input."""
 


Test patch: