1
Fork 0
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:
Steffo 2020-02-07 15:36:19 +01:00
parent 741b9f50db
commit bb3aa1fd85
13 changed files with 89 additions and 30 deletions

View file

@ -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__

View file

@ -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")

View file

@ -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
}

View 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()

View file

@ -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):

View file

@ -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)

View file

@ -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

View file

@ -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",
]

View 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

View file

@ -1,6 +0,0 @@
from .apierrors import MissingParameterException
class ApiDataDict(dict):
def __missing__(self, key):
raise MissingParameterException(f"Missing '{key}'")

View file

@ -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

View file

@ -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:

View file

@ -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)