mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-27 13:34:28 +00:00
API login routes completed
This commit is contained in:
parent
741b9f50db
commit
bb3aa1fd85
13 changed files with 89 additions and 30 deletions
|
@ -1,12 +1,14 @@
|
|||
# Imports go here!
|
||||
from .api_royalnet_version import ApiRoyalnetVersionStar
|
||||
from .api_royalnet_login import ApiRoyalnetLoginStar
|
||||
from .api_login_royalnet import ApiLoginRoyalnetStar
|
||||
from .api_token_info import ApiTokenInfoStar
|
||||
|
||||
|
||||
# Enter the PageStars of your Pack here!
|
||||
available_page_stars = [
|
||||
ApiRoyalnetVersionStar,
|
||||
ApiRoyalnetLoginStar,
|
||||
ApiLoginRoyalnetStar,
|
||||
ApiTokenInfoStar,
|
||||
]
|
||||
|
||||
# Don't change this, it should automatically generate __all__
|
||||
|
|
|
@ -6,10 +6,10 @@ from ..tables.aliases import Alias
|
|||
from ..tables.tokens import Token
|
||||
|
||||
|
||||
class ApiRoyalnetLoginStar(ApiStar):
|
||||
path = "/api/royalnet/login/v1"
|
||||
class ApiLoginRoyalnetStar(ApiStar):
|
||||
path = "/api/login/royalnet/v1"
|
||||
|
||||
async def api(self, data: ApiDataDict) -> dict:
|
||||
async def api(self, data: ApiData) -> dict:
|
||||
TokenT = self.alchemy.get(Token)
|
||||
UserT = self.alchemy.get(User)
|
||||
AliasT = self.alchemy.get(Alias)
|
||||
|
@ -20,7 +20,7 @@ class ApiRoyalnetLoginStar(ApiStar):
|
|||
async with self.session_acm() as session:
|
||||
user: User = await ru.asyncify(session.query(UserT).filter_by(username=username).one_or_none)
|
||||
if user is None:
|
||||
raise NotFoundException("User not found")
|
||||
raise NotFoundError("User not found")
|
||||
pswd_check = user.test_password(password)
|
||||
if not pswd_check:
|
||||
raise ApiError("Invalid password")
|
|
@ -5,7 +5,7 @@ from royalnet.constellation.api import *
|
|||
class ApiRoyalnetVersionStar(ApiStar):
|
||||
path = "/api/royalnet/version/v1"
|
||||
|
||||
async def api(self, data: ApiDataDict) -> dict:
|
||||
async def api(self, data: ApiData) -> dict:
|
||||
return {
|
||||
"semantic": rv.semantic
|
||||
}
|
||||
|
|
13
royalnet/backpack/stars/api_token_info.py
Normal file
13
royalnet/backpack/stars/api_token_info.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import datetime
|
||||
import royalnet.utils as ru
|
||||
from royalnet.constellation.api import *
|
||||
from ..tables.users import User
|
||||
from ..tables.aliases import Alias
|
||||
|
||||
|
||||
class ApiTokenInfoStar(ApiStar):
|
||||
path = "/api/token/info/v1"
|
||||
|
||||
async def api(self, data: ApiData) -> dict:
|
||||
token = await data.token()
|
||||
return token.json()
|
|
@ -4,6 +4,7 @@ from sqlalchemy import Column, \
|
|||
ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
import royalnet.utils as ru
|
||||
|
||||
|
||||
class Alias:
|
||||
|
@ -22,10 +23,10 @@ class Alias:
|
|||
return relationship("User", backref="aliases")
|
||||
|
||||
@classmethod
|
||||
def find_user(cls, alchemy, session, alias: str):
|
||||
result = session.query(alchemy.get(cls)).filter_by(alias=alias.lower()).one_or_none()
|
||||
async def find_user(cls, alchemy, session, alias: str):
|
||||
result = await ru.asyncify(session.query(alchemy.get(cls)).filter_by(alias=alias.lower()).one_or_none)
|
||||
if result is not None:
|
||||
result = result.royal
|
||||
result = result.user
|
||||
return result
|
||||
|
||||
def __init__(self, user: str, alias: str):
|
||||
|
|
|
@ -3,6 +3,8 @@ import secrets
|
|||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import *
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
import royalnet.utils as ru
|
||||
from .users import User
|
||||
|
||||
|
||||
class Token:
|
||||
|
@ -40,3 +42,7 @@ class Token:
|
|||
"token": self.token,
|
||||
"expiration": self.expiration.isoformat()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def authenticate(cls, alchemy, session, token: str) -> "Token":
|
||||
return await ru.asyncify(session.query(alchemy.get(cls)).filter_by(token=token).one_or_none)
|
||||
|
|
|
@ -75,7 +75,6 @@ class CommandData:
|
|||
Alias.find_user(self._interface.alchemy, self.session, alias)
|
||||
)
|
||||
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def keyboard(self, text, keys: List["KeyboardKey"]):
|
||||
yield
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from .apistar import ApiStar
|
||||
from .jsonapi import api_response, api_success, api_error
|
||||
from .apidatadict import ApiDataDict
|
||||
from .apierrors import ApiError, MissingParameterException, NotFoundException, UnauthorizedException
|
||||
from .apidata import ApiData
|
||||
from .apierrors import ApiError, MissingParameterError, NotFoundError, ForbiddenError
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -9,8 +9,8 @@ __all__ = [
|
|||
"api_response",
|
||||
"api_success",
|
||||
"api_error",
|
||||
"ApiDataDict",
|
||||
"ApiData",
|
||||
"ApiError",
|
||||
"MissingParameterException",
|
||||
"NotFoundException",
|
||||
"MissingParameterError",
|
||||
"NotFoundError",
|
||||
]
|
||||
|
|
31
royalnet/constellation/api/apidata.py
Normal file
31
royalnet/constellation/api/apidata.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from .apierrors import MissingParameterError
|
||||
from royalnet.backpack.tables.tokens import Token
|
||||
from royalnet.backpack.tables.users import User
|
||||
from .apierrors import *
|
||||
|
||||
|
||||
class ApiData(dict):
|
||||
def __init__(self, data, star):
|
||||
super().__init__(data)
|
||||
self.star = star
|
||||
self._session = None
|
||||
|
||||
def __missing__(self, key):
|
||||
raise MissingParameterError(f"Missing '{key}'")
|
||||
|
||||
async def token(self) -> Token:
|
||||
token = await Token.authenticate(self.star.alchemy, self.session, self["token"])
|
||||
if token is None:
|
||||
raise ForbiddenError("'token' is invalid")
|
||||
return token
|
||||
|
||||
async def user(self) -> Token:
|
||||
return (await self.token()).user
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
if self._session is None:
|
||||
if self.star.alchemy is None:
|
||||
raise UnsupportedError("'alchemy' is not enabled on this Royalnet instance")
|
||||
self._session = self.star.alchemy.Session()
|
||||
return self._session
|
|
@ -1,6 +0,0 @@
|
|||
from .apierrors import MissingParameterException
|
||||
|
||||
|
||||
class ApiDataDict(dict):
|
||||
def __missing__(self, key):
|
||||
raise MissingParameterException(f"Missing '{key}'")
|
|
@ -2,13 +2,21 @@ class ApiError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class NotFoundException(ApiError):
|
||||
class NotFoundError(ApiError):
|
||||
pass
|
||||
|
||||
|
||||
class UnauthorizedException(ApiError):
|
||||
class ForbiddenError(ApiError):
|
||||
pass
|
||||
|
||||
|
||||
class MissingParameterException(ApiError):
|
||||
class MissingParameterError(ApiError):
|
||||
pass
|
||||
|
||||
|
||||
class NotImplementedError(ApiError):
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedError(NotImplementedError):
|
||||
pass
|
||||
|
|
|
@ -5,8 +5,8 @@ from starlette.requests import Request
|
|||
from starlette.responses import JSONResponse
|
||||
from ..pagestar import PageStar
|
||||
from .jsonapi import api_error, api_success
|
||||
from .apidatadict import ApiDataDict
|
||||
from .apierrors import ApiError, NotFoundException
|
||||
from .apidata import ApiData
|
||||
from .apierrors import *
|
||||
|
||||
|
||||
class ApiStar(PageStar, ABC):
|
||||
|
@ -19,9 +19,13 @@ class ApiStar(PageStar, ABC):
|
|||
except JSONDecodeError:
|
||||
data = {}
|
||||
try:
|
||||
response = await self.api(ApiDataDict(data))
|
||||
except NotFoundException as e:
|
||||
response = await self.api(ApiData(data, self))
|
||||
except NotFoundError as e:
|
||||
return api_error(e, code=404)
|
||||
except ForbiddenError as e:
|
||||
return api_error(e, code=403)
|
||||
except NotImplementedError as e:
|
||||
return api_error(e, code=501)
|
||||
except ApiError as e:
|
||||
return api_error(e, code=400)
|
||||
except Exception as e:
|
||||
|
|
|
@ -27,6 +27,7 @@ def api_error(error: Exception, code: int = 500) -> JSONResponse:
|
|||
result = {
|
||||
"success": False,
|
||||
"error_type": error.__class__.__qualname__,
|
||||
"error_args": list(error.args)
|
||||
"error_args": list(error.args),
|
||||
"error_code": code,
|
||||
}
|
||||
return api_response(result, code=code)
|
||||
|
|
Loading…
Reference in a new issue