Skip to content

Commit 0a0c1a8

Browse files
authored
Merge pull request #163 from mekanix/user-model
Return all user fields except password
2 parents 6cbaa5c + 8c57240 commit 0a0c1a8

File tree

8 files changed

+59
-50
lines changed

8 files changed

+59
-50
lines changed

alembic/versions/ecd6a3f19a8f_initial.py renamed to alembic/versions/a754f05fd8e5_initial.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""initial
22
3-
Revision ID: ecd6a3f19a8f
3+
Revision ID: a754f05fd8e5
44
Revises:
5-
Create Date: 2025-01-18 00:10:08.290307
5+
Create Date: 2025-01-25 19:46:28.006950
66
77
"""
88

@@ -11,7 +11,7 @@
1111

1212

1313
# revision identifiers, used by Alembic.
14-
revision = "ecd6a3f19a8f"
14+
revision = "a754f05fd8e5"
1515
down_revision = None
1616
branch_labels = None
1717
depends_on = None
@@ -51,7 +51,7 @@ def upgrade():
5151
"users",
5252
sa.Column("id", sa.Integer(), nullable=False),
5353
sa.Column("email", sa.Text(), nullable=False),
54-
sa.Column("password", sa.Text(), nullable=False),
54+
sa.Column("password", sa.Text(), nullable=True),
5555
sa.Column("active", sa.Boolean(), nullable=True),
5656
sa.Column("admin", sa.Boolean(), nullable=True),
5757
sa.PrimaryKeyConstraint("id"),

freenit/api/auth/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from freenit.auth import authorize, decode, encode, encrypt
88
from freenit.config import getConfig
99
from freenit.mail import sendmail
10-
from freenit.models.safe import UserSafe
1110
from freenit.models.user import User
1211

1312
config = getConfig()
@@ -24,7 +23,7 @@ class TokenExpire(pydantic.BaseModel):
2423

2524

2625
class LoginResponse(pydantic.BaseModel):
27-
user: UserSafe
26+
user: User
2827
expire: TokenExpire
2928

3029

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

8384

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

107108

108-
@api.post("/auth/verify", response_model=UserSafe, tags=["auth"])
109+
@api.post("/auth/verify", response_model=User, tags=["auth"])
109110
async def verify(verification: Verification):
110111
user = await decode(verification.verification)
111112
await user.update(active=True)
@@ -117,6 +118,7 @@ async def refresh(request: Request, response: Response):
117118
user = await authorize(request, cookie="refresh")
118119
access = encode(user)
119120
response.set_cookie("access", access, httponly=True, secure=config.auth.secure)
121+
user.password = None
120122
return {
121123
"user": user,
122124
"expire": {

freenit/api/role/sql.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
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
109
from freenit.models.user import User
1110
from freenit.permissions import role_perms
1211

@@ -21,30 +20,35 @@ async def get(
2120
page: int = Header(default=1),
2221
perpage: int = Header(default=10),
2322
_: User = Depends(role_perms),
24-
) -> Page[RoleSafe]:
25-
return await paginate(Role.objects, page, perpage)
23+
) -> Page[Role]:
24+
return await paginate(
25+
Role.objects.select_related("users").exclude_fields("users__password"),
26+
page,
27+
perpage,
28+
)
2629

2730
@staticmethod
28-
async def post(role: Role, _: User = Depends(role_perms)) -> RoleSafe:
31+
async def post(role: Role, _: User = Depends(role_perms)) -> Role:
2932
await role.save()
3033
return role
3134

3235

3336
@route("/roles/{id}", tags=tags)
3437
class RoleDetailAPI:
3538
@staticmethod
36-
async def get(id, _: User = Depends(role_perms)) -> RoleSafe:
39+
async def get(id, _: User = Depends(role_perms)) -> Role:
3740
try:
38-
role = await Role.objects.get(pk=id)
41+
role = (
42+
await Role.objects.select_related("users")
43+
.exclude_fields("users__password")
44+
.get(pk=id)
45+
)
3946
except ormar.exceptions.NoMatch:
4047
raise HTTPException(status_code=404, detail="No such role")
41-
await role.load_all(follow=True)
4248
return role
4349

4450
@staticmethod
45-
async def patch(
46-
id, role_data: RoleOptional, _: User = Depends(role_perms)
47-
) -> RoleSafe:
51+
async def patch(id, role_data: RoleOptional, _: User = Depends(role_perms)) -> Role:
4852
if Role.dbtype() == "sql":
4953
try:
5054
role = await Role.objects.get(pk=id)
@@ -58,7 +62,7 @@ async def patch(
5862
)
5963

6064
@staticmethod
61-
async def delete(id, _: User = Depends(role_perms)) -> RoleSafe:
65+
async def delete(id, _: User = Depends(role_perms)) -> Role:
6266
try:
6367
role = await Role.objects.get(pk=id)
6468
except ormar.exceptions.NoMatch:
@@ -71,12 +75,15 @@ async def delete(id, _: User = Depends(role_perms)) -> RoleSafe:
7175
class RoleUserAPI:
7276
@staticmethod
7377
@description("Assign user to role")
74-
async def post(role_id, user_id, _: User = Depends(role_perms)) -> UserSafe:
78+
async def post(role_id, user_id, _: User = Depends(role_perms)) -> User:
7579
try:
76-
user = await User.objects.get(pk=user_id)
80+
user = (
81+
await User.objects.select_related("roles")
82+
.exclude_fields("password")
83+
.get(pk=user_id)
84+
)
7785
except ormar.exceptions.NoMatch:
7886
raise HTTPException(status_code=404, detail="No such user")
79-
await user.load_all()
8087
for role in user.roles:
8188
if role.id == role_id:
8289
raise HTTPException(status_code=409, detail="User already assigned")
@@ -89,16 +96,19 @@ async def post(role_id, user_id, _: User = Depends(role_perms)) -> UserSafe:
8996

9097
@staticmethod
9198
@description("Deassign user to role")
92-
async def delete(role_id, user_id, _: User = Depends(role_perms)) -> UserSafe:
99+
async def delete(role_id, user_id, _: User = Depends(role_perms)) -> User:
93100
try:
94-
user = await User.objects.get(pk=user_id)
101+
user = (
102+
await User.objects.select_related("roles")
103+
.exclude_fields("password")
104+
.get(pk=user_id)
105+
)
95106
except ormar.exceptions.NoMatch:
96107
raise HTTPException(status_code=404, detail="No such user")
97108
try:
98109
role = await Role.objects.get(pk=role_id)
99110
except ormar.exceptions.NoMatch:
100111
raise HTTPException(status_code=404, detail="No such role")
101-
await user.load_all()
102112
try:
103113
await user.roles.remove(role)
104114
except ormar.exceptions.NoMatch:

freenit/api/user/sql.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from freenit.config import getConfig
88
from freenit.decorators import description
99
from freenit.models.pagination import Page, paginate
10-
from freenit.models.safe import UserSafe
1110
from freenit.models.user import User, UserOptional
1211
from freenit.permissions import profile_perms, user_perms
1312

@@ -24,23 +23,30 @@ async def get(
2423
page: int = Header(default=1),
2524
perpage: int = Header(default=10),
2625
_: User = Depends(user_perms),
27-
) -> Page[UserSafe]:
28-
return await paginate(User.objects, page, perpage)
26+
) -> Page[User]:
27+
return await paginate(
28+
User.objects.select_related("roles").exclude_fields("password"),
29+
page,
30+
perpage,
31+
)
2932

3033

3134
@route("/users/{id}", tags=tags)
3235
class UserDetailAPI:
3336
@staticmethod
34-
async def get(id, _: User = Depends(user_perms)) -> UserSafe:
37+
async def get(id, _: User = Depends(user_perms)) -> User:
3538
try:
36-
user = await User.objects.get(pk=id)
39+
user = (
40+
await User.objects.select_related("roles")
41+
.exclude_fields("password")
42+
.get(pk=id)
43+
)
3744
except ormar.exceptions.NoMatch:
3845
raise HTTPException(status_code=404, detail="No such user")
39-
await user.load_all(follow=True)
4046
return user
4147

4248
@staticmethod
43-
async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> UserSafe:
49+
async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> User:
4450
if data.password:
4551
data.password = encrypt(data.password)
4652
try:
@@ -51,7 +57,7 @@ async def patch(id, data: UserOptional, _: User = Depends(user_perms)) -> UserSa
5157
return user
5258

5359
@staticmethod
54-
async def delete(id, _: User = Depends(user_perms)) -> UserSafe:
60+
async def delete(id, _: User = Depends(user_perms)) -> User:
5561
try:
5662
user = await User.objects.get(pk=id)
5763
except ormar.exceptions.NoMatch:
@@ -64,15 +70,15 @@ async def delete(id, _: User = Depends(user_perms)) -> UserSafe:
6470
class ProfileDetailAPI:
6571
@staticmethod
6672
@description("Get my profile")
67-
async def get(user: User = Depends(profile_perms)) -> UserSafe:
73+
async def get(user: User = Depends(profile_perms)) -> User:
6874
await user.load_all()
6975
return user
7076

7177
@staticmethod
7278
@description("Edit my profile")
7379
async def patch(
7480
data: UserOptional, user: User = Depends(profile_perms)
75-
) -> UserSafe:
81+
) -> User:
7682
if data.password:
7783
data.password = encrypt(data.password)
7884
await user.patch(data)

freenit/auth.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async def decode(token):
2020
import ormar.exceptions
2121

2222
try:
23-
user = await User.objects.get(pk=pk)
23+
user = await User.objects.select_related("roles").get(pk=pk)
2424
return user
2525
except ormar.exceptions.NoMatch:
2626
raise HTTPException(status_code=403, detail="Unauthorized")
@@ -46,7 +46,6 @@ async def authorize(request: Request, roles=[], allof=[], cookie="access"):
4646
raise HTTPException(status_code=403, detail="Unauthorized")
4747
user = await decode(token)
4848
if user.dbtype() == "sql":
49-
await user.load_all()
5049
if not user.active:
5150
raise HTTPException(status_code=403, detail="Permission denied")
5251
if user.admin:

freenit/models/safe.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

freenit/models/sql/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ 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()
26+
password: str = ormar.Text(nullable=True)
2727
active: bool = ormar.Boolean(default=False)
2828
admin: bool = ormar.Boolean(default=False)
2929

freenit/models/sql/user.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616

1717
class BaseUser(OrmarBaseModel, OrmarUserMixin):
1818
def check(self, password: str) -> bool:
19+
if self.password is None:
20+
return False
1921
return verify(password, self.password)
2022

2123
@classmethod
2224
async def login(cls, credentials) -> BaseUser:
2325
try:
24-
user = await cls.objects.get(email=credentials.email, active=True)
26+
user = await cls.objects.select_related("roles").get(
27+
email=credentials.email, active=True
28+
)
2529
except ormar.exceptions.NoMatch:
2630
raise HTTPException(status_code=403, detail="Failed to login")
2731
if user.check(credentials.password):

0 commit comments

Comments
 (0)