From 134b2f70e4cf947744f1b061766bb37fe616ad65 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 5 Feb 2022 16:50:11 +0400 Subject: Overhaul Scope System Adds discord role support to the pre-existing scopes system to power more complex access permissions. Signed-off-by: Hassan Abouelela --- backend/routes/discord.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 backend/routes/discord.py (limited to 'backend/routes/discord.py') diff --git a/backend/routes/discord.py b/backend/routes/discord.py new file mode 100644 index 0000000..a980d94 --- /dev/null +++ b/backend/routes/discord.py @@ -0,0 +1,83 @@ +"""Routes which directly interact with discord related data.""" + +import pydantic +from spectree import Response +from starlette.authentication import requires +from starlette.responses import JSONResponse +from starlette.routing import Request + +from backend import discord, models, route +from backend.validation import ErrorMessage, OkayResponse, api + +NOT_FOUND_EXCEPTION = JSONResponse( + {"error": "Could not find the requested resource in the guild or cache."}, status_code=404 +) + + +class RolesRoute(route.Route): + """Refreshes the roles database.""" + + name = "roles" + path = "/roles" + + class RolesResponse(pydantic.BaseModel): + """A list of all roles on the configured server.""" + + roles: list[models.DiscordRole] + + @requires(["authenticated", "admin"]) + @api.validate( + resp=Response(HTTP_200=OkayResponse), + tags=["roles"] + ) + async def patch(self, request: Request) -> JSONResponse: + """Refresh the roles database.""" + roles = await discord.get_roles(request.state.db, force_refresh=True) + + return JSONResponse( + {"status": "ok"}, + ) + + +class MemberRoute(route.Route): + """Retrieve information about a server member.""" + + name = "member" + path = "/member" + + class MemberRequest(pydantic.BaseModel): + """An ID of the member to update.""" + + user_id: str + + @requires(["authenticated", "admin"]) + @api.validate( + resp=Response(HTTP_200=models.DiscordMember, HTTP_400=ErrorMessage), + json=MemberRequest, + tags=["auth"] + ) + async def delete(self, request: Request): + """Force a resync of the cache for the given user.""" + body = await request.json() + member = await discord.get_member(request.state.db, body["user_id"], force_refresh=True) + + if member: + return JSONResponse(member.dict()) + else: + return NOT_FOUND_EXCEPTION + + @requires(["authenticated", "admin"]) + @api.validate( + resp=Response(HTTP_200=models.DiscordMember, HTTP_400=ErrorMessage), + json=MemberRequest, + tags=["auth"] + ) + async def get(self, request: Request): + """Get a user's roles on the configured server.""" + body = await request.json() + member = await discord.get_member(request.state.db, body["user_id"]) + + if member: + return JSONResponse(member.dict()) + else: + return NOT_FOUND_EXCEPTION -- cgit v1.2.3 From c4f816c576097d78c5645113115bbcaa29f7a1ee Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 5 Feb 2022 18:49:45 +0400 Subject: Fix Linting Errors Signed-off-by: Hassan Abouelela --- backend/models/discord_role.py | 2 +- backend/models/form.py | 2 +- backend/routes/discord.py | 10 +++++----- tox.ini | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'backend/routes/discord.py') diff --git a/backend/models/discord_role.py b/backend/models/discord_role.py index 9f0b7dd..c05c9de 100644 --- a/backend/models/discord_role.py +++ b/backend/models/discord_role.py @@ -10,7 +10,7 @@ class RoleTags(BaseModel): integration_id: typing.Optional[str] premium_subscriber: bool - def __init__(self, **data: typing.Any): + def __init__(self, **data: typing.Any) -> None: """ Handle the terrible discord API. diff --git a/backend/models/form.py b/backend/models/form.py index 4ee2804..f888d6e 100644 --- a/backend/models/form.py +++ b/backend/models/form.py @@ -70,7 +70,7 @@ class Form(BaseModel): return value @validator("response_readers", "editors") - def validate_role_scoping(cls, value: t.Optional[list[str]]): + def validate_role_scoping(cls, value: t.Optional[list[str]]) -> t.Optional[list[str]]: """Ensure special role based permissions aren't granted to the @everyone role.""" if value and str(DISCORD_GUILD) in value: raise ValueError("You can not add the everyone role as an access scope.") diff --git a/backend/routes/discord.py b/backend/routes/discord.py index a980d94..bca1edb 100644 --- a/backend/routes/discord.py +++ b/backend/routes/discord.py @@ -7,7 +7,7 @@ from starlette.responses import JSONResponse from starlette.routing import Request from backend import discord, models, route -from backend.validation import ErrorMessage, OkayResponse, api +from backend.validation import ErrorMessage, api NOT_FOUND_EXCEPTION = JSONResponse( {"error": "Could not find the requested resource in the guild or cache."}, status_code=404 @@ -27,7 +27,7 @@ class RolesRoute(route.Route): @requires(["authenticated", "admin"]) @api.validate( - resp=Response(HTTP_200=OkayResponse), + resp=Response(HTTP_200=RolesResponse), tags=["roles"] ) async def patch(self, request: Request) -> JSONResponse: @@ -35,7 +35,7 @@ class RolesRoute(route.Route): roles = await discord.get_roles(request.state.db, force_refresh=True) return JSONResponse( - {"status": "ok"}, + {"roles": [role.dict() for role in roles]}, ) @@ -56,7 +56,7 @@ class MemberRoute(route.Route): json=MemberRequest, tags=["auth"] ) - async def delete(self, request: Request): + async def delete(self, request: Request) -> JSONResponse: """Force a resync of the cache for the given user.""" body = await request.json() member = await discord.get_member(request.state.db, body["user_id"], force_refresh=True) @@ -72,7 +72,7 @@ class MemberRoute(route.Route): json=MemberRequest, tags=["auth"] ) - async def get(self, request: Request): + async def get(self, request: Request) -> JSONResponse: """Get a user's roles on the configured server.""" body = await request.json() member = await discord.get_member(request.state.db, body["user_id"]) diff --git a/tox.ini b/tox.ini index afb3b34..451c3dd 100644 --- a/tox.ini +++ b/tox.ini @@ -5,6 +5,6 @@ docstring-convention=all import-order-style=pycharm ignore= # Type annotations - ANN101,ANN102 + ANN002,ANN003,ANN101,ANN102 # Line breaks W503 -- cgit v1.2.3