1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00

Start work on the osu updater

This commit is contained in:
Steffo 2020-07-22 01:39:04 +02:00
parent dff7127a38
commit 347fd489ca
8 changed files with 234 additions and 0 deletions

View file

@ -37,6 +37,7 @@ from .steampowered import SteampoweredCommand
from .treasure import TreasureCommand
from .trivia import TriviaCommand
from .userinfo import UserinfoCommand
from .osu import OsuCommand
# Enter the commands of your Pack here!
available_commands = [
@ -78,6 +79,7 @@ available_commands = [
TreasureCommand,
TriviaCommand,
UserinfoCommand,
OsuCommand,
]
# Don't change this, it should automatically generate __all__

71
royalpack/commands/osu.py Normal file
View file

@ -0,0 +1,71 @@
from typing import *
import itsdangerous
from royalnet.backpack import tables as rbt
import royalnet.commands as rc
from .abstract.linker import LinkerCommand
from ..types import Updatable
from ..stars.api_auth_login_osu import ApiAuthLoginOsuStar
class OsuCommand(LinkerCommand):
name = "osu"
description = "Connetti e sincronizza il tuo account di osu!"
@property
def client_id(self):
return self.config[self.name]['client_id']
@property
def client_secret(self):
return self.config[self.name]['client_secret']
@property
def base_url(self):
return self.config['base_url']
@property
def secret_key(self):
return self.config['secret_key']
async def get_updatables_of_user(self, session, user: rbt.User) -> List[Updatable]:
return []
async def get_updatables(self, session) -> List[Updatable]:
return []
async def create(self,
session,
user: rbt.User,
args: rc.CommandArgs,
data: Optional[rc.CommandData] = None) -> Optional[Updatable]:
serializer = itsdangerous.URLSafeSerializer(self.secret_key, salt="osu")
await data.reply("🔑 [b]Login necessario[/b]\n"
f"[url=https://osu.ppy.sh/oauth/authorize"
f"?client_id={self.client_id}"
f"&redirect_uri={self.base_url}{ApiAuthLoginOsuStar.path}"
f"&response_type=code"
f"&state={serializer.dumps(user.uid)}]"
f"Connetti osu! a Royalnet"
f"[/url]")
return None
async def update(self, session, obj, change: Callable[[str, Any], Awaitable[None]]):
pass
async def on_increase(self, session, obj: Updatable, attribute: str, old: Any, new: Any) -> None:
pass
async def on_unchanged(self, session, obj: Updatable, attribute: str, old: Any, new: Any) -> None:
pass
async def on_decrease(self, session, obj: Updatable, attribute: str, old: Any, new: Any) -> None:
pass
async def on_first(self, session, obj: Updatable, attribute: str, old: None, new: Any) -> None:
pass
async def on_reset(self, session, obj: Updatable, attribute: str, old: Any, new: None) -> None:
pass

View file

@ -13,6 +13,7 @@ from .api_cvstats_avg import ApiCvstatsAvgStar
from .api_user_ryg import ApiUserRygStar
from .api_user_ryg_list import ApiUserRygListStar
from .api_user_avatar import ApiUserAvatarStar
from .api_auth_login_osu import ApiAuthLoginOsuStar
# Enter the PageStars of your Pack here!
available_page_stars = [
@ -30,6 +31,7 @@ available_page_stars = [
ApiUserRygStar,
ApiUserRygListStar,
ApiUserAvatarStar,
ApiAuthLoginOsuStar,
]
# Don't change this, it should automatically generate __all__

View file

@ -0,0 +1,86 @@
import royalnet.utils as ru
import royalnet.backpack.tables as rbt
import royalnet.constellation.api as rca
import itsdangerous
import aiohttp
import aiohttp.client_exceptions
import datetime
from ..types import oauth_refresh
from ..tables import Osu, FiorygiTransaction
class ApiAuthLoginOsuStar(rca.ApiStar):
path = "/api/auth/login/osu/v1"
parameters = {
"get": {
"code": "The code returned by the osu! API.",
"state": "(Optional) The state payload generated by the osu! command to link a new account. "
"If missing, just login."
}
}
auth = {
"get": False,
}
tags = ["auth"]
@property
def client_id(self):
return self.config['osu']['client_id']
@property
def client_secret(self):
return self.config['osu']['client_secret']
@property
def base_url(self):
return self.config['base_url']
@property
def secret_key(self):
return self.config['secret_key']
@rca.magic
async def get(self, data: rca.ApiData) -> ru.JSON:
"""Login to Royalnet with your osu! account."""
OsuT = self.alchemy.get(Osu)
code = data.str("code")
state = data.str("state", optional=True)
if state is not None:
serializer = itsdangerous.URLSafeSerializer(self.config["secret_key"], salt="osu")
uid = serializer.loads(state)
user = await rbt.User.find(self.alchemy, data.session, uid)
else:
user = None
try:
t = await oauth_refresh(url="https://osu.ppy.sh/oauth/token",
client_id=self.client_id,
client_secret=self.client_secret,
redirect_uri=f"{self.base_url}{self.path}",
refresh_code=code)
except aiohttp.client_exceptions.ClientResponseError:
raise rca.ForbiddenError("osu! API returned an error in the OAuth token exchange")
async with aiohttp.ClientSession(headers={"Authorization": f"Bearer {t['access_token']}"}) as session:
async with session.get("https://osu.ppy.sh/api/v2/me/") as response:
m = await response.json()
if user is not None:
osu = OsuT(
user=user,
access_token=t["access_token"],
refresh_token=t["refresh_token"],
expiration_date=datetime.datetime.now() + datetime.timedelta(seconds=t["expires_in"]),
osu_id=m["id"],
username=m["username"]
)
data.session.add(osu)
await data.session_commit()
raise rca.MethodNotImplementedError()

View file

@ -18,6 +18,7 @@ from .mmevents import MMEvent
from .mmresponse import MMResponse
from .cvstats import Cvstats
from .treasure import Treasure
from .osu import Osu
# Enter the tables of your Pack here!
available_tables = [
@ -40,6 +41,7 @@ available_tables = [
MMResponse,
Cvstats,
Treasure,
Osu,
]
# Don't change this, it should automatically generate __all__

55
royalpack/tables/osu.py Normal file
View file

@ -0,0 +1,55 @@
from typing import *
import aiohttp
import datetime
from sqlalchemy import *
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declared_attr
from ..types import Updatable, oauth_refresh
# noinspection PyAttributeOutsideInit
class Osu(Updatable):
__tablename__ = "osu"
@declared_attr
def user_id(self):
return Column(Integer, ForeignKey("users.uid"))
@declared_attr
def user(self):
return relationship("User", backref=backref("osu"))
@declared_attr
def access_token(self):
return Column(String, nullable=False)
@declared_attr
def refresh_token(self):
return Column(String, nullable=False)
@declared_attr
def expiration_date(self):
return Column(DateTime, nullable=False)
@declared_attr
def osu_id(self):
return Column(Integer, primary_key=True)
@declared_attr
def username(self):
return Column(String)
async def refresh(self, *, client_id, client_secret, base_url, path):
j = await oauth_refresh(url="https://osu.ppy.sh/oauth/token",
client_id=client_id,
client_secret=client_secret,
redirect_uri=f"{base_url}{path}",
refresh_code=self.refresh_token)
self.access_token = j["access_token"]
self.refresh_token = j["refresh_token"]
self.expiration_date = datetime.datetime.now() + datetime.timedelta(seconds=j["expires_in"])
async def refresh_if_expired(self, *, client_id, client_secret, base_url, path):
if datetime.datetime.now() >= self.expiration_date:
await self.refresh(client_id=client_id, client_secret=client_secret, base_url=base_url, path=path)

View file

@ -11,6 +11,7 @@ from .brawlhallametal import BrawlhallaMetal
from .brawlhallarank import BrawlhallaRank
from .pollmood import PollMood
from .updatable import Updatable
from .oauth_refresh import oauth_refresh
__all__ = [
@ -28,4 +29,5 @@ __all__ = [
"BrawlhallaTier",
"PollMood",
"Updatable",
"oauth_refresh",
]

View file

@ -0,0 +1,14 @@
import aiohttp
async def oauth_refresh(*, url, client_id, client_secret, redirect_uri, refresh_code):
async with aiohttp.ClientSession() as session:
async with session.post(url, data={
"client_id": client_id,
"client_secret": client_secret,
"code": refresh_code,
"grant_type": "authorization_code",
"redirect_uri": redirect_uri
}) as response:
j = await response.json()
return j