#2260 frontend: remove leading and trailing whitespace from StringField
Merged 2 years ago by praiskup. Opened 2 years ago by frostyx.
copr/ frostyx/copr wtforms-whitespace  into  main

@@ -447,7 +447,41 @@ 

          return value

  

  

- class CoprBaseForm(FlaskForm):

+ class BaseForm(FlaskForm):

+     """

+     Base class for all of our forms. For example, WTForms doesn't automatically

+     remove leading and trailing whitespace from fields, which causes nasty

+     bugs like #2223

+     """

+     class Meta:

+         # pylint: disable=missing-class-docstring

+         # pylint: disable=missing-function-docstring

+         # pylint: disable=no-self-use

+ 

+         def bind_field(self, form, unbound_field, options):

+             filters = unbound_field.kwargs.get("filters", [])

+ 

+             # It doesn't make sense to strip whitespace for BooleanField,

+             # IntegerField, etc. But we don't want to strip whitespace from

+             # TextAreaField either, because we want to preserve \n at their end.

+             # We also get custom scripts via TextAreaField and we ideally don't

+             # want to modify them at all

+             if unbound_field.field_class == wtforms.StringField:

+                 filters.append(strip_whitespace_filter)

+ 

+             return unbound_field.bind(form=form, filters=filters, **options)

+ 

+ 

+ def strip_whitespace_filter(value):

+     """

+     Remove leading and trailing whitespace from a field

+     """

+     if value is not None and hasattr(value, "strip"):

+         return value.strip()

+     return value

+ 

+ 

+ class CoprBaseForm(BaseForm):

      """

      All forms that modify Copr project should inherit from this.

      """
@@ -472,7 +506,7 @@ 

          ])

  

  

- class CoprForm(FlaskForm):

+ class CoprForm(BaseForm):

      """

      Base form class for adding and modifying projects

      """
@@ -700,7 +734,7 @@ 

          return F

  

  

- class CoprDeleteForm(FlaskForm):

