"""
User management paths
"""
from datetime import datetime
from typing import List, Optional
from fastapi import (
APIRouter,
Depends,
HTTPException,
status,
)
import pydantic as pdt
from sni.esi.scope import EsiScope
from sni.esi.token import available_esi_scopes
from sni.uac.clearance import assert_has_clearance
from sni.uac.token import (
from_authotization_header_nondyn,
Token,
)
from sni.user.models import User
router = APIRouter()
[docs]class GetUserShortOut(pdt.BaseModel):
"""
Model for an element of ``GET /user`` response
"""
character_id: int
character_name: str
[docs] @staticmethod
def from_record(usr: User) -> "GetUserShortOut":
"""
Converts a :class:`sni.user.models.User` to a
:class:`sni.api.routers.user.GetUserShortOut`
"""
return GetUserShortOut(
character_id=usr.character_id, character_name=usr.character_name,
)
[docs]class GetUserOut(pdt.BaseModel):
"""
Model for ``GET /user/{character_name}`` responses
"""
alliance: Optional[int]
authorized_to_login: Optional[bool]
available_esi_scopes: List[EsiScope]
character_id: int
character_name: str
clearance_level: int
coalitions: List[str]
corporation: Optional[str]
created_on: datetime
cumulated_mandatory_esi_scopes: List[EsiScope]
is_ceo_of_alliance: bool
is_ceo_of_corporation: bool
tickered_name: str
updated_on: datetime
[docs] @staticmethod
def from_record(usr: User) -> "GetUserOut":
"""
Populates a new :class:`sni.routers.user.GetUserOut` with the information
contained in a user database record.
"""
return GetUserOut(
alliance=(
usr.alliance.alliance_id if usr.alliance is not None else None
),
authorized_to_login=usr.authorized_to_login,
available_esi_scopes=list(available_esi_scopes(usr)),
character_id=usr.character_id,
character_name=usr.character_name,
clearance_level=usr.clearance_level,
coalitions=[str(coalition.pk) for coalition in usr.coalitions()],
corporation=(
usr.corporation.corporation_id
if usr.corporation is not None
else None
),
created_on=usr.created_on,
cumulated_mandatory_esi_scopes=list(
usr.cumulated_mandatory_esi_scopes()
),
is_ceo_of_alliance=usr.is_ceo_of_alliance(),
is_ceo_of_corporation=usr.is_ceo_of_corporation(),
tickered_name=usr.tickered_name,
updated_on=usr.updated_on,
)
[docs]class PutUserIn(pdt.BaseModel):
"""
Model for ``PUT /user/{character_id}`` requests
"""
authorized_to_login: Optional[bool]
clearance_level: Optional[int]
[docs]@router.get(
"", response_model=List[GetUserShortOut], summary="Get the user list",
)
def get_user(tkn: Token = Depends(from_authotization_header_nondyn)):
"""
Returns the list of all user names. Requires a clearance level of 0 or
more.
"""
assert_has_clearance(tkn.owner, "sni.read_user")
return [
GetUserShortOut.from_record(usr)
for usr in User.objects(clearance_level__gte=0).order_by(
"character_name"
)
]
[docs]@router.delete(
"/{character_id}", summary="Delete a user",
)
def delete_user(
character_id: int, tkn: Token = Depends(from_authotization_header_nondyn)
):
"""
Deletes a user. Requires a clearance level of 9 or more.
"""
assert_has_clearance(tkn.owner, "sni.delete_user")
usr: User = User.objects.get(character_id=character_id)
usr.delete()
[docs]@router.get(
"/{character_id}",
response_model=GetUserOut,
summary="Get basic informations about a user",
)
def get_user_name(
character_id: int, tkn: Token = Depends(from_authotization_header_nondyn)
):
"""
Returns details about a character. Requires a clearance level of 0 or more.
"""
assert_has_clearance(tkn.owner, "sni.read_user")
usr = User.objects.get(character_id=character_id)
return GetUserOut.from_record(usr)
[docs]@router.put(
"/{character_id}", response_model=GetUserOut, summary="Update a user",
)
def put_user_name(
character_id: int,
data: PutUserIn,
tkn: Token = Depends(from_authotization_header_nondyn),
):
"""
Manually updates non ESI data about a character. The required clearance
level depends on the modification.
"""
usr: User = User.objects.get(character_id=character_id)
if data.clearance_level is not None:
if not 0 <= data.clearance_level <= 10:
raise HTTPException(
status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Field clearance_level must be between 0 and 10 (inclusive).",
)
scope_name = f"sni.set_clearance_level_{data.clearance_level}"
assert_has_clearance(tkn.owner, scope_name, usr)
usr.clearance_level = data.clearance_level
if data.authorized_to_login is not None:
assert_has_clearance(tkn.owner, "sni.set_authorized_to_login")
usr.authorized_to_login = data.authorized_to_login
usr.save()
return GetUserOut.from_record(usr)