Skip to content

Commit d0e09d2

Browse files
committed
Apply fixable lint settings with Ruff
1 parent 38faefc commit d0e09d2

27 files changed

+387
-401
lines changed

backend/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
dsn=constants.FORMS_BACKEND_DSN,
2828
send_default_pii=True,
2929
release=SENTRY_RELEASE,
30-
environment=SENTRY_RELEASE
30+
environment=SENTRY_RELEASE,
3131
)
3232

3333
middleware = [
@@ -36,10 +36,10 @@
3636
allow_origins=["https://forms.pythondiscord.com"],
3737
allow_origin_regex=ALLOW_ORIGIN_REGEX,
3838
allow_headers=[
39-
"Content-Type"
39+
"Content-Type",
4040
],
4141
allow_methods=["*"],
42-
allow_credentials=True
42+
allow_credentials=True,
4343
),
4444
Middleware(DatabaseMiddleware),
4545
Middleware(AuthenticationMiddleware, backend=JWTAuthenticationBackend()),

backend/authentication/backend.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import typing as t
2-
31
import jwt
42
from starlette import authentication
53
from starlette.requests import Request
64

7-
from backend import constants
8-
from backend import discord
5+
from backend import constants, discord
6+
97
# We must import user such way here to avoid circular imports
108
from .user import User
119

@@ -19,20 +17,19 @@ def get_token_from_cookie(cookie: str) -> str:
1917
try:
2018
prefix, token = cookie.split()
2119
except ValueError:
22-
raise authentication.AuthenticationError(
23-
"Unable to split prefix and token from authorization cookie."
24-
)
20+
msg = "Unable to split prefix and token from authorization cookie."
21+
raise authentication.AuthenticationError(msg)
2522

2623
if prefix.upper() != "JWT":
27-
raise authentication.AuthenticationError(
28-
f"Invalid authorization cookie prefix '{prefix}'."
29-
)
24+
msg = f"Invalid authorization cookie prefix '{prefix}'."
25+
raise authentication.AuthenticationError(msg)
3026

3127
return token
3228

