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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastadmin
3
- Version: 0.2.20
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
- async def authenticate(self, username: str, password: str) -> UUID | int | None:
506
- user = await User.filter(username=username, is_superuser=True).first()
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(User).filter_by(username=username, password=password, is_superuser=True)
658
+ query = select(self.model_cls).filter_by(username=username, password=password, is_superuser=True)
629
659
  result = await session.scalars(query)
630
- user = result.first()
631
- if not user:
660
+ obj = result.first()
661
+ if not obj:
632
662
  return None
633
- if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
663
+ if not bcrypt.checkpw(password.encode(), obj.hash_password.encode()):
634
664
  return None
635
- return user.id
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
- user = next((f for f in self.model_cls.select(username=username, password=password, is_superuser=True)), None)
690
- if not user:
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(), user.hash_password.encode()):
742
+ if not bcrypt.checkpw(password.encode(), obj.hash_password.encode()):
693
743
  return None
694
- return user.id
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=KkQq8r2Tni5IfxLlHHH4DmDIeMylTV4wTxvedb6qxe8,27697
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=C8lz6Mdx9XZwlq7q9dcbNe0hvbsPexDL81FtSjtrKxc,3270358
43
+ fastadmin/static/index.min.js,sha256=E6B5aPBPVYvLhJ5yIEtU_wvDaEdXiKQZEr6Cm84XiZ4,3270501
44
44
  fastadmin/templates/index.html,sha256=WHIAqNmtJ_fHMgYrMHkUwsYxt4Xo6yMrieDODKDCN9Q,719
45
- fastadmin-0.2.20.dist-info/LICENSE,sha256=-5Cmq6xd5DlFq8rhBcqGMi8Mlh_h-YVjKOYjnYk5dyM,1063
46
- fastadmin-0.2.20.dist-info/METADATA,sha256=mkZC4z3vWBNhI7Yrh_wkTo3xMS54vOJj5M_BSOwCorM,11813
47
- fastadmin-0.2.20.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
48
- fastadmin-0.2.20.dist-info/RECORD,,
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,,