Files
Synculous-2/api/routes/rewards.py

115 lines
3.4 KiB
Python

"""
Rewards API - variable reward system for routine completion
"""
import os
import uuid
import random
import flask
import jwt
import core.auth as auth
import core.postgres as postgres
def _get_user_uuid(token):
try:
payload = jwt.decode(token, os.getenv("JWT_SECRET"), algorithms=["HS256"])
return payload.get("sub")
except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
return None
def _auth(request):
header = request.headers.get("Authorization", "")
if not header.startswith("Bearer "):
return None
token = header[7:]
user_uuid = _get_user_uuid(token)
if not user_uuid or not auth.verifyLoginToken(token, userUUID=user_uuid):
return None
return user_uuid
def register(app):
@app.route("/api/rewards/random", methods=["GET"])
def api_getRandomReward():
"""Get a weighted random reward. Query: ?context=completion"""
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
context = flask.request.args.get("context", "completion")
# Fetch all rewards from pool
all_rewards = postgres.select("reward_pool", where={})
if not all_rewards:
return flask.jsonify({"reward": None}), 200
# Weight by rarity: common=70%, uncommon=25%, rare=5%
weights = {
"common": 70,
"uncommon": 25,
"rare": 5,
}
weighted = []
for reward in all_rewards:
w = weights.get(reward.get("rarity", "common"), 70)
weighted.extend([reward] * w)
if not weighted:
return flask.jsonify({"reward": None}), 200
selected = random.choice(weighted)
# Record that user earned this reward
try:
postgres.insert("user_rewards", {
"id": str(uuid.uuid4()),
"user_uuid": user_uuid,
"reward_id": selected["id"],
"context": context,
})
except Exception:
pass # Don't fail if recording fails
return flask.jsonify({
"reward": {
"id": selected["id"],
"category": selected["category"],
"content": selected["content"],
"emoji": selected.get("emoji"),
"rarity": selected.get("rarity", "common"),
}
}), 200
@app.route("/api/rewards/history", methods=["GET"])
def api_getRewardHistory():
"""Get user's past earned rewards."""
user_uuid = _auth(flask.request)
if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401
earned = postgres.select(
"user_rewards",
where={"user_uuid": user_uuid},
order_by="earned_at DESC",
limit=50,
)
# Enrich with reward content
result = []
for entry in earned:
reward = postgres.select_one("reward_pool", {"id": entry["reward_id"]})
if reward:
result.append({
"earned_at": entry["earned_at"],
"context": entry.get("context"),
"category": reward["category"],
"content": reward["content"],
"emoji": reward.get("emoji"),
"rarity": reward.get("rarity"),
})
return flask.jsonify(result), 200