Added Fienta integration
This commit is contained in:
@@ -7,7 +7,7 @@ Environment variables (set in .env):
|
||||
PB_URL Base URL of PocketBase (default: http://127.0.0.1:8090)
|
||||
PB_ADMIN_EMAIL PocketBase admin e-mail
|
||||
PB_ADMIN_PASSWORD PocketBase admin password
|
||||
PB_ECONOMY_COLLECTION_DEV / PB_ECONOMY_COLLECTION_ECONOMY
|
||||
PB_ECONOMY_COLLECTION_DEV / PB_ECONOMY_COLLECTION_ECONOMY / PB_ECONOMY_COLLECTION_LAN
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -75,16 +75,28 @@ async def _hdrs() -> dict[str, str]:
|
||||
return {"Authorization": await _ensure_auth()}
|
||||
|
||||
|
||||
def _escape_filter_value(value: str) -> str:
|
||||
return value.replace("\\", "\\\\").replace('"', '\\"')
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CRUD helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def get_record(user_id: str) -> dict[str, Any] | None:
|
||||
"""Fetch one economy record by Discord user_id. Returns None if not found."""
|
||||
return await get_first_record(
|
||||
ECONOMY_COLLECTION,
|
||||
f'user_id="{_escape_filter_value(user_id)}"',
|
||||
)
|
||||
|
||||
|
||||
async def get_first_record(collection: str, filter_expr: str) -> dict[str, Any] | None:
|
||||
"""Fetch one record from any collection by a PocketBase filter expression."""
|
||||
session = _get_session()
|
||||
async with session.get(
|
||||
f"{PB_URL}/api/collections/{ECONOMY_COLLECTION}/records",
|
||||
params={"filter": f'user_id="{user_id}"', "perPage": 1},
|
||||
f"{PB_URL}/api/collections/{collection}/records",
|
||||
params={"filter": filter_expr, "perPage": 1},
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
resp.raise_for_status()
|
||||
@@ -93,11 +105,22 @@ async def get_record(user_id: str) -> dict[str, Any] | None:
|
||||
return items[0] if items else None
|
||||
|
||||
|
||||
async def get_record_by_field(collection: str, field: str, value: str) -> dict[str, Any] | None:
|
||||
"""Fetch one record where `field` exactly equals `value`."""
|
||||
escaped = _escape_filter_value(value)
|
||||
return await get_first_record(collection, f'{field}="{escaped}"')
|
||||
|
||||
|
||||
async def create_record(record: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Create a new economy record. Returns the created record (includes PB id)."""
|
||||
return await create_record_in(ECONOMY_COLLECTION, record)
|
||||
|
||||
|
||||
async def create_record_in(collection: str, record: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Create a new record in any collection. Returns the created record."""
|
||||
session = _get_session()
|
||||
async with session.post(
|
||||
f"{PB_URL}/api/collections/{ECONOMY_COLLECTION}/records",
|
||||
f"{PB_URL}/api/collections/{collection}/records",
|
||||
json=record,
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
@@ -109,9 +132,14 @@ async def create_record(record: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
async def update_record(record_id: str, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""PATCH an existing record by its PocketBase record id."""
|
||||
return await update_record_in(ECONOMY_COLLECTION, record_id, data)
|
||||
|
||||
|
||||
async def update_record_in(collection: str, record_id: str, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""PATCH an existing record in any collection by its PocketBase record id."""
|
||||
session = _get_session()
|
||||
async with session.patch(
|
||||
f"{PB_URL}/api/collections/{ECONOMY_COLLECTION}/records/{record_id}",
|
||||
f"{PB_URL}/api/collections/{collection}/records/{record_id}",
|
||||
json=data,
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
@@ -121,9 +149,14 @@ async def update_record(record_id: str, data: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
async def count_records() -> int:
|
||||
"""Return the total number of records in the collection (single cheap request)."""
|
||||
return await count_records_in(ECONOMY_COLLECTION)
|
||||
|
||||
|
||||
async def count_records_in(collection: str) -> int:
|
||||
"""Return the total number of records in any collection."""
|
||||
session = _get_session()
|
||||
async with session.get(
|
||||
f"{PB_URL}/api/collections/{ECONOMY_COLLECTION}/records",
|
||||
f"{PB_URL}/api/collections/{collection}/records",
|
||||
params={"perPage": 1, "page": 1},
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
@@ -134,13 +167,18 @@ async def count_records() -> int:
|
||||
|
||||
async def list_all_records(page_size: int = 500) -> list[dict[str, Any]]:
|
||||
"""Fetch every record in the collection, handling PocketBase pagination."""
|
||||
return await list_all_records_in(ECONOMY_COLLECTION, page_size=page_size)
|
||||
|
||||
|
||||
async def list_all_records_in(collection: str, page_size: int = 500) -> list[dict[str, Any]]:
|
||||
"""Fetch every record in any collection, handling PocketBase pagination."""
|
||||
results: list[dict[str, Any]] = []
|
||||
page = 1
|
||||
session = _get_session()
|
||||
hdrs = await _hdrs()
|
||||
while True:
|
||||
async with session.get(
|
||||
f"{PB_URL}/api/collections/{ECONOMY_COLLECTION}/records",
|
||||
f"{PB_URL}/api/collections/{collection}/records",
|
||||
params={"perPage": page_size, "page": page},
|
||||
headers=hdrs,
|
||||
) as resp:
|
||||
@@ -152,3 +190,51 @@ async def list_all_records(page_size: int = 500) -> list[dict[str, Any]]:
|
||||
break
|
||||
page += 1
|
||||
return results
|
||||
|
||||
|
||||
async def upsert_record_by_field(
|
||||
collection: str,
|
||||
field: str,
|
||||
value: str,
|
||||
data: dict[str, Any],
|
||||
) -> tuple[dict[str, Any], bool]:
|
||||
"""Create or update a record. Returns (record, created)."""
|
||||
existing = await get_record_by_field(collection, field, value)
|
||||
if existing:
|
||||
return await update_record_in(collection, existing["id"], data), False
|
||||
return await create_record_in(collection, data), True
|
||||
|
||||
|
||||
async def get_collection(collection: str) -> dict[str, Any] | None:
|
||||
"""Fetch collection metadata, returning None if it doesn't exist."""
|
||||
session = _get_session()
|
||||
async with session.get(
|
||||
f"{PB_URL}/api/collections/{collection}",
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
if resp.status == 404:
|
||||
return None
|
||||
resp.raise_for_status()
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def create_collection(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Create a PocketBase collection from a full collection payload."""
|
||||
session = _get_session()
|
||||
async with session.post(
|
||||
f"{PB_URL}/api/collections",
|
||||
json=payload,
|
||||
headers=await _hdrs(),
|
||||
) as resp:
|
||||
if resp.status not in (200, 201):
|
||||
text = await resp.text()
|
||||
raise RuntimeError(f"PocketBase collection create failed ({resp.status}): {text}")
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def ensure_collection(collection: str, payload: dict[str, Any]) -> bool:
|
||||
"""Create `collection` when missing. Returns True if created."""
|
||||
if await get_collection(collection):
|
||||
return False
|
||||
await create_collection(payload)
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user