fastadmin 0.2.20__py3-none-any.whl → 0.2.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastadmin/models/base.py +6 -3
- fastadmin/static/index.min.js +52 -52
- {fastadmin-0.2.20.dist-info → fastadmin-0.2.22.dist-info}/METADATA +86 -18
- {fastadmin-0.2.20.dist-info → fastadmin-0.2.22.dist-info}/RECORD +6 -6
- {fastadmin-0.2.20.dist-info → fastadmin-0.2.22.dist-info}/LICENSE +0 -0
- {fastadmin-0.2.20.dist-info → fastadmin-0.2.22.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: fastadmin
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.22
|
4
4
|
Summary: FastAdmin is an easy-to-use Admin Dashboard App for FastAPI/Flask/Django inspired by Django Admin.
|
5
5
|
License: MIT
|
6
6
|
Keywords: fastapi,admin
|
@@ -475,13 +475,14 @@ Register ORM models
|
|
475
475
|
|
476
476
|
|
477
477
|
```python
|
478
|
+
import typing as tp
|
478
479
|
from uuid import UUID
|
479
480
|
|
480
481
|
import bcrypt
|
481
482
|
from tortoise import fields
|
482
483
|
from tortoise.models import Model
|
483
484
|
|
484
|
-
from fastadmin import TortoiseModelAdmin, register
|
485
|
+
from fastadmin import TortoiseModelAdmin, WidgetType, register
|
485
486
|
|
486
487
|
|
487
488
|
class User(Model):
|
@@ -489,6 +490,7 @@ class User(Model):
|
|
489
490
|
hash_password = fields.CharField(max_length=255)
|
490
491
|
is_superuser = fields.BooleanField(default=False)
|
491
492
|
is_active = fields.BooleanField(default=False)
|
493
|
+
avatar_url = fields.TextField(null=True)
|
492
494
|
|
493
495
|
def __str__(self):
|
494
496
|
return self.username
|
@@ -501,15 +503,39 @@ class UserAdmin(TortoiseModelAdmin):
|
|
501
503
|
list_display_links = ("id", "username")
|
502
504
|
list_filter = ("id", "username", "is_superuser", "is_active")
|
503
505
|
search_fields = ("username",)
|
504
|
-
|
505
|
-
|
506
|
-
|
506
|
+
formfield_overrides = { # noqa: RUF012
|
507
|
+
"username": (WidgetType.SlugInput, {"required": True}),
|
508
|
+
"password": (WidgetType.PasswordInput, {"passwordModalForm": True}),
|
509
|
+
"avatar_url": (
|
510
|
+
WidgetType.Upload,
|
511
|
+
{
|
512
|
+
"required": False,
|
513
|
+
# Disable crop image for upload field
|
514
|
+
# "disableCropImage": True,
|
515
|
+
},
|
516
|
+
),
|
517
|
+
}
|
518
|
+
|
519
|
+
async def authenticate(self, username: str, password: str) -> int | None:
|
520
|
+
user = await self.model_cls.filter(phone=username, is_superuser=True).first()
|
507
521
|
if not user:
|
508
522
|
return None
|
509
523
|
if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
|
510
524
|
return None
|
511
525
|
return user.id
|
512
526
|
|
527
|
+
async def change_password(self, id: UUID | int, password: str) -> None:
|
528
|
+
user = await self.model_cls.filter(id=id).first()
|
529
|
+
if not user:
|
530
|
+
return
|
531
|
+
user.hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
532
|
+
await user.save(update_fields=("hash_password",))
|
533
|
+
|
534
|
+
async def orm_save_upload_field(self, obj: tp.Any, field: str, base64: str) -> None:
|
535
|
+
# convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
|
536
|
+
setattr(obj, field, base64)
|
537
|
+
await obj.save(update_fields=(field,))
|
538
|
+
|
513
539
|
```
|
514
540
|
|
515
541
|
|
@@ -583,8 +609,11 @@ class UserAdmin(DjangoModelAdmin):
|
|
583
609
|
|
584
610
|
|
585
611
|
```python
|
612
|
+
import typing as tp
|
613
|
+
import uuid
|
614
|
+
|
586
615
|
import bcrypt
|
587
|
-
from sqlalchemy import Boolean, Integer, String, select
|
616
|
+
from sqlalchemy import Boolean, Integer, String, Text, select, update
|
588
617
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
589
618
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
590
619
|
|
@@ -609,6 +638,7 @@ class User(Base):
|
|
609
638
|
hash_password: Mapped[str] = mapped_column(String(length=255), nullable=False)
|
610
639
|
is_superuser: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
611
640
|
is_active: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
641
|
+
avatar_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
612
642
|
|
613
643
|
def __str__(self):
|
614
644
|
return self.username
|
@@ -622,17 +652,33 @@ class UserAdmin(SqlAlchemyModelAdmin):
|
|
622
652
|
list_filter = ("id", "username", "is_superuser", "is_active")
|
623
653
|
search_fields = ("username",)
|
624
654
|
|
625
|
-
async def authenticate(self, username, password):
|
655
|
+
async def authenticate(self, username: str, password: str) -> uuid.UUID | int | None:
|
626
656
|
sessionmaker = self.get_sessionmaker()
|
627
657
|
async with sessionmaker() as session:
|
628
|
-
query = select(
|
658
|
+
query = select(self.model_cls).filter_by(username=username, password=password, is_superuser=True)
|
629
659
|
result = await session.scalars(query)
|
630
|
-
|
631
|
-
if not
|
660
|
+
obj = result.first()
|
661
|
+
if not obj:
|
632
662
|
return None
|
633
|
-
if not bcrypt.checkpw(password.encode(),
|
663
|
+
if not bcrypt.checkpw(password.encode(), obj.hash_password.encode()):
|
634
664
|
return None
|
635
|
-
return
|
665
|
+
return obj.id
|
666
|
+
|
667
|
+
async def change_password(self, id: uuid.UUID | int, password: str) -> None:
|
668
|
+
sessionmaker = self.get_sessionmaker()
|
669
|
+
async with sessionmaker() as session:
|
670
|
+
hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
671
|
+
query = update(self.model_cls).where(User.id.in_([id])).values(hash_password=hash_password)
|
672
|
+
await session.execute(query)
|
673
|
+
await session.commit()
|
674
|
+
|
675
|
+
async def orm_save_upload_field(self, obj: tp.Any, field: str, base64: str) -> None:
|
676
|
+
sessionmaker = self.get_sessionmaker()
|
677
|
+
async with sessionmaker() as session:
|
678
|
+
# convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
|
679
|
+
query = update(self.model_cls).where(User.id.in_([obj.id])).values(**{field: base64})
|
680
|
+
await session.execute(query)
|
681
|
+
await session.commit()
|
636
682
|
|
637
683
|
```
|
638
684
|
|
@@ -655,8 +701,11 @@ class UserAdmin(SqlAlchemyModelAdmin):
|
|
655
701
|
|
656
702
|
|
657
703
|
```python
|
704
|
+
import typing as tp
|
705
|
+
import uuid
|
706
|
+
|
658
707
|
import bcrypt
|
659
|
-
from pony.orm import Database, PrimaryKey, Required, db_session
|
708
|
+
from pony.orm import Database, LongStr, Optional, PrimaryKey, Required, commit, db_session
|
660
709
|
|
661
710
|
from fastadmin import PonyORMModelAdmin, register
|
662
711
|
|
@@ -671,6 +720,7 @@ class User(db.Entity): # type: ignore [name-defined]
|
|
671
720
|
hash_password = Required(str)
|
672
721
|
is_superuser = Required(bool, default=False)
|
673
722
|
is_active = Required(bool, default=False)
|
723
|
+
avatar_url = Optional(LongStr, nullable=True)
|
674
724
|
|
675
725
|
def __str__(self):
|
676
726
|
return self.username
|
@@ -685,13 +735,31 @@ class UserAdmin(PonyORMModelAdmin):
|
|
685
735
|
search_fields = ("username",)
|
686
736
|
|
687
737
|
@db_session
|
688
|
-
def authenticate(self, username, password):
|
689
|
-
|
690
|
-
if not
|
738
|
+
def authenticate(self, username: str, password: str) -> uuid.UUID | int | None:
|
739
|
+
obj = next((f for f in User.select(username=username, password=password, is_superuser=True)), None) # fmt: skip
|
740
|
+
if not obj:
|
691
741
|
return None
|
692
|
-
if not bcrypt.checkpw(password.encode(),
|
742
|
+
if not bcrypt.checkpw(password.encode(), obj.hash_password.encode()):
|
693
743
|
return None
|
694
|
-
return
|
744
|
+
return obj.id
|
745
|
+
|
746
|
+
@db_session
|
747
|
+
def change_password(self, id: uuid.UUID | int, password: str) -> None:
|
748
|
+
obj = next((f for f in self.model_cls.select(id=id)), None)
|
749
|
+
if not obj:
|
750
|
+
return
|
751
|
+
hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
752
|
+
obj.hash_password = hash_password
|
753
|
+
commit()
|
754
|
+
|
755
|
+
@db_session
|
756
|
+
def orm_save_upload_field(self, obj: tp.Any, field: str, base64: str) -> None:
|
757
|
+
obj = next((f for f in self.model_cls.select(id=obj.id)), None)
|
758
|
+
if not obj:
|
759
|
+
return
|
760
|
+
# convert base64 to bytes, upload to s3/filestorage, get url and save or save base64 as is to db (don't recomment it)
|
761
|
+
setattr(obj, field, base64)
|
762
|
+
commit()
|
695
763
|
|
696
764
|
```
|
697
765
|
|
@@ -19,7 +19,7 @@ fastadmin/api/helpers.py,sha256=Tj0xMW-RHhQtnT-tOgEerIFcks3dCxGFj4etHMkKPwo,2322
|
|
19
19
|
fastadmin/api/schemas.py,sha256=5eYJDGrSrvy0YdB8vak0zPv-a51a36CYJ_RVA2vgTKU,1348
|
20
20
|
fastadmin/api/service.py,sha256=TGVb4HS80IC0QpdN-qbDqaqbaI-H769EHCE-HHEd2Lo,18174
|
21
21
|
fastadmin/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
fastadmin/models/base.py,sha256=
|
22
|
+
fastadmin/models/base.py,sha256=u8qw07QVpKdph3vqAB4mtKhYmtps0UOZWMVEAi7Kks0,27885
|
23
23
|
fastadmin/models/decorators.py,sha256=KtfUBoiDJGbUGVgw4LZS7YdgqlEzHvA1mhXynnJ3-jg,2877
|
24
24
|
fastadmin/models/helpers.py,sha256=CBQhkwgzhtdPkkMLiHhuQUBrmG539ceDI1EiqdTdhn0,14761
|
25
25
|
fastadmin/models/orms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -40,9 +40,9 @@ fastadmin/static/images/header-logo.svg,sha256=FfFOShL7p4EvggDS106VDcMzI_Oe7zAG7
|
|
40
40
|
fastadmin/static/images/sign-in-logo.svg,sha256=sD6YXIwT0kOvZTCGxyoUMiIoszXV77OBxFLvlZOYEeE,1359
|
41
41
|
fastadmin/static/index.html,sha256=J6YYi1W7Y-YHlAfdTjy4KOd_yMZy-UWMJZAFDe78eAI,613
|
42
42
|
fastadmin/static/index.min.css,sha256=wLq82YRWuzAgSDLc92AzsDhWUuP94F4y7AlayA3fd5U,72109
|
43
|
-
fastadmin/static/index.min.js,sha256=
|
43
|
+
fastadmin/static/index.min.js,sha256=E6B5aPBPVYvLhJ5yIEtU_wvDaEdXiKQZEr6Cm84XiZ4,3270501
|
44
44
|
fastadmin/templates/index.html,sha256=WHIAqNmtJ_fHMgYrMHkUwsYxt4Xo6yMrieDODKDCN9Q,719
|
45
|
-
fastadmin-0.2.
|
46
|
-
fastadmin-0.2.
|
47
|
-
fastadmin-0.2.
|
48
|
-
fastadmin-0.2.
|
45
|
+
fastadmin-0.2.22.dist-info/LICENSE,sha256=-5Cmq6xd5DlFq8rhBcqGMi8Mlh_h-YVjKOYjnYk5dyM,1063
|
46
|
+
fastadmin-0.2.22.dist-info/METADATA,sha256=46Riio3lGEl3XoXgGJ8jxmnOJR-LxJfe-DSEFQDSVGI,14898
|
47
|
+
fastadmin-0.2.22.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
48
|
+
fastadmin-0.2.22.dist-info/RECORD,,
|
File without changes
|
File without changes
|