cleaned up auth (only use supabase)
This commit is contained in:
parent
b396602dee
commit
c02f08a767
|
|
@ -0,0 +1,7 @@
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
- [ ] Schedule opening
|
||||||
|
- [ ] Notification
|
||||||
|
- [ ] Complete API (for selling)
|
||||||
|
- [ ] Add a scoring for cards pulled
|
||||||
|
- [ ] Multiusers
|
||||||
|
|
@ -5,6 +5,7 @@ description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"apscheduler>=3.11.3",
|
||||||
"dotenv>=0.9.9",
|
"dotenv>=0.9.9",
|
||||||
"httpx>=0.28.1",
|
"httpx>=0.28.1",
|
||||||
"loguru>=0.7.3",
|
"loguru>=0.7.3",
|
||||||
|
|
|
||||||
37
src/app.py
37
src/app.py
|
|
@ -4,9 +4,10 @@ from loguru import logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# from sqlalchemy import create_engine
|
# from sqlalchemy import create_engine
|
||||||
from .lib.utils import EveryRunRotator
|
from .lib.utils import EveryRunRotator, HumanReadable as hr
|
||||||
from .services.wiki_masters import WikiMastersClient
|
from .services.wiki_masters import WikiMastersClient
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
|
|
||||||
class App:
|
class App:
|
||||||
|
|
@ -42,8 +43,38 @@ class App:
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
truc = WikiMastersClient()
|
wm_client = WikiMastersClient()
|
||||||
truc.login(environ.get("ACCOUNT_EMAIL"), environ.get("ACCOUNT_PASSWORD"))
|
user = wm_client.login(
|
||||||
|
environ.get("ACCOUNT_EMAIL"), environ.get("ACCOUNT_PASSWORD")
|
||||||
|
)
|
||||||
|
|
||||||
|
d = user.sync()
|
||||||
|
logger.debug("sync user {}", d.username)
|
||||||
|
packs_remaining = d.packs_remaining
|
||||||
|
packs_last_regen_at = d.packs_last_regen_at
|
||||||
|
|
||||||
|
if packs_remaining == 10:
|
||||||
|
packs_remaining, packs_last_regen_at = wm_client.open_pack(
|
||||||
|
user.auth_cookies
|
||||||
|
)
|
||||||
|
|
||||||
|
# Does this math still works when we are opening the 9th pack ?
|
||||||
|
next_pack_in = WikiMastersClient.ONE_PACK_TIME - (
|
||||||
|
datetime.now(tz=timezone.utc) - packs_last_regen_at
|
||||||
|
)
|
||||||
|
next_run_in = (
|
||||||
|
next_pack_in
|
||||||
|
+ WikiMastersClient.ONE_PACK_TIME * (9 - packs_remaining)
|
||||||
|
- timedelta(seconds=10)
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"Next pack is in {}",
|
||||||
|
hr.seconds_to_human(next_pack_in.total_seconds()),
|
||||||
|
)
|
||||||
|
logger.debug(
|
||||||
|
"We should schedule in {}", hr.seconds_to_human(next_run_in.total_seconds())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import httpx
|
import httpx
|
||||||
|
from dataclasses import dataclass
|
||||||
from supabase import create_client, Client
|
from supabase import create_client, Client
|
||||||
|
from supabase_auth import Session
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta
|
||||||
from ..lib.supabase_cookie import get_auth_cookies
|
from ..lib.supabase_cookie import get_auth_cookies
|
||||||
from ..lib.utils import HumanReadable as hr
|
from typing import Self
|
||||||
# supabase ?
|
# supabase ?
|
||||||
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/token?grant_type=password
|
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/token?grant_type=password
|
||||||
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/user
|
# https://cyrxjeppjqsxxjayfrur.supabase.co/auth/v1/user
|
||||||
|
|
@ -11,6 +13,44 @@ from ..lib.utils import HumanReadable as hr
|
||||||
# https://cyrxjeppjqsxxjayfrur.supabase.co/rest/v1/rpc/sync_profile_packs
|
# https://cyrxjeppjqsxxjayfrur.supabase.co/rest/v1/rpc/sync_profile_packs
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SyncDataSubset:
|
||||||
|
_id: str
|
||||||
|
username: str
|
||||||
|
packs_remaining: int
|
||||||
|
packs_last_regen_at: datetime
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_json(d: dict) -> Self:
|
||||||
|
return SyncDataSubset(
|
||||||
|
d["id"],
|
||||||
|
d["username"],
|
||||||
|
d["packs_remaining"],
|
||||||
|
datetime.fromisoformat(d["packs_last_regen_at"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UserSession:
|
||||||
|
username: str
|
||||||
|
sb_client: Client
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auth_cookies(self):
|
||||||
|
return get_auth_cookies(self.session.model_dump_json().encode("utf-8"))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def session(self):
|
||||||
|
return self.sb_client.auth.get_session()
|
||||||
|
|
||||||
|
def sync(self) -> SyncDataSubset:
|
||||||
|
response = self.sb_client.postgrest.rpc(
|
||||||
|
"sync_profile_packs", {"user_id": self.session.user.id}
|
||||||
|
).execute()
|
||||||
|
|
||||||
|
return SyncDataSubset.from_json(response.data[0])
|
||||||
|
|
||||||
|
|
||||||
class WikiMastersClient:
|
class WikiMastersClient:
|
||||||
BASE_URL = "https://www.wiki-masters.com"
|
BASE_URL = "https://www.wiki-masters.com"
|
||||||
|
|
||||||
|
|
@ -22,12 +62,9 @@ class WikiMastersClient:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.logger = logger.bind(service=self.__class__.__name__)
|
self.logger = logger.bind(service=self.__class__.__name__)
|
||||||
|
self.users: dict[str, UserSession] = {}
|
||||||
|
|
||||||
self.logger.info("creating client for supabase")
|
def open_pack(self, cookies) -> tuple[int, str]:
|
||||||
self.sb_client: Client = create_client(self.SUPABASE_URL, self.SUPABASE_KEY)
|
|
||||||
self.logger.info("done creating client for supabase: {}", self.sb_client)
|
|
||||||
|
|
||||||
def open_pack(self, cookies):
|
|
||||||
url = f"{self.BASE_URL}/api/packs/open"
|
url = f"{self.BASE_URL}/api/packs/open"
|
||||||
|
|
||||||
logger.debug("trying to request a pull (cookies:{})", cookies)
|
logger.debug("trying to request a pull (cookies:{})", cookies)
|
||||||
|
|
@ -37,57 +74,28 @@ class WikiMastersClient:
|
||||||
cookies=cookies,
|
cookies=cookies,
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code != 200:
|
||||||
logger.debug("trying to pull: {}", response.json())
|
|
||||||
else:
|
|
||||||
logger.error(
|
logger.error(
|
||||||
"error while opening [{}] {}", response.status_code, response.content
|
"error while opening [{}] {}", response.status_code, response.content
|
||||||
)
|
)
|
||||||
|
raise Exception("Could not pull :'(")
|
||||||
|
|
||||||
def login(self, email, password):
|
pull_data = response.json()
|
||||||
url = f"{self.SUPABASE_URL}/auth/v1/token?grant_type=password"
|
logger.debug("trying to pull: {}", pull_data)
|
||||||
response = httpx.post(
|
|
||||||
url,
|
return (pull_data["packs_remaining"], datetime.fromisoformat(pull_data["packs_last_regen_at"]))
|
||||||
json={"email": email, "password": password, "gotrue_meta_security": {}},
|
|
||||||
headers={
|
def login(self, email, password) -> UserSession:
|
||||||
"ApiKey": self.SUPABASE_KEY,
|
sb_client = create_client(self.SUPABASE_URL, self.SUPABASE_KEY)
|
||||||
"Authorization": f"Bearer {self.SUPABASE_KEY}",
|
response = sb_client.auth.sign_in_with_password(
|
||||||
},
|
{"email": email, "password": password}
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug("trying to login {}", response)
|
if not response.session:
|
||||||
if response.status_code == 200:
|
raise Exception(f"Login failed for {email}")
|
||||||
cookies_compute = get_auth_cookies(response.content)
|
|
||||||
# TODO: save cookies for the current user
|
|
||||||
|
|
||||||
content = response.json()
|
session = response.session
|
||||||
session = self.sb_client.auth.set_session(
|
|
||||||
content["access_token"], content["refresh_token"]
|
|
||||||
)
|
|
||||||
username = session.user.user_metadata["username"]
|
username = session.user.user_metadata["username"]
|
||||||
self.logger.debug("connected with supabase as {}", username)
|
logger.debug("logged user {}", username)
|
||||||
|
|
||||||
response = self.sb_client.postgrest.rpc(
|
return UserSession(username, sb_client)
|
||||||
"sync_profile_packs", {"user_id": session.user.id}
|
|
||||||
).execute()
|
|
||||||
self.logger.info("info sync: {}", response)
|
|
||||||
|
|
||||||
d = response.data[0]
|
|
||||||
_id = d["id"]
|
|
||||||
_username = d["username"]
|
|
||||||
_packs_remaining = d["packs_remaining"]
|
|
||||||
_packs_last_regen_at = datetime.fromisoformat(
|
|
||||||
d["packs_last_regen_at"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Does this math still works when we are opening the 9th pack ?
|
|
||||||
next_pack_in = WikiMastersClient.ONE_PACK_TIME - (
|
|
||||||
datetime.now(tz=timezone.utc) - _packs_last_regen_at
|
|
||||||
)
|
|
||||||
next_run_in = next_pack_in + WikiMastersClient.ONE_PACK_TIME * (9 - _packs_remaining) - timedelta(seconds=10)
|
|
||||||
|
|
||||||
self.logger.info(
|
|
||||||
"Next pack is in {}",
|
|
||||||
hr.seconds_to_human(next_pack_in.total_seconds()),
|
|
||||||
)
|
|
||||||
self.logger.debug("We should schedule in {}", hr.seconds_to_human(next_run_in.total_seconds()))
|
|
||||||
|
|
|
||||||
35
uv.lock
35
uv.lock
|
|
@ -23,6 +23,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
|
{ url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apscheduler"
|
||||||
|
version = "3.11.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "tzlocal" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8c/6b/eeff360196bb20b312c9e762a820fd1b2c6d809466c755ef57863478e454/apscheduler-3.11.3.tar.gz", hash = "sha256:cd2fcc9330039a81a5893472ad49facf23a6d5604cbe1d918c835c6de7834d5a", size = 110312, upload-time = "2026-06-28T19:39:22.493Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl", hash = "sha256:bbeb2ec02d23d3c06a6c07ed7f0f3939ada6680eb121fae809a69bb42c537a30", size = 66024, upload-time = "2026-06-28T19:39:20.982Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2026.7.22"
|
version = "2026.7.22"
|
||||||
|
|
@ -753,6 +765,27 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdata"
|
||||||
|
version = "2026.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzlocal"
|
||||||
|
version = "5.4.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/81/5b/879b2f932adfa7a053c360d50bc896c977fa6426109185f7c12ebdd0cb9d/tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4", size = 31170, upload-time = "2026-06-29T08:03:40.026Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15", size = 18115, upload-time = "2026-06-29T08:03:38.666Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websockets"
|
name = "websockets"
|
||||||
version = "15.0.1"
|
version = "15.0.1"
|
||||||
|
|
@ -778,6 +811,7 @@ name = "wiki-bot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "apscheduler" },
|
||||||
{ name = "dotenv" },
|
{ name = "dotenv" },
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
{ name = "loguru" },
|
{ name = "loguru" },
|
||||||
|
|
@ -787,6 +821,7 @@ dependencies = [
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "apscheduler", specifier = ">=3.11.3" },
|
||||||
{ name = "dotenv", specifier = ">=0.9.9" },
|
{ name = "dotenv", specifier = ">=0.9.9" },
|
||||||
{ name = "httpx", specifier = ">=0.28.1" },
|
{ name = "httpx", specifier = ">=0.28.1" },
|
||||||
{ name = "loguru", specifier = ">=0.7.3" },
|
{ name = "loguru", specifier = ">=0.7.3" },
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue