115 lines
3.4 KiB
Python
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
|