Merge pull request #12 from BlackChaosNL/fea/users
Add user routes
This commit was merged in pull request #12.
This commit is contained in:
@@ -10,8 +10,6 @@ from modules.auth.models import Token
|
|||||||
from fastapi import Depends, HTTPException, status
|
from fastapi import Depends, HTTPException, status
|
||||||
from tortoise.expressions import Q
|
from tortoise.expressions import Q
|
||||||
from config import settings
|
from config import settings
|
||||||
from modules.users.schemas import user_model
|
|
||||||
from modules.auth.schemas import register_model
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/v1/auth", tags=["auth"])
|
router = APIRouter(prefix="/api/v1/auth", tags=["auth"])
|
||||||
|
|
||||||
@@ -31,7 +29,7 @@ async def login(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
|
|||||||
Logs the user into our API, creates tokens and passes them back to User.
|
Logs the user into our API, creates tokens and passes them back to User.
|
||||||
"""
|
"""
|
||||||
user: User | None = await User.filter(
|
user: User | None = await User.filter(
|
||||||
Q(email=form.username) | Q(username=form.username)
|
(Q(email=form.username) | Q(username=form.username)) & Q(disabled=False)
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
@@ -44,11 +42,6 @@ async def login(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
|
|||||||
status_code=status.HTTP_401_UNAUTHORIZED, detail=account_error
|
status_code=status.HTTP_401_UNAUTHORIZED, detail=account_error
|
||||||
)
|
)
|
||||||
|
|
||||||
if user.disabled is True:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED, detail=account_error
|
|
||||||
)
|
|
||||||
|
|
||||||
tokens = await create_jwt_tokens(user)
|
tokens = await create_jwt_tokens(user)
|
||||||
|
|
||||||
return {"jwt": tokens}
|
return {"jwt": tokens}
|
||||||
@@ -61,7 +54,7 @@ async def logout(user: Annotated[User, Depends(get_current_active_user)]):
|
|||||||
|
|
||||||
Logout destroys all tokens for User that are currently active.
|
Logout destroys all tokens for User that are currently active.
|
||||||
"""
|
"""
|
||||||
get_all_tokens = await Token.filter(Q(user__id=user.id))
|
get_all_tokens = await Token.filter(Q(user__id=user.id) & Q(disabled=False))
|
||||||
if get_all_tokens is None:
|
if get_all_tokens is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_204_NO_CONTENT, detail="An error occurred."
|
status_code=status.HTTP_204_NO_CONTENT, detail="An error occurred."
|
||||||
@@ -98,12 +91,6 @@ async def refresh_login(
|
|||||||
detail=token_error,
|
detail=token_error,
|
||||||
)
|
)
|
||||||
|
|
||||||
if refresh_token.disabled is True:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail=token_error,
|
|
||||||
)
|
|
||||||
|
|
||||||
get_all_tokens = await Token.filter(Q(user__id=refresh_token.user_id))
|
get_all_tokens = await Token.filter(Q(user__id=refresh_token.user_id))
|
||||||
|
|
||||||
for token in get_all_tokens:
|
for token in get_all_tokens:
|
||||||
@@ -115,36 +102,3 @@ async def refresh_login(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return {"jwt": tokens}
|
return {"jwt": tokens}
|
||||||
|
|
||||||
|
|
||||||
@router.post(
|
|
||||||
"/register", status_code=status.HTTP_201_CREATED, response_model=user_model
|
|
||||||
)
|
|
||||||
async def register(user: register_model):
|
|
||||||
# Prevent existing users from reapplying for our system.
|
|
||||||
existing_user: User | None = await User.filter(
|
|
||||||
Q(email=user.email)
|
|
||||||
& Q(username=user.username)
|
|
||||||
& Q(name=user.name)
|
|
||||||
& Q(surname=user.surname)
|
|
||||||
).get_or_none()
|
|
||||||
|
|
||||||
if existing_user is not None:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail=user_exists,
|
|
||||||
)
|
|
||||||
|
|
||||||
if user.password != user.validate_password:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail=password_failed,
|
|
||||||
)
|
|
||||||
|
|
||||||
return await User.create(
|
|
||||||
email=user.email,
|
|
||||||
username=user.username,
|
|
||||||
name=user.name,
|
|
||||||
surname=user.surname,
|
|
||||||
password=crypt.hash(user.password),
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
from pydantic import BaseModel, EmailStr
|
|
||||||
from tortoise.contrib.pydantic import pydantic_model_creator
|
from tortoise.contrib.pydantic import pydantic_model_creator
|
||||||
|
|
||||||
from modules.auth.models import Token
|
from modules.auth.models import Token
|
||||||
|
|
||||||
token_model = pydantic_model_creator(Token)
|
token_model = pydantic_model_creator(Token)
|
||||||
|
|
||||||
class register_model(BaseModel):
|
|
||||||
email: EmailStr
|
|
||||||
username: str
|
|
||||||
name: str
|
|
||||||
surname: str
|
|
||||||
password: str
|
|
||||||
validate_password: str
|
|
||||||
@@ -61,7 +61,7 @@ async def create_jwt_tokens(user: User) -> Token:
|
|||||||
|
|
||||||
|
|
||||||
async def get_tokens_from_logged_in_user(
|
async def get_tokens_from_logged_in_user(
|
||||||
token: Annotated[str, Depends(settings.OAUTH2_SCHEME)]
|
token: Annotated[str, Depends(settings.OAUTH2_SCHEME)],
|
||||||
) -> User | None:
|
) -> User | None:
|
||||||
credentials_exception = HTTPException(
|
credentials_exception = HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
@@ -79,4 +79,6 @@ async def get_tokens_from_logged_in_user(
|
|||||||
except:
|
except:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
|
|
||||||
return await Token.filter(Q(refresh_token=token) & Q(user__id=user_id)).first()
|
return await Token.filter(
|
||||||
|
Q(refresh_token=token) & Q(user__id=user_id) & Q(disabled=False)
|
||||||
|
).first()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
|
|
||||||
from typing import Annotated, List
|
from typing import Annotated, List
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ async def all_active_organizations(
|
|||||||
organizations: List[Organization] = []
|
organizations: List[Organization] = []
|
||||||
|
|
||||||
if len(memberships) < 1:
|
if len(memberships) < 1:
|
||||||
raise HTTPException(status_code=404, detail="No active organizations found!")
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No active organizations found!")
|
||||||
|
|
||||||
for member in memberships:
|
for member in memberships:
|
||||||
organizations.append(member.organization)
|
organizations.append(member.organization)
|
||||||
@@ -35,7 +35,7 @@ async def all_active_organizations(
|
|||||||
return organizations
|
return organizations
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{org_id}", status_code=204)
|
@router.delete("/{org_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def delete_organization(
|
async def delete_organization(
|
||||||
user: Annotated[User, Depends(get_current_active_user)], org_id: uuid.UUID
|
user: Annotated[User, Depends(get_current_active_user)], org_id: uuid.UUID
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
from fastapi import HTTPException, status
|
||||||
from pydantic import EmailStr
|
from pydantic import EmailStr
|
||||||
import pytz
|
import pytz
|
||||||
from tortoise.models import Model
|
from tortoise.models import Model
|
||||||
@@ -41,9 +42,10 @@ class User(Model):
|
|||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.id} - {self.name} {self.surname}"
|
return f"{self.id} - {self.name} {self.surname}"
|
||||||
|
|
||||||
async def set_password(self, password: str) -> None:
|
async def set_password(self, password: str) -> bool:
|
||||||
self.password = crypt.hash(password)
|
self.password = crypt.hash(password)
|
||||||
await self.save() # Make sure to save the model in DB
|
await self.save() # Make sure to save the model in DB
|
||||||
|
return True
|
||||||
|
|
||||||
def check_against_password(self, password: str) -> bool:
|
def check_against_password(self, password: str) -> bool:
|
||||||
return crypt.verify(password, self.password)
|
return crypt.verify(password, self.password)
|
||||||
@@ -55,7 +57,7 @@ class User(Model):
|
|||||||
return False
|
return False
|
||||||
if new_password is not verify_new_password:
|
if new_password is not verify_new_password:
|
||||||
return False
|
return False
|
||||||
await self.set_password(new_password)
|
return await self.set_password(new_password)
|
||||||
|
|
||||||
async def delete(self, force: bool = False) -> None:
|
async def delete(self, force: bool = False) -> None:
|
||||||
if force:
|
if force:
|
||||||
|
|||||||
@@ -1,20 +1,99 @@
|
|||||||
from fastapi import APIRouter
|
from typing import Annotated, List
|
||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from modules.users.models import User
|
from fastapi import HTTPException, status
|
||||||
|
|
||||||
|
from tortoise.expressions import Q
|
||||||
|
|
||||||
|
from modules.auth.models import Token
|
||||||
|
from modules.users.utils import get_current_active_user
|
||||||
|
from modules.users.schemas import register_model, update_user_model
|
||||||
|
from modules.users.models import Membership, User
|
||||||
|
from modules.users.schemas import user_model
|
||||||
|
|
||||||
|
from config import settings
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/v1/users", tags=["users"])
|
router = APIRouter(prefix="/api/v1/users", tags=["users"])
|
||||||
|
|
||||||
|
crypt = settings.CRYPT
|
||||||
|
|
||||||
@router.get("/")
|
user_exists: str = "Account failed to create, please contact support."
|
||||||
def get_all_users():
|
password_failed: str = "Password validation failed, please try again."
|
||||||
pass
|
|
||||||
|
|
||||||
@router.post("/")
|
|
||||||
def create_user():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/me")
|
@router.post("/", status_code=status.HTTP_201_CREATED, response_model=user_model)
|
||||||
def get_user():
|
async def create_user(user: register_model):
|
||||||
pass
|
# Prevent existing users from reapplying for our system.
|
||||||
|
existing_user: User | None = await User.get_or_none(
|
||||||
|
Q(email=user.email)
|
||||||
|
& Q(username=user.username)
|
||||||
|
& Q(name=user.name)
|
||||||
|
& Q(surname=user.surname)
|
||||||
|
& Q(disabled=False)
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing_user is not None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail=user_exists,
|
||||||
|
)
|
||||||
|
|
||||||
|
if user.password != user.validate_password:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail=password_failed,
|
||||||
|
)
|
||||||
|
|
||||||
|
return await User.create(
|
||||||
|
email=user.email,
|
||||||
|
username=user.username,
|
||||||
|
name=user.name,
|
||||||
|
surname=user.surname,
|
||||||
|
password=crypt.hash(user.password),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/me", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
async def update_user(
|
||||||
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
|
updated_user: update_user_model,
|
||||||
|
):
|
||||||
|
if updated_user.email:
|
||||||
|
user.email = updated_user.email
|
||||||
|
if updated_user.name:
|
||||||
|
user.name = updated_user.name
|
||||||
|
if updated_user.surname:
|
||||||
|
user.surname = updated_user.surname
|
||||||
|
|
||||||
|
if (
|
||||||
|
updated_user.old_password
|
||||||
|
and updated_user.password
|
||||||
|
and updated_user.validate_password
|
||||||
|
):
|
||||||
|
user.update_password(
|
||||||
|
updated_user.old_password,
|
||||||
|
updated_user.password,
|
||||||
|
updated_user.validate_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
await user.save()
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/me", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
async def update_user(
|
||||||
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
|
):
|
||||||
|
memberships: List[Membership] = await Membership.filter(Q(user__id=user.id) & Q(disabled=False))
|
||||||
|
for membership in memberships:
|
||||||
|
await membership.acl.delete()
|
||||||
|
await membership.delete()
|
||||||
|
tokens: List[Token] = await Token.filter(Q(user__id=user.id) & Q(disabled=False))
|
||||||
|
for token in tokens:
|
||||||
|
await token.delete()
|
||||||
|
await user.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/me", response_model=user_model)
|
||||||
|
async def get_user(user: Annotated[User, Depends(get_current_active_user)]):
|
||||||
|
return user
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
|
from pydantic import BaseModel, EmailStr
|
||||||
from tortoise.contrib.pydantic import pydantic_model_creator
|
from tortoise.contrib.pydantic import pydantic_model_creator
|
||||||
|
|
||||||
from modules.users.models import User
|
from modules.users.models import User
|
||||||
|
|
||||||
user_model = pydantic_model_creator(User, exclude=["password"])
|
user_model = pydantic_model_creator(User, exclude=["password"])
|
||||||
|
|
||||||
|
class register_model(BaseModel):
|
||||||
|
email: EmailStr
|
||||||
|
username: str
|
||||||
|
name: str
|
||||||
|
surname: str
|
||||||
|
password: str
|
||||||
|
validate_password: str
|
||||||
|
|
||||||
|
|
||||||
|
class update_user_model(BaseModel):
|
||||||
|
email: EmailStr | None
|
||||||
|
name: str | None
|
||||||
|
surname: str | None
|
||||||
|
old_password: str | None
|
||||||
|
password: str | None
|
||||||
|
validate_password: str | None
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from config import settings
|
|||||||
|
|
||||||
|
|
||||||
async def get_user_from_token(
|
async def get_user_from_token(
|
||||||
token: Annotated[str, Depends(settings.OAUTH2_SCHEME)]
|
token: Annotated[str, Depends(settings.OAUTH2_SCHEME)],
|
||||||
) -> User | None:
|
) -> User | None:
|
||||||
credentials_exception = HTTPException(
|
credentials_exception = HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
@@ -28,7 +28,7 @@ async def get_user_from_token(
|
|||||||
except:
|
except:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
|
|
||||||
return await User.filter(Q(id=user_id)).first()
|
return await User.filter(Q(id=user_id) & Q(disabled=False)).first()
|
||||||
|
|
||||||
|
|
||||||
async def get_current_active_user(
|
async def get_current_active_user(
|
||||||
@@ -37,11 +37,6 @@ async def get_current_active_user(
|
|||||||
if user is None:
|
if user is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail="User is not found or active",
|
detail="The requested token does not exist or you are not logged in.",
|
||||||
)
|
|
||||||
if user.disabled:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="User is not found or active",
|
|
||||||
)
|
)
|
||||||
return user
|
return user
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
from tests.base_test import Test
|
from tests.base_test import Test
|
||||||
from modules.users.models import User
|
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
from config import settings
|
from config import settings
|
||||||
from unittest.mock import ANY
|
from unittest.mock import ANY
|
||||||
from tortoise.expressions import Q
|
|
||||||
|
|
||||||
crypt = settings.CRYPT
|
crypt = settings.CRYPT
|
||||||
|
|
||||||
@@ -161,35 +159,3 @@ class TestAuthentication(Test):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async def test_setup_new_account(self, client: AsyncClient):
|
|
||||||
# Ensure account is never available. Prevents account already being available.
|
|
||||||
check_if_account_exists: User | None = await User.filter(
|
|
||||||
Q(email="superuser@localhost.com")
|
|
||||||
).get_or_none()
|
|
||||||
if check_if_account_exists:
|
|
||||||
await check_if_account_exists.delete(force=True)
|
|
||||||
|
|
||||||
account = await client.post(
|
|
||||||
"https://localhost/api/v1/auth/register",
|
|
||||||
json={
|
|
||||||
"email": "superuser@localhost.com",
|
|
||||||
"username": "superuser",
|
|
||||||
"name": "awesome",
|
|
||||||
"surname": "superuser",
|
|
||||||
"password": "superuserpassword",
|
|
||||||
"validate_password": "superuserpassword",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert account.status_code == 201
|
|
||||||
assert account.json() == {
|
|
||||||
"created_at": ANY,
|
|
||||||
"disabled": False,
|
|
||||||
"disabled_at": None,
|
|
||||||
"email": "superuser@localhost.com",
|
|
||||||
"id": ANY,
|
|
||||||
"modified_at": ANY,
|
|
||||||
"name": "awesome",
|
|
||||||
"surname": "superuser",
|
|
||||||
"username": "superuser",
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
from tests.base_test import Test
|
||||||
|
from tortoise.expressions import Q
|
||||||
|
from tests.base_test import Test
|
||||||
|
from httpx import AsyncClient
|
||||||
|
from unittest.mock import ANY
|
||||||
|
from modules.users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class TestAccounts(Test):
|
||||||
|
async def test_setup_new_account(self, client: AsyncClient):
|
||||||
|
# Ensure account is never available. Prevents account already being available.
|
||||||
|
check_if_account_exists: User | None = await User.filter(
|
||||||
|
Q(email="superuser@localhost.com")
|
||||||
|
).get_or_none()
|
||||||
|
if check_if_account_exists:
|
||||||
|
await check_if_account_exists.delete(force=True)
|
||||||
|
|
||||||
|
account = await client.post(
|
||||||
|
"https://localhost/api/v1/users/",
|
||||||
|
json={
|
||||||
|
"email": "superuser@localhost.com",
|
||||||
|
"username": "superuser",
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "superuser",
|
||||||
|
"password": "superuserpassword",
|
||||||
|
"validate_password": "superuserpassword",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 201
|
||||||
|
assert account.json() == {
|
||||||
|
"created_at": ANY,
|
||||||
|
"disabled": False,
|
||||||
|
"disabled_at": None,
|
||||||
|
"email": "superuser@localhost.com",
|
||||||
|
"id": ANY,
|
||||||
|
"modified_at": ANY,
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "superuser",
|
||||||
|
"username": "superuser",
|
||||||
|
}
|
||||||
|
|
||||||
|
async def test_me_route(self, client: AsyncClient, create_user_with_org):
|
||||||
|
_, _, _, tokens = await create_user_with_org()
|
||||||
|
|
||||||
|
account = await client.get(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 200
|
||||||
|
assert account.json() == {
|
||||||
|
"created_at": ANY,
|
||||||
|
"disabled": False,
|
||||||
|
"disabled_at": None,
|
||||||
|
"email": "user@localhost.com",
|
||||||
|
"id": ANY,
|
||||||
|
"modified_at": ANY,
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "user",
|
||||||
|
"username": "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
async def test_update_me_route(self, client: AsyncClient, create_user_with_org):
|
||||||
|
_, _, _, tokens = await create_user_with_org()
|
||||||
|
|
||||||
|
account = await client.get(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 200
|
||||||
|
assert account.json() == {
|
||||||
|
"created_at": ANY,
|
||||||
|
"disabled": False,
|
||||||
|
"disabled_at": None,
|
||||||
|
"email": "user@localhost.com",
|
||||||
|
"id": ANY,
|
||||||
|
"modified_at": ANY,
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "user",
|
||||||
|
"username": "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
account = await client.put(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
json={
|
||||||
|
"email": None,
|
||||||
|
"name": None,
|
||||||
|
"surname": "bluey",
|
||||||
|
"old_password": None,
|
||||||
|
"password": None,
|
||||||
|
"validate_password": None,
|
||||||
|
},
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 204
|
||||||
|
|
||||||
|
account = await client.get(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 200
|
||||||
|
assert account.json() == {
|
||||||
|
"created_at": ANY,
|
||||||
|
"disabled": False,
|
||||||
|
"disabled_at": None,
|
||||||
|
"email": "user@localhost.com",
|
||||||
|
"id": ANY,
|
||||||
|
"modified_at": ANY,
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "bluey",
|
||||||
|
"username": "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
async def test_remove_account(self, client: AsyncClient, create_user_with_org):
|
||||||
|
_, _, _, tokens = await create_user_with_org(email="sup3rus3r@gmail.com")
|
||||||
|
|
||||||
|
account = await client.get(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert account.status_code == 200
|
||||||
|
assert account.json() == {
|
||||||
|
"created_at": ANY,
|
||||||
|
"disabled": False,
|
||||||
|
"disabled_at": None,
|
||||||
|
"email": "sup3rus3r@gmail.com",
|
||||||
|
"id": ANY,
|
||||||
|
"modified_at": ANY,
|
||||||
|
"name": "awesome",
|
||||||
|
"surname": "user",
|
||||||
|
"username": "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
delete = await client.delete(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert delete.status_code == 204
|
||||||
|
|
||||||
|
old = await client.get(
|
||||||
|
"https://localhost/api/v1/users/me",
|
||||||
|
headers={"Authorization": f"Bearer {tokens.access_token}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert old.status_code == 401
|
||||||
|
assert old.json() == {
|
||||||
|
"detail": "The requested token does not exist or you are not logged in.",
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user