Skip to content

Commit d86a51c

Browse files
authored
Merge pull request #167 from mekanix/user-safe
Make UserSafe without password
2 parents c71f924 + d879c4d commit d86a51c

File tree

10 files changed

+69
-55
lines changed

10 files changed

+69
-55
lines changed

freenit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.3.11"
1+
__version__ = "0.3.12"

freenit/api/auth/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from freenit.config import getConfig
99
from freenit.mail import sendmail
1010
from freenit.models.user import User
11+
from freenit.models.safe import UserSafe
1112

1213
config = getConfig()
1314

@@ -23,7 +24,7 @@ class TokenExpire(pydantic.BaseModel):
2324

2425

2526
class LoginResponse(pydantic.BaseModel):
26-
user: User
27+
user: UserSafe
2728
expire: TokenExpire
2829

2930

@@ -48,7 +49,6 @@ async def login(credentials: LoginInput, response: Response):
4849
httponly=True,
4950
secure=config.auth.secure,
5051
)
51-
user.password = None
5252
return {
5353
"user": user,
5454
"expire": {
@@ -78,7 +78,6 @@ async def register_sql(credentials: LoginInput) -> User:
7878
active=False,
7979
)
8080
await user.save()
81-
user.password = None
8281
return user
8382

8483

@@ -106,7 +105,7 @@ async def register(credentials: LoginInput, host=Header(default="")):
106105
return {"status": True}
107106

108107

109-
@api.post("/auth/verify", response_model=User, tags=["auth"])
108+
@api.post("/auth/verify", response_model=UserSafe, tags=["auth"])
110109
async def verify(verification: Verification):
111110
user = await decode(verification.verification)
112111
await user.update(active=True)
@@ -118,7 +117,6 @@ async def refresh(request: Request, response: Response):
118117
user = await authorize(request, cookie="refresh")
119118
access = encode(user)
120119
response.set_cookie("access", access, httponly=True, secure=config.auth.secure)
121-
user.password = None
122120
return {
123121
"user": user,
124122
"expire": {

freenit/api/role/sql.py

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from freenit.decorators import description
77
from freenit.models.pagination import Page, paginate
88
from freenit.models.role import Role, RoleOptional
9+
from freenit.models.safe import RoleSafe, UserSafe
910
from freenit.models.user import User
1011
from freenit.permissions import role_perms
1112

@@ -20,49 +21,49 @@ async def get(
2021
page: int = Header(default=1),
2122
perpage: int = Header(default=10),
2223
_: User = Depends(role_perms),
23-
) -> Page[Role]:
24-
return await paginate(
25-
Role.objects.select_related("users").exclude_fields("users__password"),
24+
) -> Page[RoleSafe]:
25+
ret = await paginate(
26+
Role.objects.select_related("users"),
2627
page,
2728
perpage,
2829
)
30+
return ret
2931

3032
@staticmethod
31-
async def post(role: Role, _: User = Depends(role_perms)) -> Role:
33+
async def post(role: Role, _: User = Depends(role_perms)) -> RoleSafe:
3234
await role.save()
35+
await role.load_all()
3336
return role
3437

3538

3639
@route("/roles/{id}", tags=tags)
3740
class RoleDetailAPI:
3841
@staticmethod
39-
async def get(id, _: User = Depends(role_perms)) -> Role:
42+
async def get(id, _: User = Depends(role_perms)) -> RoleSafe:
4043
try:
41-
role = (
42-
await Role.objects.select_related("users")
43-
.exclude_fields("users__password")
44-
.get(pk=id)
45-
)
44+
role = await Role.objects.select_related("users").get(pk=id)
4645
except ormar.exceptions.NoMatch:
4746
raise HTTPException(status_code=404, detail="No such role")
47+
await role.load_all()
4848
return role
4949

5050
@staticmethod
51-
async def patch(id, role_data: RoleOptional, _: User = Depends(role_perms)) -> Role:
51+
async def patch(id, role_data: RoleOptional, _: User = Depends(role_perms)) -> RoleSafe:
5252
if Role.dbtype() == "sql":
5353
try:
5454
role = await Role.objects.get(pk=id)
5555
except ormar.exceptions.NoMatch:
5656
raise HTTPException(status_code=404, detail="No such role")
5757
await role.patch(role_data)
58+
await role.load_all()
5859
return role
5960
raise HTTPException(
6061
status_code=409,
6162
detail=f"Role type {Role.dbtype()} doesn't support PATCH method",
6263
)
6364

6465
@staticmethod
65-
async def delete(id, _: User = Depends(role_perms)) -> Role:
66+
async def delete(id, _: User = Depends(role_perms)) -> RoleSafe:
6667
try:
6768
role = await Role.objects.get(pk=id)
6869
except ormar.exceptions.NoMatch:
@@ -75,13 +76,9 @@ async def delete(id, _: User = Depends(role_perms)) -> Role:
7576
class RoleUserAPI:
7677
@staticmethod
7778
@description("Assign user to role")
78-
async def post(role_id, user_id, _: User = Depends(role_perms)) -> User:
79+
async def post(role_id, user_id, _: User = Depends(role_perms)) -> UserSafe:
7980
try:
80-
user = (
81-
await User.objects.select_related("roles")
82-
.exclude_fields("password")
83-
.get(pk=user_id)
84-
)
81+
user = await User.objects.select_related("roles").get(pk=user_id)
8582
except ormar.exceptions.NoMatch:
8683
raise HTTPException(status_code=404, detail="No such user")
8784
for role in user.roles:
@@ -96,13 +93,9 @@ async def post(role_id, user_id, _: User = Depends(role_perms)) -> User:
9693

9794
@staticmethod
9895
@description("Deassign user to role")
99-
async def delete(role_id, user_id, _: User = Depends(role_perms)) -> User:
96+
async def delete(role_id, user_id, _: User = Depends(role_perms)) -> UserSafe:
10097
try:
101-
user = (
102-
await User.objects.select_related("roles")
103-
.exclude_fields("password")
104-
.get(pk=user_id)
105-
)
98+
user = await User.objects.select_related("roles").get(pk=user_id)
10699
except ormar.exceptions.NoMatch:
107100
raise HTTPException(status_code=404, detail="No such user")
108101
try:

freenit/api/user/sql.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from freenit.decorators import description
99
from freenit.models.pagination import Page, paginate
1010
from freenit.models.user import User, UserOptional
11+
from freenit.models.safe import UserSafe
1112
from freenit.permissions import profile_perms, user_perms
1213

1314
tags = ["user"]
@@ -23,9 +24,9 @@ async def get(
2324
page: int = Header(default=1),
2425
perpage: int = Header(default=10),
2526
_: User = Depends(user_perms),
26-
) -> Page[User]:
27+
) -> Page[UserSafe]:
2728
return await paginate(
28-
User.objects.select_related("roles").exclude_fields("password"),
29+
User.objects.select_related(["roles"]),
2930
page,
3031
perpage,
3132
)
@@ -34,19 +35,15 @@ async def get(
3435
@route("/users/{id}", tags=tags)
3536
class UserDetailAPI:
3637
@staticmethod
37-
async def get(id, _: User = Depends(user_perms)) -> User:
38+
async def get(id, _: User = Depends(user_perms)) -> UserSafe:
3839
try:
39-
user = (
40-
await User.objects.select_related("roles")
41-
.exclude_fields("password")
42-
.get(pk=id)
43-
)
40+
user = await User.objects.select_related("roles").get(pk=id)
4441
except ormar.exceptions.NoMatch:
4542
raise HTTPException(status_code=404, detail="No such user")
4643
return user
4744

4845
@staticmethod
49-
async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> User:
46+
async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> UserSafe:
5047
if data.password:
5148
data.password = encrypt(data.password)
5249
try:
@@ -57,7 +54,7 @@ async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> User:
5754
return user
5855

5956
@staticmethod
60-
async def delete(id, _: User = Depends(user_perms)) -> User:
57+
async def delete(id, _: User = Depends(user_perms)) -> UserSafe:
6158
try:
6259
user = await User.objects.get(pk=id)
6360
except ormar.exceptions.NoMatch:
@@ -70,15 +67,13 @@ async def delete(id, _: User = Depends(user_perms)) -> User:
7067
class ProfileDetailAPI:
7168
@staticmethod
7269
@description("Get my profile")
73-
async def get(user: User = Depends(profile_perms)) -> User:
70+
async def get(user: User = Depends(profile_perms)) -> UserSafe:
7471
await user.load_all()
7572
return user
7673

7774
@staticmethod
7875
@description("Edit my profile")
79-
async def patch(
80-
data: UserOptional, user: User = Depends(profile_perms)
81-
) -> User:
76+
async def patch(data: UserOptional, user: User = Depends(profile_perms)) -> UserSafe:
8277
if data.password:
8378
data.password = encrypt(data.password)
8479
await user.patch(data)

freenit/models/role.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22

33
config = getConfig()
44
auth = config.get_model("role")
5-
Role = auth.Role
6-
RoleOptional = auth.RoleOptional
5+
6+
7+
class Role(auth.Role):
8+
pass
9+
10+
11+
class RoleOptional(auth.RoleOptional):
12+
pass

freenit/models/safe.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import List
2+
3+
from freenit.config import getConfig
4+
5+
config = getConfig()
6+
7+
8+
class UserSafe(config.get_model("user").User.get_pydantic(exclude={"password"})):
9+
pass
10+
11+
12+
class RoleSafe(config.get_model("role").BaseRole):
13+
users: List[UserSafe]

freenit/models/sql/base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ async def patch(self, fields):
2323
class OrmarUserMixin:
2424
id: int = ormar.Integer(primary_key=True)
2525
email: pydantic.EmailStr = ormar.Text(unique=True)
26-
password: str = ormar.Text(nullable=True)
26+
password: str = ormar.Text()
2727
fullname: str = ormar.Text(nullable=True)
2828
active: bool = ormar.Boolean(default=False)
2929
admin: bool = ormar.Boolean(default=False)
3030

3131

3232
class OrmarRoleMixin:
3333
id: int = ormar.Integer(primary_key=True)
34-
name: str = ormar.Text(unique=True)
34+
name: str = ormar.Text(unique=True, index=True)
3535

3636

3737
ormar_config = ormar.OrmarConfig(
@@ -44,3 +44,7 @@ class OrmarRoleMixin:
4444
def make_optional(OptionalModel):
4545
for field_name in OptionalModel.model_fields:
4646
OptionalModel.model_fields[field_name].default = None
47+
48+
49+
class BaseRole(OrmarBaseModel, OrmarRoleMixin):
50+
ormar_config = ormar_config.copy()

freenit/models/sql/role.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
from .base import OrmarBaseModel, OrmarRoleMixin, make_optional, ormar_config
1+
from .base import BaseRole, ormar_config, make_optional
22

3-
4-
class Role(OrmarBaseModel, OrmarRoleMixin):
3+
class Role(BaseRole):
54
ormar_config = ormar_config.copy()
65

76

8-
class RoleOptional(Role):
7+
class RoleOptional(BaseRole):
98
pass
109

1110

freenit/models/sql/user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from fastapi import HTTPException
66

77
from freenit.auth import verify
8-
from freenit.models.sql.base import (
8+
from .base import (
99
OrmarBaseModel,
1010
OrmarUserMixin,
1111
make_optional,

freenit/models/user.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22

33
config = getConfig()
44
auth = config.get_model("user")
5-
User = auth.User
6-
UserOptional = auth.UserOptionalPydantic
5+
6+
7+
class User(auth.User):
8+
pass
9+
10+
11+
class UserOptional(auth.UserOptional):
12+
pass

0 commit comments

Comments
 (0)