+ class CoprDeleteForm(BaseForm):

      verify = wtforms.StringField(

          "Confirm deleting by typing 'yes'",

          validators=[
@@ -725,7 +759,7 @@ 

      # TODO: drop, and use _get_build_form directly

      @staticmethod

      def create_form_cls(active_chroots):

-         return _get_build_form(active_chroots, FlaskForm)

+         return _get_build_form(active_chroots, BaseForm)

  

  

  class RebuildPackageFactory(object):
@@ -772,7 +806,7 @@ 

                  raise wtforms.ValidationError('patterns are deny-listing all chroots')

  

  

- class BasePackageForm(FlaskForm):

+ class BasePackageForm(BaseForm):

      package_name_regex = r"^[-+_.a-zA-Z0-9]+$"

  

      package_name = wtforms.StringField(
@@ -1137,7 +1171,7 @@ 

  

  class RebuildAllPackagesFormFactory(object):

      def __new__(cls, active_chroots, package_names):

-         form_cls = _get_build_form(active_chroots, FlaskForm)

+         form_cls = _get_build_form(active_chroots, BaseForm)

          form_cls.packages = MultiCheckboxField(

              "Packages",

              choices=[(name, name) for name in package_names],
@@ -1286,7 +1320,7 @@ 

  

  class BuildFormUploadFactory(object):

      def __new__(cls, active_chroots):

-         form = _get_build_form(active_chroots, FlaskForm)

+         form = _get_build_form(active_chroots, BaseForm)

          form.pkgs = FileField('srpm', validators=[

              FileRequired(),

              SrpmValidator()])
@@ -1308,7 +1342,7 @@ 

  

  class BuildFormUrlFactory(object):

      def __new__(cls, active_chroots):

-         form = _get_build_form(active_chroots, FlaskForm)

+         form = _get_build_form(active_chroots, BaseForm)

          form.pkgs = wtforms.TextAreaField(

              "Pkgs",

              validators=[
@@ -1319,7 +1353,7 @@ 

          return form

  

  

- class ModuleFormUploadFactory(FlaskForm):

+ class ModuleFormUploadFactory(BaseForm):

      modulemd = FileField("modulemd", validators=[

          FileRequired(),

          # @TODO Validate modulemd.yaml file
@@ -1330,7 +1364,7 @@ 

  

  

  def get_module_build_form(*args, **kwargs):

-     class ModuleBuildForm(FlaskForm):

+     class ModuleBuildForm(BaseForm):

          modulemd = FileField("modulemd")

          scmurl = wtforms.StringField()

          branch = wtforms.StringField()
@@ -1340,7 +1374,7 @@ 

      return ModuleBuildForm(*args, **kwargs)

  

  

- class PagureIntegrationForm(FlaskForm):

+ class PagureIntegrationForm(BaseForm):

      repo_url = wtforms.StringField("repo_url", default='')

      api_key = wtforms.StringField("api_key", default='')

  
@@ -1352,7 +1386,7 @@ 

              self.repo_url.data = repo_url

  

  

- class ChrootForm(FlaskForm):

+ class ChrootForm(BaseForm):

  

      """

      Validator for editing chroots in project
@@ -1392,14 +1426,14 @@ 

          return result

  

  

- class CoprChrootExtend(FlaskForm):

+ class CoprChrootExtend(BaseForm):

      extend = wtforms.StringField("Chroot name")

      expire = wtforms.StringField("Chroot name")

      ownername = wtforms.HiddenField("Owner name")

      projectname = wtforms.HiddenField("Project name")

  

  

- class CoprLegalFlagForm(FlaskForm):

+ class CoprLegalFlagForm(BaseForm):

      comment = wtforms.TextAreaField("Comment")

  

  
@@ -1407,7 +1441,7 @@ 

  

      @staticmethod

      def create_form_cls(permission=None):

-         class F(FlaskForm):

+         class F(BaseForm):

              pass

  

          builder_default = False
@@ -1439,7 +1473,7 @@ 

      """Creates a dynamic form for given set of copr permissions"""

      @staticmethod

      def create_form_cls(permissions):

-         class F(FlaskForm):

+         class F(BaseForm):

              pass

  

          for perm in permissions:
@@ -1467,7 +1501,7 @@ 

  class CoprForkFormFactory(object):

      @staticmethod

      def create_form_cls(copr, user, groups):

-         class F(FlaskForm):

+         class F(BaseForm):

              source = wtforms.StringField(

                  "Source",

                  default=copr.full_name)
@@ -1510,7 +1544,7 @@ 

          pass

  

  

- class PinnedCoprsForm(FlaskForm):

+ class PinnedCoprsForm(BaseForm):

      copr_ids = SelectMultipleFieldNoValidation(wtforms.IntegerField("Pinned Copr ID"))

  

      def __init__(self, owner, *args, **kwargs):
@@ -1537,7 +1571,7 @@ 

          return True

  

  

- class VoteForCopr(FlaskForm):

+ class VoteForCopr(BaseForm):

      """

      Form for upvoting and downvoting projects

      """
@@ -1546,11 +1580,11 @@ 

      reset = wtforms.SubmitField("Reset vote")

  

  

- class AdminPlaygroundForm(FlaskForm):

+ class AdminPlaygroundForm(BaseForm):

      playground = wtforms.BooleanField("Playground", false_values=FALSE_VALUES)

  

  

- class AdminPlaygroundSearchForm(FlaskForm):

+ class AdminPlaygroundSearchForm(BaseForm):

      project = wtforms.StringField("Project")

  

  
@@ -1566,7 +1600,7 @@ 

              raise wtforms.ValidationError(self.message.format(field.data))

  

  

- class ActivateFasGroupForm(FlaskForm):

+ class ActivateFasGroupForm(BaseForm):

  

      name = wtforms.StringField(

          validators=[
@@ -1579,7 +1613,7 @@ 

      )

  

  

- class CreateModuleForm(FlaskForm):

+ class CreateModuleForm(BaseForm):

      builds = wtforms.FieldList(wtforms.StringField("Builds ID list"))

      packages = wtforms.FieldList(wtforms.StringField("Packages list"))

      components = wtforms.FieldList(
@@ -1597,7 +1631,7 @@ 

          super(CreateModuleForm, self).__init__(*args, **kwargs)

  

      def validate(self):

-         if not FlaskForm.validate(self):

+         if not BaseForm.validate(self):

              return False

  

          # Profile names should be unique
@@ -1618,7 +1652,7 @@ 

          return True

  

  

- class ModuleRepo(FlaskForm):

+ class ModuleRepo(BaseForm):

      owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()])

      copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()])

      name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()])

Fix #2223

WTForms doesn't automatically remove leading and trailing whitespace
from fields, and AFAIK doesn't provide any built-in filter or option
for doing so.

This seems to be the common way how people of the internet are solving
this issue for themselves.

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci

rebased onto d39aa8d2ad07eb84ea9a4bde8144169d228e803f

2 years ago

Build succeeded.

rebased onto 5208386

2 years ago

Pull-Request has been merged by praiskup

2 years ago

Build succeeded.

Metadata