3329
async def authenticate(
34-
self, request: Request
35-
) -> t.Optional[tuple[authentication.AuthCredentials, authentication.BaseUser]]:
30+
self,
31+
request: Request,
32+
) -> tuple[authentication.AuthCredentials, authentication.BaseUser] | None:
3633
"""Handles JWT authentication process."""
3734
cookie = request.cookies.get("token")
3835
if not cookie:
@@ -48,21 +45,25 @@ async def authenticate(
4845
scopes = ["authenticated"]
4946

5047
if not payload.get("token"):
51-
raise authentication.AuthenticationError("Token is missing from JWT.")
48+
msg = "Token is missing from JWT."
49+
raise authentication.AuthenticationError(msg)
5250
if not payload.get("refresh"):
53-
raise authentication.AuthenticationError(
54-
"Refresh token is missing from JWT."
55-
)
51+
msg = "Refresh token is missing from JWT."
52+
raise authentication.AuthenticationError(msg)
5653

5754
try:
5855
user_details = payload.get("user_details")
5956
if not user_details or not user_details.get("id"):
60-
raise authentication.AuthenticationError("Improper user details.")
61-
except Exception:
62-
raise authentication.AuthenticationError("Could not parse user details.")
57+
msg = "Improper user details."
58+
raise authentication.AuthenticationError(msg) # noqa: TRY301
59+
except Exception: # noqa: BLE001
60+
msg = "Could not parse user details."
61+
raise authentication.AuthenticationError(msg)
6362

6463
user = User(
65-
token, user_details, await discord.get_member(request.state.db, user_details["id"])
64+
token,
65+
user_details,
66+
await discord.get_member(request.state.db, user_details["id"]),
6667
)
6768
if await user.fetch_admin_status(request.state.db):
6869
scopes.append("admin")

backend/authentication/user.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import typing
21
import typing as t
32

43
import jwt
@@ -16,7 +15,7 @@ def __init__(
1615
self,
1716
token: str,
1817
payload: dict[str, t.Any],
19-
member: typing.Optional[models.DiscordMember],
18+
member: models.DiscordMember | None,
2019
) -> None:
2120
self.token = token
2221
self.payload = payload
@@ -31,11 +30,11 @@ def is_authenticated(self) -> bool:
3130
@property
3231
def display_name(self) -> str:
3332
"""Return username and discriminator as display name."""
34-
return f"{self.payload['username']}#{self.payload['discriminator']}"
33+
return f"{self.payload["username"]}#{self.payload["discriminator"]}"
3534

3635
@property
3736
def discord_mention(self) -> str:
38-
return f"<@{self.payload['id']}>"
37+
return f"<@{self.payload["id"]}>"
3938

4039
@property
4140
def user_id(self) -> str:
@@ -61,9 +60,10 @@ async def get_user_roles(self, database: Database) -> list[str]:
6160
return roles
6261

6362
async def fetch_admin_status(self, database: Database) -> bool:
64-
self.admin = await database.admins.find_one(
65-
{"_id": self.payload["id"]}
66-
) is not None
63+
query = {"_id": self.payload["id"]}
64+
found_admin = await database.admins.find_one(query)
65+
66+
self.admin = found_admin is not None
6767

6868
return self.admin
6969

backend/constants.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
OAUTH2_CLIENT_ID = os.getenv("OAUTH2_CLIENT_ID")
1919
OAUTH2_CLIENT_SECRET = os.getenv("OAUTH2_CLIENT_SECRET")
2020
OAUTH2_REDIRECT_URI = os.getenv(
21-
"OAUTH2_REDIRECT_URI", "https://forms.pythondiscord.com/callback"
21+
"OAUTH2_REDIRECT_URI",
22+
"https://forms.pythondiscord.com/callback",
2223
)
2324

2425
GIT_SHA = os.getenv("GIT_SHA", "dev")
@@ -28,7 +29,7 @@
2829

2930
SECRET_KEY = os.getenv("SECRET_KEY", binascii.hexlify(os.urandom(30)).decode())
3031
DISCORD_BOT_TOKEN = os.getenv("DISCORD_BOT_TOKEN")
31-
DISCORD_GUILD = os.getenv("DISCORD_GUILD", 267624335836053506)
32+
DISCORD_GUILD = os.getenv("DISCORD_GUILD", "267624335836053506")
3233

3334
HCAPTCHA_API_SECRET = os.getenv("HCAPTCHA_API_SECRET")
3435

backend/discord.py

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import datetime
44
import json
5-
import typing
65

76
import httpx
87
import starlette.requests
@@ -17,7 +16,7 @@ async def fetch_bearer_token(code: str, redirect: str, *, refresh: bool) -> dict
1716
data = {
1817
"client_id": constants.OAUTH2_CLIENT_ID,
1918
"client_secret": constants.OAUTH2_CLIENT_SECRET,
20-
"redirect_uri": f"{redirect}/callback"
19+
"redirect_uri": f"{redirect}/callback",
2120
}
2221

2322
if refresh:
@@ -27,9 +26,13 @@ async def fetch_bearer_token(code: str, redirect: str, *, refresh: bool) -> dict
2726
data["grant_type"] = "authorization_code"
2827
data["code"] = code
2928

30-
r = await client.post(f"{constants.DISCORD_API_BASE_URL}/oauth2/token", headers={
31-
"Content-Type": "application/x-www-form-urlencoded"
32-
}, data=data)
29+
r = await client.post(
30+
f"{constants.DISCORD_API_BASE_URL}/oauth2/token",
31+
headers={
32+
"Content-Type": "application/x-www-form-urlencoded",
33+
},
34+
data=data,
35+
)
3336

3437
r.raise_for_status()
3538

@@ -38,9 +41,12 @@ async def fetch_bearer_token(code: str, redirect: str, *, refresh: bool) -> dict
3841

3942
async def fetch_user_details(bearer_token: str) -> dict:
4043
async with httpx.AsyncClient() as client:
41-
r = await client.get(f"{constants.DISCORD_API_BASE_URL}/users/@me", headers={
42-
"Authorization": f"Bearer {bearer_token}"
43-
})
44+
r = await client.get(
45+
f"{constants.DISCORD_API_BASE_URL}/users/@me",
46+
headers={
47+
"Authorization": f"Bearer {bearer_token}",
48+
},
49+
)
4450

4551
r.raise_for_status()
4652

@@ -52,15 +58,17 @@ async def _get_role_info() -> list[models.DiscordRole]:
5258
async with httpx.AsyncClient() as client:
5359
r = await client.get(
5460
f"{constants.DISCORD_API_BASE_URL}/guilds/{constants.DISCORD_GUILD}/roles",
55-
headers={"Authorization": f"Bot {constants.DISCORD_BOT_TOKEN}"}
61+
headers={"Authorization": f"Bot {constants.DISCORD_BOT_TOKEN}"},
5662
)
5763

5864
r.raise_for_status()
5965
return [models.DiscordRole(**role) for role in r.json()]
6066

6167

6268
async def get_roles(
63-
database: Database, *, force_refresh: bool = False
69+
database: Database,
70+
*,
71+
force_refresh: bool = False,
6472
) -> list[models.DiscordRole]:
6573
"""
6674
Get a list of all roles from the cache, or discord API if not available.
@@ -86,23 +94,26 @@ async def get_roles(
8694
if len(roles) == 0:
8795
# Fetch roles from the API and insert into the database
8896
roles = await _get_role_info()
89-
await collection.insert_many({
90-
"name": role.name,
91-
"id": role.id,
92-
"data": role.json(),
93-
"inserted_at": datetime.datetime.now(tz=datetime.timezone.utc),
94-
} for role in roles)
97+
await collection.insert_many(
98+
{
99+
"name": role.name,
100+
"id": role.id,
101+
"data": role.json(),
102+
"inserted_at": datetime.datetime.now(tz=datetime.UTC),
103+
}
104+
for role in roles
105+
)
95106

96107
return roles
97108

98109

99-
async def _fetch_member_api(member_id: str) -> typing.Optional[models.DiscordMember]:
110+
async def _fetch_member_api(member_id: str) -> models.DiscordMember | None:
100111
"""Get a member by ID from the configured guild using the discord API."""
101112
async with httpx.AsyncClient() as client:
102113
r = await client.get(
103114
f"{constants.DISCORD_API_BASE_URL}/guilds/{constants.DISCORD_GUILD}"
104115
f"/members/{member_id}",
105-
headers={"Authorization": f"Bot {constants.DISCORD_BOT_TOKEN}"}
116+
headers={"Authorization": f"Bot {constants.DISCORD_BOT_TOKEN}"},
106117
)
107118

108119
if r.status_code == 404:
@@ -113,8 +124,11 @@ async def _fetch_member_api(member_id: str) -> typing.Optional[models.DiscordMem
113124

114125

115126
async def get_member(
116-
database: Database, user_id: str, *, force_refresh: bool = False
117-
) -> typing.Optional[models.DiscordMember]:
127+
database: Database,
128+
user_id: str,
129+
*,
130+
force_refresh: bool = False,
131+
) -> models.DiscordMember | None:
118132
"""
119133
Get a member from the cache, or from the discord API.
120134
@@ -147,7 +161,7 @@ async def get_member(
147161
await collection.insert_one({
148162
"user": user_id,
149163
"data": member.json(),
150-
"inserted_at": datetime.datetime.now(tz=datetime.timezone.utc),
164+
"inserted_at": datetime.datetime.now(tz=datetime.UTC),
151165
})
152166
return member
153167

@@ -161,7 +175,9 @@ class UnauthorizedError(exceptions.HTTPException):
161175

162176

163177
async def _verify_access_helper(
164-
form_id: str, request: starlette.requests.Request, attribute: str
178+
form_id: str,
179+
request: starlette.requests.Request,
180+
attribute: str,
165181
) -> None:
166182
"""A low level helper to validate access to a form resource based on the user's scopes."""
167183
form = await request.state.db.forms.find_one({"_id": form_id})

backend/middleware.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,20 @@
77

88

99
class DatabaseMiddleware:
10-
1110
def __init__(self, app: ASGIApp) -> None:
1211
self._app = app
1312

1413
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
1514
client: AsyncIOMotorClient = AsyncIOMotorClient(
1615
DATABASE_URL,
17-
tlsAllowInvalidCertificates=True
16+
tlsAllowInvalidCertificates=True,
1817
)
1918
db = client[MONGO_DATABASE]
2019
Request(scope).state.db = db
2120
await self._app(scope, receive, send)
2221

2322

2423
class ProtectedDocsMiddleware:
25-
2624
def __init__(self, app: ASGIApp) -> None:
2725
self._app = app
2826

backend/models/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77

88
__all__ = [
99
"AntiSpam",
10+
"CodeQuestion",
11+
"DiscordMember",
1012
"DiscordRole",
1113
"DiscordUser",
12-
"DiscordMember",
1314
"Form",
15+
"FormList",
1416
"FormResponse",
15-
"CodeQuestion",
1617
"Question",
17-
"FormList",
18-
"ResponseList"
18+
"ResponseList",
1919
]

backend/models/discord_role.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import typing
2-
31
from pydantic import BaseModel
42

53

64
class RoleTags(BaseModel):
75
"""Meta information about a discord role."""
86

9-
bot_id: typing.Optional[str]
10-
integration_id: typing.Optional[str]
7+
bot_id: str | None
8+
integration_id: str | None
119
premium_subscriber: bool
1210

1311
def __init__(self, **data) -> None:
@@ -20,7 +18,7 @@ def __init__(self, **data) -> None:
2018
We manually parse the raw data to determine if the field exists, and give it a useful
2119
bool value.
2220
"""
23-
data["premium_subscriber"] = "premium_subscriber" in data.keys()
21+
data["premium_subscriber"] = "premium_subscriber" in data
2422
super().__init__(**data)
2523

2624

@@ -31,10 +29,10 @@ class DiscordRole(BaseModel):
3129
name: str
3230
color: int
3331
hoist: bool
34-
icon: typing.Optional[str]
35-
unicode_emoji: typing.Optional[str]
32+
icon: str | None
33+
unicode_emoji: str | None
3634
position: int
3735
permissions: str
3836
managed: bool
3937
mentionable: bool
40-
tags: typing.Optional[RoleTags]
38+
tags: RoleTags | None

0 commit comments

Comments
 (0)