Skip to content

Commit 0c9cfbc

Browse files
committed
feat(headless): reflect ACCOUNT_SIGNUP_FORM_CLASS
1 parent e43bd94 commit 0c9cfbc

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

ChangeLog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ Note worthy changes
3636
- Removed inline scripts, so that it becomes possible to use a strong Content
3737
Security Policy.
3838

39+
- Headless: The OpenAPI specification now dynamically reflects the
40+
``ACCOUNT_SIGNUP_FIELDS`` configuration, as well as any custom fields you have
41+
in ``ACCOUNT_SIGNUP_FORM_CLASS``.
42+
3943

4044
Fixes
4145
-----

allauth/headless/spec/internal/schema.py

+37
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from pathlib import Path
22

3+
from django import forms
34
from django.urls import resolve, reverse
45
from django.urls.exceptions import Resolver404
56

67
from allauth.account import app_settings as account_settings
8+
from allauth.account.internal.flows.signup import base_signup_form_class
79
from allauth.headless import app_settings
810

911

@@ -26,6 +28,7 @@ def get_schema() -> dict:
2628
drop_unused_tags(spec, used_tags)
2729
drop_unused_tag_groups(spec, used_tags)
2830
specify_signup_fields(spec)
31+
specify_custom_signup_form(spec)
2932
return spec
3033

3134

@@ -104,3 +107,37 @@ def specify_signup_fields(spec: dict) -> None:
104107
signup["allOf"] = signup["allOf"][:1]
105108
elif not password_field["required"]:
106109
signup["allOf"][1]["required"].remove("password")
110+
111+
112+
def specify_custom_signup_form(spec: dict) -> None:
113+
form_class = base_signup_form_class()
114+
base_signup = spec["components"]["schemas"]["BaseSignup"]
115+
field_mapping = {
116+
forms.CharField: {"type": "string"},
117+
forms.IntegerField: {"type": "integer"},
118+
forms.FloatField: {"type": "number"},
119+
forms.BooleanField: {"type": "boolean"},
120+
forms.DateField: {"type": "string", "format": "date"},
121+
forms.DateTimeField: {"type": "string", "format": "date-time"},
122+
forms.EmailField: {"type": "string", "format": "email"},
123+
forms.URLField: {"type": "string", "format": "uri"},
124+
forms.DecimalField: {
125+
"type": "string",
126+
"format": "decimal",
127+
"pattern": r"^\d+(\.\d+)?$",
128+
},
129+
}
130+
for field_name, field in form_class.base_fields.items():
131+
field_spec = field_mapping.get(type(field), {"type": "string"})
132+
if not field_spec:
133+
continue
134+
field_spec = dict(field_spec)
135+
if hasattr(field, "max_length") and field.max_length:
136+
field_spec["maxLength"] = field.max_length
137+
if hasattr(field, "min_length") and field.min_length:
138+
field_spec["minLength"] = field.min_length
139+
if hasattr(field, "required") and field.required:
140+
base_signup["required"].append(field_name)
141+
if hasattr(field, "help_text") and field.help_text:
142+
field_spec["description"] = field.help_text
143+
base_signup["properties"][field_name] = field_spec

0 commit comments

Comments
 (0)