Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
refactor: Refactors user creation & corresponding telemetry (#32)
Browse files Browse the repository at this point in the history
* refactor: Refactors user creation

* test: Updates tests
  • Loading branch information
frgfm authored Nov 8, 2023
1 parent e62a076 commit b7efdf0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 32 deletions.
24 changes: 5 additions & 19 deletions src/app/api/api_v1/endpoints/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
from fastapi.security import OAuth2PasswordRequestForm
from pydantic import HttpUrl

from app.api.api_v1.endpoints.users import _create_user
from app.api.dependencies import get_user_crud
from app.core.config import settings
from app.core.security import create_access_token, hash_password, verify_password
from app.core.security import create_access_token, verify_password
from app.crud import UserCRUD
from app.models import UserScope
from app.schemas.login import GHAccessToken, Token, TokenRequest
from app.schemas.services import GHToken
from app.schemas.users import UserCreation
from app.schemas.users import UserCreate
from app.services.github import gh_client
from app.services.telemetry import telemetry_client

Expand Down Expand Up @@ -78,30 +79,15 @@ async def login_with_github_token(
# Fetch GitHub
gh_user = gh_client.get_my_user(payload.github_token)
telemetry_client.capture(gh_user["id"], event="user-login", properties={"login": gh_user["login"]})
telemetry_client.identify(
gh_user["id"],
properties={
"login": gh_user["login"],
"name": gh_user["name"],
"email": gh_user["email"],
"twitter_username": gh_user["twitter_username"],
},
)
# Check that GH account is a user
if gh_user["type"] != "User":
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "GitHub account is expected to be a user")
# Verify credentials
user = await users.get(gh_user["id"], strict=False)
# Register if non existing
if user is None:
telemetry_client.capture(gh_user["id"], event="user-creation", properties={"login": gh_user["login"]})
user = await users.create(
UserCreation(
id=gh_user["id"],
login=gh_user["login"],
hashed_password=await hash_password(secrets.token_urlsafe(32)),
scope=UserScope.USER,
)
user = await _create_user(
UserCreate(id=gh_user["id"], password=secrets.token_urlsafe(32), scope=UserScope.USER), users
)

# create access token using user user_id/user_scopes
Expand Down
45 changes: 34 additions & 11 deletions src/app/api/api_v1/endpoints/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# All rights reserved.
# Copying and/or distributing is strictly prohibited without the express permission of its copyright owner.

from typing import List, cast
from typing import List, Union, cast

from fastapi import APIRouter, Depends, HTTPException, Path, Security, status

Expand All @@ -18,22 +18,45 @@
router = APIRouter()


async def _create_user(payload: UserCreate, users: UserCRUD, requester: Union[User, None] = None) -> User:
# Check that user exists on GitHub
gh_user = gh_client.get_user(payload.id)
if gh_user["type"] != "User":
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "GitHub account is expected to be a user")
telemetry_client.identify(
gh_user["id"],
properties={
"login": gh_user["login"],
"name": gh_user["name"],
"email": gh_user["email"],
"twitter_username": gh_user["twitter_username"],
},
)
# Create the entry
user = await users.create(
UserCreation(
id=payload.id,
login=gh_user["login"],
hashed_password=await hash_password(payload.password),
scope=payload.scope,
)
)
# Assume the requester is the new user if none was specified
telemetry_client.capture(
requester.id if isinstance(requester, User) else user.id,
event="user-creation",
properties={"login": gh_user["login"]},
)
return user


@router.post("/", status_code=status.HTTP_201_CREATED)
async def create_user(
payload: UserCreate,
users: UserCRUD = Depends(get_user_crud),
user: User = Security(get_current_user, scopes=[UserScope.ADMIN]),
) -> User:
# Check that user exists on GitHub
gh_user = gh_client.get_user(payload.id)
if gh_user["type"] != "User":
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "GitHub account is expected to be a user")
telemetry_client.capture(user.id, event="user-creation", properties={"login": gh_user["login"]})
# Hash the password
pwd = await hash_password(payload.password)
return await users.create(
UserCreation(id=payload.id, login=gh_user["login"], hashed_password=pwd, scope=payload.scope)
)
return await _create_user(payload, users, user)


@router.get("/{user_id}", status_code=status.HTTP_200_OK)
Expand Down
4 changes: 2 additions & 2 deletions src/tests/endpoints/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from httpx import AsyncClient
from sqlmodel.ext.asyncio.session import AsyncSession

from app.api.api_v1.endpoints import login
from app.api.api_v1.endpoints import login, users
from app.models import User

USER_TABLE = [
Expand All @@ -21,7 +21,7 @@ async def login_session(async_session: AsyncSession, monkeypatch):
async_session.add(User(**entry))
await async_session.commit()
monkeypatch.setattr(login, "verify_password", pytest.mock_verify_password)
monkeypatch.setattr(login, "hash_password", pytest.mock_hash_password)
monkeypatch.setattr(users, "hash_password", pytest.mock_hash_password)
yield async_session


Expand Down

0 comments on commit b7efdf0

Please sign in to comment.