Add password auto hash.

`Field` description as help text for form.
This commit is contained in:
long2ice
2020-06-20 14:48:06 +08:00
parent d275de375f
commit 821f5cbe8a
7 changed files with 38 additions and 27 deletions

View File

@@ -4,6 +4,12 @@ ChangeLog
0.2
===
0.2.8
-----
- Add password auto hash.
- `Field` description as help text for form.
0.2.7
-----
- Add custom login_view.

View File

@@ -210,10 +210,10 @@ class Status(EnumMixin, IntEnum):
}
```
### Verbose Name
### Help Text
FastAPI-Admin will auto read `description` defined in tortoise-orm model
`Field` and display in front.
`Field` and display in front with form help text.
### ForeignKeyField Support

View File

@@ -51,7 +51,6 @@ async def start_up():
locale_switcher=True,
theme_switcher=True,
),
login_view="examples.routes.login",
)

View File

@@ -6,9 +6,12 @@ from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
async def handle_m2m_fields_create_or_update(body, m2m_fields, model, create=True, pk=None):
async def handle_m2m_fields_create_or_update(
body, m2m_fields, model, user_model, create=True, pk=None
):
"""
handle m2m update or create
:param user_model:
:param body:
:param m2m_fields:
:param model:
@@ -17,6 +20,8 @@ async def handle_m2m_fields_create_or_update(body, m2m_fields, model, create=Tru
:return:
"""
copy_body = deepcopy(body)
if model == user_model:
copy_body["password"] = pwd_context.hash(copy_body.pop("password"))
m2m_body = {}
for k, v in body.items():
if k in m2m_fields:

View File

@@ -113,11 +113,7 @@ class AdminApp(FastAPI):
permission_menus = [
Menu(name="Auth", title=True),
Menu(
name="User",
url="/rest/User",
icon="fa fa-user",
exclude=("password",),
search_fields=("username",),
name="User", url="/rest/User", icon="fa fa-user", search_fields=("username",),
),
Menu(name="Role", url="/rest/Role", icon="fa fa-group", actions={"delete": False}),
Menu(
@@ -221,15 +217,15 @@ class AdminApp(FastAPI):
fields = {}
pk = name = pk_field.get("name")
if not exclude_pk and not self._exclude_field(resource, name):
fields = {
name: Field(
label=pk_field.get("name").title(),
required=True,
type=self._get_field_type(name, pk_field.get("field_type").__name__, menu),
sortable=name in sort_fields,
**menu.attrs.get(name) or {},
)
}
field = Field(
label=pk_field.get("name").title(),
required=True,
type=self._get_field_type(name, pk_field.get("field_type").__name__, menu),
sortable=name in sort_fields,
description=pk_field.get("description"),
)
field = field.copy(update=menu.attrs.get(name) or {})
fields = {name: field}
if not exclude_actions and menu.actions:
fields["_actions"] = menu.actions
@@ -246,7 +242,7 @@ class AdminApp(FastAPI):
for k, v in model._meta.fields_map[name].enum_type.choices().items():
options.append({"text": v, "value": k})
label = data_field.get("description") or data_field.get("name").title()
label = data_field.get("name").title()
field = Field(
label=label,
required=not data_field.get("nullable"),
@@ -254,8 +250,9 @@ class AdminApp(FastAPI):
options=options,
sortable=name in sort_fields,
disabled=readonly,
**menu.attrs.get(name) or {},
description=data_field.get("description"),
)
field = field.copy(update=menu.attrs.get(name) or {})
fields[name] = field
if name in search_fields:
search_fields_ret[name] = field
@@ -267,7 +264,7 @@ class AdminApp(FastAPI):
fk_model_class = fk_field.get("python_type")
objs = await fk_model_class.all()
raw_field = fk_field.get("raw_field")
label = fk_field.get("description") or name.title()
label = name.title()
options = list(map(lambda x: {"text": str(x), "value": x.pk}, objs))
field = Field(
label=label,
@@ -275,8 +272,9 @@ class AdminApp(FastAPI):
type="select",
options=options,
sortable=name in sort_fields,
**menu.attrs.get(name) or {},
description=fk_field.get("description"),
)
field = field.copy(update=menu.attrs.get(name) or {})
fields[raw_field] = field
if name in search_fields:
search_fields_ret[raw_field] = field
@@ -284,7 +282,7 @@ class AdminApp(FastAPI):
for m2m_field in m2m_fields:
name = m2m_field.get("name")
if not self._exclude_field(resource, name):
label = m2m_field.get("description") or name.title()
label = name.title()
m2m_model_class = m2m_field.get("python_type")
objs = await m2m_model_class.all()
options = list(map(lambda x: {"text": str(x), "value": x.pk}, objs))
@@ -293,6 +291,7 @@ class AdminApp(FastAPI):
type="tree",
options=options,
multiple=True,
description=m2m_field.get("description"),
**menu.attrs.get(name) or {},
)
return pk, fields, search_fields_ret

View File

@@ -5,7 +5,7 @@ from fastapi_admin import enums
class User(Model):
username = fields.CharField(max_length=20, unique=True)
password = fields.CharField(max_length=200)
password = fields.CharField(max_length=200, description="Will auto hash with raw password")
class Meta:
abstract = True
@@ -15,7 +15,7 @@ class Permission(Model):
label = fields.CharField(max_length=50)
model = fields.CharField(max_length=50)
action: enums.PermissionAction = fields.IntEnumField(
enums.PermissionAction, default=enums.PermissionAction.read, description="Permission Action"
enums.PermissionAction, default=enums.PermissionAction.read
)
def __str__(self):

View File

@@ -120,7 +120,9 @@ async def update_one(id: int, parsed=Depends(parse_body), model=Depends(get_mode
body, resource_fields = parsed
m2m_fields = model._meta.m2m_fields
try:
obj = await handle_m2m_fields_create_or_update(body, m2m_fields, model, False, id)
obj = await handle_m2m_fields_create_or_update(
body, m2m_fields, model, app.user_model, False, id
)
except IntegrityError as e:
return UJSONResponse(
status_code=HTTP_409_CONFLICT, content=dict(message=f"Update Error,{e}")
@@ -135,7 +137,7 @@ async def create_one(parsed=Depends(parse_body), model=Depends(get_model)):
m2m_fields = model._meta.m2m_fields
creator = pydantic_model_creator(model, include=resource_fields, exclude=m2m_fields)
try:
obj = await handle_m2m_fields_create_or_update(body, m2m_fields, model)
obj = await handle_m2m_fields_create_or_update(body, m2m_fields, model, app.user_model)
except IntegrityError as e:
return UJSONResponse(
status_code=HTTP_409_CONFLICT, content=dict(message=f"Create Error,{e}")