From cb9824f83a27ae7099f70ddb755ed408b9c439bd Mon Sep 17 00:00:00 2001 From: Martastain Date: Mon, 25 Dec 2023 13:18:55 +0100 Subject: [PATCH] fixed some docstrings --- backend/api/auth.py | 25 ++++++++++++++++++++----- backend/api/delete.py | 2 +- backend/api/jobs/jobs.py | 7 +++---- backend/api/services.py | 4 +--- backend/api/sessions.py | 15 +++++++++++---- backend/api/set.py | 10 ++++++---- backend/api/solve.py | 4 +++- backend/nebula/version.py | 1 - backend/server/endpoints.py | 2 +- 9 files changed, 46 insertions(+), 24 deletions(-) diff --git a/backend/api/auth.py b/backend/api/auth.py index 8830a5ee..4bdd5f7d 100644 --- a/backend/api/auth.py +++ b/backend/api/auth.py @@ -66,16 +66,19 @@ async def check_failed_login(ip_address: str) -> None: async def set_failed_login(ip_address: str): ns = "login-failed-ip" - failed_attempts = await nebula.redis.incr(ns, ip_address) + failed_attempts_str = await nebula.redis.incr(ns, ip_address) + failed_attempts = int(failed_attempts_str) if failed_attempts_str else 0 + await nebula.redis.expire( ns, ip_address, 600 ) # this is just for the clean-up, it cannot be used to reset the counter if failed_attempts > nebula.config.max_failed_login_attempts: + ban_time = nebula.config.failed_login_ban_time or 0 await nebula.redis.set( "banned-ip-until", ip_address, - time.time() + nebula.config.failed_login_ban_time, + str(time.time() + ban_time), ) @@ -84,7 +87,15 @@ async def clear_failed_login(ip_address: str): class LoginRequest(APIRequest): - """Login using a username and password""" + """Login using a username and password + + This request will return an access token that can be used in the + Authorization header for the subsequent requests. + If the login fails, request will return 401 Unauthorized. + + If the login fails too many (configurable) times, + the IP address will be banned for a certain amount of time (configurable). + """ name: str = "login" response_model = LoginResponseModel @@ -94,6 +105,7 @@ async def handle( request: Request, payload: LoginRequestModel, ) -> LoginResponseModel: + if request is not None: await check_failed_login(get_real_ip(request)) @@ -113,7 +125,10 @@ async def handle( class LogoutRequest(APIRequest): - """Log out the current user""" + """Log out the current user. + + This request will invalidate the access token used in the Authorization header. + """ name: str = "logout" title: str = "Logout" @@ -144,7 +159,7 @@ async def handle( self, request: PasswordRequestModel, user: CurrentUser, - ): + ) -> Response: if request.login: if not user.is_admin: raise nebula.UnauthorizedException( diff --git a/backend/api/delete.py b/backend/api/delete.py index 18f14436..ef811efc 100644 --- a/backend/api/delete.py +++ b/backend/api/delete.py @@ -69,7 +69,7 @@ async def handle( case _: # do not delete bins directly raise nebula.NotImplementedException( - f"Deleting {request.obejct_type} is not implemented" + f"Deleting {request.object_type} is not implemented" ) # Delete simple objects diff --git a/backend/api/jobs/jobs.py b/backend/api/jobs/jobs.py index 8ac9d3d7..346142cd 100644 --- a/backend/api/jobs/jobs.py +++ b/backend/api/jobs/jobs.py @@ -182,18 +182,17 @@ async def set_priority(id_job: int, priority: int, user: nebula.User) -> None: class JobsRequest(APIRequest): - """List and control jobs""" + """Get list of jobs, abort or restart them""" name: str = "jobs" - title: str = "Get list of jobs, abort or restart them" + title: str = "List and control jobs" response_model = JobsResponseModel async def handle( self, request: JobsRequestModel, user: CurrentUser, - ) -> JobsResponseModel: - + ) -> JobsResponseModel | Response: if request.abort: await abort_job(request.abort, user) diff --git a/backend/api/services.py b/backend/api/services.py index 70e95da9..67b5e8d2 100644 --- a/backend/api/services.py +++ b/backend/api/services.py @@ -45,7 +45,7 @@ class ServicesResponseModel(ResponseModel): class Request(APIRequest): - """Get a list of objects""" + """List and control installed services.""" name: str = "services" title: str = "Service control" @@ -56,8 +56,6 @@ async def handle( request: ServiceRequestModel, user: CurrentUser, ) -> ServicesResponseModel: - """List and control installed services.""" - if request.stop: nebula.log.info(f"Stopping service {request.stop}", user=user.name) await nebula.db.execute( diff --git a/backend/api/sessions.py b/backend/api/sessions.py index 42800d7f..c598e3ea 100644 --- a/backend/api/sessions.py +++ b/backend/api/sessions.py @@ -12,6 +12,8 @@ class SessionsRequest(RequestModel): class Sessions(APIRequest): + """List user sessions.""" + name = "sessions" title = "List sessions" response_model = list[SessionModel] @@ -21,7 +23,6 @@ async def handle( request: SessionsRequest, user: CurrentUser, ) -> list[SessionModel]: - """Create or update an object.""" id_user = request.id_user @@ -46,16 +47,22 @@ class InvalidateSessionRequest(RequestModel): class InvalidateSession(APIRequest): + """Invalidate a user session. + + This endpoint is used to invalidate an user session. It can be used + to remotely log out a user. If the user is an admin, it can also be + used to log out other users. + """ + name = "invalidate_session" - title = "Invalidate session" + title = "Invalidate a session" responses = [204, 201] async def handle( self, payload: InvalidateSessionRequest, user: CurrentUser, - ) -> None: - """Create or update an object.""" + ) -> Response: session = await Session.check(payload.token) if session is None: diff --git a/backend/api/set.py b/backend/api/set.py index 25934bd3..ac7bafc5 100644 --- a/backend/api/set.py +++ b/backend/api/set.py @@ -146,8 +146,10 @@ async def can_modify_object(obj, user: nebula.User): class OperationsRequest(APIRequest): + """Create or update multiple objects in one requests.""" + name: str = "ops" - title: str = "Create / update multiple objects at once" + title: str = "Save multiple objects" response_model = OperationsResponseModel async def handle( @@ -155,7 +157,6 @@ async def handle( request: OperationsRequestModel, user: CurrentUser, ) -> OperationsResponseModel: - """Create or update multiple objects in one requests.""" pool = await nebula.db.pool() result = [] @@ -264,8 +265,10 @@ async def handle( class SetRequest(APIRequest): + """Create or update an object.""" + name = "set" - title = "Create or update an object" + title = "Save an object" response_model = OperationResponseModel async def handle( @@ -273,7 +276,6 @@ async def handle( request: OperationModel, user: CurrentUser, ) -> OperationResponseModel: - """Create or update an object.""" operation = OperationsRequest() result = await operation.handle( diff --git a/backend/api/solve.py b/backend/api/solve.py index 074fb81c..aef79a1a 100644 --- a/backend/api/solve.py +++ b/backend/api/solve.py @@ -53,7 +53,7 @@ class SolveRequestModel(RequestModel): class Request(APIRequest): - """Browse the assets database.""" + """Solve a rundown placeholder""" name: str = "solve" responses: list[int] = [200] @@ -63,6 +63,8 @@ async def handle( request: SolveRequestModel, user: CurrentUser, ) -> Response: + # TODO: check permissions + assert user is not None solver = get_solver(request.solver) diff --git a/backend/nebula/version.py b/backend/nebula/version.py index f8d2069e..58e57409 100644 --- a/backend/nebula/version.py +++ b/backend/nebula/version.py @@ -1,2 +1 @@ __version__ = "6.0.3" - diff --git a/backend/server/endpoints.py b/backend/server/endpoints.py index 02d17ac2..66266ef8 100644 --- a/backend/server/endpoints.py +++ b/backend/server/endpoints.py @@ -101,7 +101,7 @@ def install_endpoints(app: fastapi.FastAPI): app.router.add_api_route( route, endpoint.handle, # type: ignore - name=endpoint.name, + name=endpoint.title or endpoint.name, operation_id=slugify(endpoint.name, separator="_"), methods=endpoint.methods, description=docstring,