Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

urbanstats persistent changes for storing infinite #897

Merged
merged 2 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import time
from typing import List, Tuple

from .utils import corrects_to_bytes

table_for_quiz_kind = {
"juxtastat": "JuxtaStatIndividualStats",
"retrostat": "JuxtaStatIndividualStatsRetrostat",
Expand All @@ -25,6 +27,12 @@ def table():
"""CREATE TABLE IF NOT EXISTS JuxtaStatIndividualStatsRetrostat
(user integer, week integer, corrects integer, time integer, PRIMARY KEY (user, week))"""
)
# juxtastat infinite
c.execute(
"""CREATE TABLE IF NOT EXISTS JuxtaStatInfiniteStats
(user integer, seed string, version integer, corrects varbinary(128), score integer, num_answers integer, time integer, PRIMARY KEY (user, seed, version))"""
)

# user to domain name
c.execute(
"""
Expand Down Expand Up @@ -158,6 +166,38 @@ def store_user_stats_retrostat(user, week_stats: List[Tuple[int, List[bool]]]):
store_user_stats_into_table(user, week_stats, "JuxtaStatIndividualStatsRetrostat")


def has_infinite_stats(user, seeds_versions):
user = int(user, 16)
_, c = table()
c.execute(
"SELECT seed, version FROM JuxtaStatInfiniteStats WHERE user=?",
(user,),
)
results = c.fetchall()
results = set(results)
return [(seed, version) in results for seed, version in seeds_versions]


def store_user_stats_infinite(user, seed, version, corrects: List[bool]):
user = int(user, 16)
conn, c = table()
correctBytes = corrects_to_bytes(corrects)
time_unix_millis = round(time.time() * 1000)
c.execute(
"INSERT OR REPLACE INTO JuxtaStatInfiniteStats VALUES (?, ?, ?, ?, ?, ?, ?)",
(
user,
seed,
version,
correctBytes,
sum(corrects),
len(corrects),
time_unix_millis,
),
)
conn.commit()


def get_per_question_stats_from_table(day, table_name, column):
day = int(day)
_, c = table()
Expand Down Expand Up @@ -245,6 +285,14 @@ def todays_score_for(requestee, requesters, date, quiz_kind):
)


def infinite_results(requestee, requesters, seed, version):
"""
For each `requseter` returns the pattern of correct answers if `(requester, requestee)` is a friend pair.
"""

return _compute_friend_results(requestee, requesters, compute_fn=lambda c, for_user: _infinite_results(c, for_user, seed, version))


def _compute_friend_results(requestee, requesters, compute_fn):
requestee = int(requestee, 16)

Expand Down Expand Up @@ -287,3 +335,32 @@ def _compute_daily_score(date, quiz_kind, c, for_user):
return dict(corrects=None)
else:
return dict(corrects=bitvector_to_corrects(res[0]))

def _infinite_results(c, for_user, seed, version):
"""
Returns the result for the given user for the given seed and version, as well
as the maximum score and corresponding seed and version.
"""

c.execute(
"SELECT score FROM JuxtaStatInfiniteStats WHERE user=? AND seed=? AND version=?",
(for_user, seed, version),
)
res = c.fetchone()
for_this_seed = None if res is None else res[0]

c.execute(
"SELECT seed, version, score FROM JuxtaStatInfiniteStats WHERE user=? AND score=(SELECT MAX(score) FROM JuxtaStatInfiniteStats WHERE user=?)",
(for_user, for_user),
)
res = c.fetchone()
max_score_seed = None if res is None else res[0]
max_score_version = None if res is None else res[1]
max_score = None if res is None else res[2]

return dict(
forThisSeed=for_this_seed,
maxScore=max_score,
maxScoreSeed=max_score_seed,
maxScoreVersion=max_score_version
)
42 changes: 42 additions & 0 deletions urbanstats-persistent-data/urbanstats_persistent_data/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
friend_request,
get_per_question_stats,
get_per_question_stats_retrostat,
has_infinite_stats,
infinite_results,
latest_day,
latest_week_retrostat,
register_user,
store_user_stats,
get_full_database,
store_user_stats_infinite,
store_user_stats_retrostat,
todays_score_for,
unfriend,
Expand Down Expand Up @@ -80,6 +83,7 @@ def get_authenticated_user(additional_required_params=()):
required_params = ["user", "secureID"] + list(additional_required_params)

if not all([param in form for param in required_params]):
print("NEEDS PARAMS", required_params, "GOT", form.keys())
return False, (
flask.jsonify(
{
Expand All @@ -101,10 +105,13 @@ def authenticate(fields):
def decorator(fn):
@functools.wraps(fn)
def wrapper():
print("AUTHENTICATE", flask_form())
success, error = get_authenticated_user(fields)
if not success:
print("AUTHENTICATE ERROR", error)
return error
return fn()

return wrapper

return decorator
Expand Down Expand Up @@ -145,6 +152,28 @@ def juxtastat_store_user_stats_request():
return flask.jsonify(dict())


@app.route("/juxtastat_infinite/has_infinite_stats", methods=["POST"])
@authenticate(["seedVersions"])
def juxtastat_infinite_has_infinite_stats_request():
form = flask_form()
print("HAS INFINITE STATS", form)
res = dict(has=has_infinite_stats(form["user"], form["seedVersions"]))
print("HAS INFINITE STATS", res)
return flask.jsonify(
res
)


@app.route("/juxtastat_infinite/store_user_stats", methods=["POST"])
@authenticate(["seed", "version", "corrects"])
def juxtastat_infinite_store_user_stats_request():
form = flask_form()
store_user_stats_infinite(
form["user"], form["seed"], form["version"], form["corrects"]
)
return flask.jsonify(dict())


@app.route("/retrostat/store_user_stats", methods=["POST"])
@authenticate(["day_stats"])
def retrostat_store_user_stats_request():
Expand Down Expand Up @@ -216,6 +245,19 @@ def juxtastat_todays_score_for():
return flask.jsonify(res)


@app.route("/juxtastat/infinite_results", methods=["POST"])
@authenticate(["requesters", "seed", "version"])
def juxtastat_infinite_results():
form = flask_form()
res = dict(
results=infinite_results(
form["user"], form["requesters"], form["seed"], form["version"]
)
)
print("INFINITE RESULTS FOR", res)
return flask.jsonify(res)


import logging

logging.getLogger("flask_cors").level = logging.DEBUG
Expand Down
12 changes: 12 additions & 0 deletions urbanstats-persistent-data/urbanstats_persistent_data/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from typing import List


def corrects_to_bytes(corrects: List[bool]) -> bytes:
result = []
for i in range(0, len(corrects), 8):
byte = 0
for j in range(8):
if i + j < len(corrects) and corrects[i + j]:
byte |= 1 << j
result.append(byte)
return bytes(result)
Loading