aboutsummaryrefslogtreecommitdiff
path: root/webmentions_ssg/forms
diff options
context:
space:
mode:
authorDennis Fink2026-08-20 23:01:59 +0200
committerDennis Fink2026-08-20 23:01:59 +0200
commit5bfcc3c06ebe6d6694221c25f07a4901572f97f5 (patch)
treefd3e9e0c8dfbde16bf96095809a765491c6d0c98 /webmentions_ssg/forms
parent12b8c4b7f1d14556cc459f672b501e901da2d216 (diff)
downloadwebmentions-ssg-5bfcc3c06ebe6d6694221c25f07a4901572f97f5.tar.gz
webmentions-ssg-5bfcc3c06ebe6d6694221c25f07a4901572f97f5.zip
docs(core): add docstrings and type annotations
Document forms, validators, models, and views with PEP 287-style docstrings and complete missing type annotations. Add developer-readable representations for Webmention models and mark the user password property as write-only in its return type.
Diffstat (limited to '')
-rw-r--r--webmentions_ssg/forms/__init__.py15
-rw-r--r--webmentions_ssg/forms/validators.py88
2 files changed, 80 insertions, 23 deletions
diff --git a/webmentions_ssg/forms/__init__.py b/webmentions_ssg/forms/__init__.py
index 7ab82e3..5d2f827 100644
--- a/webmentions_ssg/forms/__init__.py
+++ b/webmentions_ssg/forms/__init__.py
@@ -12,12 +12,23 @@ from .validators import AllowedHostname, NotEqualTo, PublicURL
class LoginForm(FlaskForm):
+ """
+ Form for authenticating a user.
+ """
+
username = StringField("Username", validators=[InputRequired()])
password = PasswordField("Password", validators=[InputRequired()])
submit = SubmitField("Sign In")
class EndpointForm(FlaskForm):
+ """
+ Form for receiving a Webmention.
+
+ The source must be a public HTTP or HTTPS URL distinct from the target.
+ The target must be an HTTP or HTTPS URL using an allowed hostname.
+ """
+
source = StringField(
"source",
validators=[
@@ -48,4 +59,8 @@ class EndpointForm(FlaskForm):
class AdminActionForm(FlaskForm):
+ """
+ Form for confirming an administrative action.
+ """
+
submit = SubmitField("Confirm")
diff --git a/webmentions_ssg/forms/validators.py b/webmentions_ssg/forms/validators.py
index fd54e0f..761dc46 100644
--- a/webmentions_ssg/forms/validators.py
+++ b/webmentions_ssg/forms/validators.py
@@ -5,28 +5,39 @@
from urllib.parse import urlsplit
from flask import current_app
-from wtforms import ValidationError
+from wtforms import Field, ValidationError
+from wtforms.form import BaseForm
from ..url_security import AddressResolutionError, is_public_url
class NotEqualTo:
"""
- Compares the values of two fields.
+ Validate that a field does not equal another field.
- :param fieldname:
- The name of the other field to compare to.
- :param message:
- Error message to raise in case of a validation error. Can be
- interpolated with `%(other_label)s` and `%(other_name)s` to provide a
- more helpful error.
+ :param fieldname: Name of the field to compare against.
+ :param message: Optional validation error message.
"""
- def __init__(self, fieldname, message=None):
+ def __init__(self, fieldname: str, message: str | None = None) -> None:
+ """
+ Initialize the validator.
+
+ :param fieldname: Name of the field to compare against.
+ :param message: Optional validation error message.
+ """
self.fieldname = fieldname
self.message = message
- def __call__(self, form, field):
+ def __call__(self, form: BaseForm, field: Field) -> None:
+ """
+ Validate that two fields do not contain equal values.
+
+ :param form: Form containing the fields to compare.
+ :param field: Field being validated.
+ :raises ValidationError: If the comparison field does not exist or both
+ fields contain equal values.
+ """
try:
other = form[self.fieldname]
except KeyError as exc:
@@ -43,36 +54,67 @@ class NotEqualTo:
or self.fieldname,
"other_name": self.fieldname,
}
- message = self.message
- if message is None:
- message = field.gettext("Field must not be equal to %(other_name)s.")
-
+ message = self.message or field.gettext(
+ "Field must not be equal to %(other_name)s."
+ )
raise ValidationError(message % d)
class AllowedHostname:
- def __init__(self, message=None):
+ """
+ Validate that a URL uses an allowed hostname.
+
+ :param message: Optional validation error message.
+ """
+
+ def __init__(self, message: str | None = None) -> None:
+ """
+ Initialize the validator.
+
+ :param message: Optional validation error message.
+ """
self.message = message
- def __call__(self, form, field):
+ def __call__(self, form: BaseForm, field: Field) -> None:
+ """
+ Validate that a URL uses an allowed hostname.
+
+ :param form: Form containing the field.
+ :param field: Field containing the URL to validate.
+ :raises ValidationError: If the URL hostname is not configured as allowed.
+ """
if (
urlsplit(field.data).hostname
in current_app.config["WEBMENTIONS_SSG_ALLOWED_HOSTNAMES"]
):
return
+ raise ValidationError(self.message or field.gettext("Invalid input."))
- message = self.message
- if self.message is None:
- message = field.gettext("Invalid input.")
- raise ValidationError(message)
+class PublicURL:
+ """
+ Validate that a URL resolves exclusively to public IP addresses.
+ :param message: Optional validation error message.
+ """
-class PublicURL:
- def __init__(self, message=None):
+ def __init__(self, message: str | None = None) -> None:
+ """
+ Initialize the validator.
+
+ :param message: Optional validation error message.
+ """
self.message = message
- def __call__(self, form, field):
+ def __call__(self, form: BaseForm, field: Field) -> None:
+ """
+ Validate that a URL resolves exclusively to public IP addresses.
+
+ :param form: Form containing the field.
+ :param field: Field containing the URL to validate.
+ :raises ValidationError: If the URL cannot be resolved, has no hostname, or
+ resolves to a non-public address.
+ """
message = self.message
if message is None: