Release v2
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Profile:
|
||||
id: str
|
||||
url: str
|
||||
name: str
|
||||
username: str
|
||||
avatar_url: str
|
||||
banner_url: str | None
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json: dict) -> "Profile":
|
||||
return cls(**json)
|
||||
|
||||
def into_json(self) -> dict:
|
||||
return self.__dict__
|
||||
@@ -0,0 +1,69 @@
|
||||
from typing import TypedDict, NotRequired
|
||||
|
||||
from nyekiapi.lib import settings, cache
|
||||
from nyekiapi.lib.requests import httpx
|
||||
from nyekiapi.lib.integrations import Profile
|
||||
|
||||
|
||||
CACHE_BY_ID_KEY = "discord:profile:id:%s"
|
||||
|
||||
|
||||
class DiscordProfile(TypedDict):
|
||||
id: str
|
||||
username: str
|
||||
global_name: str | None
|
||||
discriminator: str
|
||||
avatar: str | None
|
||||
banner: NotRequired[str | None]
|
||||
|
||||
|
||||
def _get_username(user: DiscordProfile) -> str:
|
||||
if user["discriminator"] == "0":
|
||||
return user["username"]
|
||||
|
||||
return f"{user['username']}#{user['discriminator']}"
|
||||
|
||||
|
||||
def _get_avatar_url(user: DiscordProfile) -> str:
|
||||
if user["avatar"] is None:
|
||||
if user["discriminator"] == "0":
|
||||
return f"https://cdn.discordapp.com/embed/avatars/{(int(user['id']) >> 22) % 6}.png?size=256"
|
||||
else:
|
||||
return f"https://cdn.discordapp.com/embed/avatars/{int(user['discriminator']) % 6}.png?size=256"
|
||||
else:
|
||||
return f"https://cdn.discordapp.com/avatars/{user['id']}/{user['avatar']}.png?size=256"
|
||||
|
||||
|
||||
def _get_banner_url(user: DiscordProfile) -> str | None:
|
||||
if "banner" not in user or user["banner"] is None:
|
||||
return None
|
||||
|
||||
return f"https://cdn.discordapp.com/banners/{user['id']}/{user['banner']}.png?size=2048"
|
||||
|
||||
|
||||
async def get_profile_by_id(id: str) -> Profile:
|
||||
profile = await cache.get(CACHE_BY_ID_KEY % id)
|
||||
|
||||
if profile is not None:
|
||||
return Profile.from_json(profile)
|
||||
|
||||
response = await httpx.get(
|
||||
f"https://discord.com/api/v10/users/{id}",
|
||||
headers={"Authorization": f"Bot {settings.DISCORD_TOKEN}"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
data: DiscordProfile = response.json()
|
||||
|
||||
profile = Profile(
|
||||
id=data["id"],
|
||||
url=f"https://discord.com/users/{data['id']}",
|
||||
name=data.get("global_name") or _get_username(data),
|
||||
username=_get_username(data),
|
||||
avatar_url=_get_avatar_url(data),
|
||||
banner_url=_get_banner_url(data),
|
||||
)
|
||||
|
||||
await cache.set(CACHE_BY_ID_KEY % id, profile, expires_in=10 * 60)
|
||||
|
||||
return profile
|
||||
@@ -0,0 +1,82 @@
|
||||
from typing import TypedDict
|
||||
|
||||
from urllib.parse import quote
|
||||
|
||||
from nyekiapi.lib import settings, project, cache
|
||||
from nyekiapi.lib.requests import httpx
|
||||
from nyekiapi.lib.integrations import Profile
|
||||
|
||||
|
||||
CACHE_BY_ID_KEY = "github:profile:id:%s"
|
||||
CACHE_BY_NAME_KEY = "github:profile:name:%s"
|
||||
|
||||
|
||||
class GithubProfile(TypedDict):
|
||||
login: str
|
||||
name: str | None
|
||||
avatar_url: str
|
||||
html_url: str
|
||||
|
||||
|
||||
async def get_profile_by_id(id: str) -> Profile:
|
||||
profile = await cache.get(CACHE_BY_ID_KEY % id)
|
||||
|
||||
if profile is not None:
|
||||
return Profile.from_json(profile)
|
||||
|
||||
response = await httpx.get(
|
||||
f"https://api.github.com/user/{quote(id)}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {settings.GITHUB_TOKEN}",
|
||||
"User-Agent": f"NyekiAPI/{project.PROJECT_VERSION}",
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
data: GithubProfile = response.json()
|
||||
|
||||
profile = Profile(
|
||||
id=id,
|
||||
url=data["html_url"],
|
||||
name=data.get("name") or data["login"],
|
||||
username=data["login"],
|
||||
avatar_url=data["avatar_url"],
|
||||
banner_url=None,
|
||||
)
|
||||
|
||||
await cache.set(CACHE_BY_ID_KEY % profile.id, profile, expires_in=10 * 60)
|
||||
await cache.set(CACHE_BY_NAME_KEY % profile.username, profile, expires_in=10 * 60)
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
async def get_profile_by_name(username: str) -> Profile:
|
||||
profile = await cache.get(CACHE_BY_NAME_KEY % username)
|
||||
|
||||
if profile is not None:
|
||||
return Profile.from_json(profile)
|
||||
|
||||
response = await httpx.get(
|
||||
f"https://api.github.com/users/{quote(username)}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {settings.GITHUB_TOKEN}",
|
||||
"User-Agent": f"NyekiAPI/{project.PROJECT_VERSION}",
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
data: GithubProfile = response.json()
|
||||
|
||||
profile = Profile(
|
||||
id=str(data["id"]),
|
||||
url=data["html_url"],
|
||||
name=data.get("name") or data["login"],
|
||||
username=data["login"],
|
||||
avatar_url=data["avatar_url"],
|
||||
banner_url=None,
|
||||
)
|
||||
|
||||
await cache.set(CACHE_BY_ID_KEY % profile.id, profile, expires_in=10 * 60)
|
||||
await cache.set(CACHE_BY_NAME_KEY % profile.username, profile, expires_in=10 * 60)
|
||||
|
||||
return profile
|
||||
Reference in New Issue
Block a user