198 lines
6.1 KiB
Python
198 lines
6.1 KiB
Python
|
|
# retoor <retoor@molodetz.nl>
|
||
|
|
|
||
|
|
from datetime import datetime, timedelta, timezone
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from devplacepy.db_client import get_table, init_db
|
||
|
|
from devplacepy.db_client import (
|
||
|
|
can_give_award,
|
||
|
|
can_receive_award,
|
||
|
|
has_giver_cooldown,
|
||
|
|
has_receiver_cooldown,
|
||
|
|
recompute_user_award_stats,
|
||
|
|
revoke_award,
|
||
|
|
)
|
||
|
|
from devplacepy.utils import generate_uid, make_combined_slug
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture(autouse=True)
|
||
|
|
def _db(local_db):
|
||
|
|
init_db()
|
||
|
|
yield
|
||
|
|
|
||
|
|
|
||
|
|
def _user(prefix="award"):
|
||
|
|
uid = generate_uid()
|
||
|
|
get_table("users").insert(
|
||
|
|
{
|
||
|
|
"uid": uid,
|
||
|
|
"username": f"{prefix}_{uid[:8]}",
|
||
|
|
"email": f"{uid[:8]}@t.dev",
|
||
|
|
"created_at": datetime.now(timezone.utc).isoformat(),
|
||
|
|
"award_count": 0,
|
||
|
|
"last_award_at": None,
|
||
|
|
"last_award_slug": None,
|
||
|
|
"last_award_uid": None,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return uid
|
||
|
|
|
||
|
|
|
||
|
|
def _award(giver_uid, receiver_uid, description="Great work", generated_at=None):
|
||
|
|
uid = generate_uid()
|
||
|
|
slug = make_combined_slug(description, uid)
|
||
|
|
now = datetime.now(timezone.utc).isoformat()
|
||
|
|
get_table("awards").insert(
|
||
|
|
{
|
||
|
|
"uid": uid,
|
||
|
|
"slug": slug,
|
||
|
|
"description": description,
|
||
|
|
"giver_uid": giver_uid,
|
||
|
|
"receiver_uid": receiver_uid,
|
||
|
|
"attachment_uid_512": "",
|
||
|
|
"attachment_uid_256": "",
|
||
|
|
"attachment_uid_64": "",
|
||
|
|
"generated_at": generated_at,
|
||
|
|
"created_at": now,
|
||
|
|
"job_uid": "",
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return uid, slug
|
||
|
|
|
||
|
|
|
||
|
|
def _attachment(user_uid):
|
||
|
|
uid = generate_uid()
|
||
|
|
get_table("attachments").insert(
|
||
|
|
{
|
||
|
|
"uid": uid,
|
||
|
|
"target_type": "award",
|
||
|
|
"target_uid": "",
|
||
|
|
"user_uid": user_uid,
|
||
|
|
"original_filename": "award.png",
|
||
|
|
"stored_name": f"{uid}.png",
|
||
|
|
"directory": "aa/bb",
|
||
|
|
"file_size": 10,
|
||
|
|
"mime_type": "image/png",
|
||
|
|
"created_at": datetime.now(timezone.utc).isoformat(),
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return uid
|
||
|
|
|
||
|
|
|
||
|
|
def test_slug_matches_make_combined_slug():
|
||
|
|
uid = generate_uid()
|
||
|
|
slug = make_combined_slug("Ship it", uid)
|
||
|
|
assert slug.endswith("-ship-it") or slug == uid.replace("-", "")[-12:]
|
||
|
|
|
||
|
|
|
||
|
|
def test_can_give_award_respects_giver_cooldown(monkeypatch):
|
||
|
|
giver = _user("giver")
|
||
|
|
receiver = _user("recv")
|
||
|
|
_award(giver, receiver)
|
||
|
|
monkeypatch.setattr(
|
||
|
|
"devplacepy.database.awards.get_int_setting",
|
||
|
|
lambda key, default: 24 if "cooldown" in key else default,
|
||
|
|
)
|
||
|
|
assert has_giver_cooldown(giver) is True
|
||
|
|
assert can_give_award(giver, receiver) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_can_receive_award_respects_receiver_cooldown(monkeypatch):
|
||
|
|
giver = _user("giver2")
|
||
|
|
receiver = _user("recv2")
|
||
|
|
_award(giver, receiver)
|
||
|
|
monkeypatch.setattr(
|
||
|
|
"devplacepy.database.awards.get_int_setting",
|
||
|
|
lambda key, default: 24 if "receive" in key else default,
|
||
|
|
)
|
||
|
|
assert has_receiver_cooldown(receiver) is True
|
||
|
|
assert can_receive_award(receiver) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_cooldown_ignores_soft_deleted_rows():
|
||
|
|
giver = _user("giver3")
|
||
|
|
receiver = _user("recv3")
|
||
|
|
uid, _ = _award(giver, receiver)
|
||
|
|
get_table("awards").update(
|
||
|
|
{"uid": uid, "deleted_at": datetime.now(timezone.utc).isoformat(), "deleted_by": giver},
|
||
|
|
["uid"],
|
||
|
|
)
|
||
|
|
assert has_giver_cooldown(giver) is False
|
||
|
|
assert has_receiver_cooldown(receiver) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_recompute_user_award_stats_sets_latest_generated():
|
||
|
|
receiver = _user("recv4")
|
||
|
|
giver = _user("giver4")
|
||
|
|
older = datetime.now(timezone.utc) - timedelta(hours=2)
|
||
|
|
newer = datetime.now(timezone.utc) - timedelta(hours=1)
|
||
|
|
uid_old, slug_old = _award(giver, receiver, "older", older.isoformat())
|
||
|
|
uid_new, slug_new = _award(giver, receiver, "newer", newer.isoformat())
|
||
|
|
recompute_user_award_stats(receiver)
|
||
|
|
row = get_table("users").find_one(uid=receiver)
|
||
|
|
assert row["award_count"] == 2
|
||
|
|
assert row["last_award_uid"] == uid_new
|
||
|
|
assert row["last_award_slug"] == slug_new
|
||
|
|
assert uid_old != uid_new
|
||
|
|
assert slug_old != slug_new
|
||
|
|
|
||
|
|
|
||
|
|
def test_revoke_latest_recomputes_to_previous():
|
||
|
|
receiver = _user("recv5")
|
||
|
|
giver = _user("giver5")
|
||
|
|
older = datetime.now(timezone.utc) - timedelta(hours=2)
|
||
|
|
newer = datetime.now(timezone.utc) - timedelta(hours=1)
|
||
|
|
uid_old, slug_old = _award(giver, receiver, "keep", older.isoformat())
|
||
|
|
uid_new, _ = _award(giver, receiver, "gone", newer.isoformat())
|
||
|
|
recompute_user_award_stats(receiver)
|
||
|
|
revoke_award(uid_new, giver)
|
||
|
|
row = get_table("users").find_one(uid=receiver)
|
||
|
|
assert row["award_count"] == 1
|
||
|
|
assert row["last_award_uid"] == uid_old
|
||
|
|
assert row["last_award_slug"] == slug_old
|
||
|
|
|
||
|
|
|
||
|
|
def test_revoke_clears_stats_when_count_zero():
|
||
|
|
receiver = _user("recv6")
|
||
|
|
giver = _user("giver6")
|
||
|
|
now = datetime.now(timezone.utc).isoformat()
|
||
|
|
uid, _ = _award(giver, receiver, "only", now)
|
||
|
|
recompute_user_award_stats(receiver)
|
||
|
|
revoke_award(uid, giver)
|
||
|
|
row = get_table("users").find_one(uid=receiver)
|
||
|
|
assert row["award_count"] == 0
|
||
|
|
assert not row.get("last_award_uid")
|
||
|
|
|
||
|
|
|
||
|
|
def test_revoke_soft_deletes_attachments_under_one_stamp():
|
||
|
|
receiver = _user("recv7")
|
||
|
|
giver = _user("giver7")
|
||
|
|
admin = _user("admin7")
|
||
|
|
now = datetime.now(timezone.utc).isoformat()
|
||
|
|
uid, _ = _award(giver, receiver, "with files", now)
|
||
|
|
a512 = _attachment(receiver)
|
||
|
|
a256 = _attachment(giver)
|
||
|
|
a64 = _attachment(giver)
|
||
|
|
get_table("awards").update(
|
||
|
|
{
|
||
|
|
"uid": uid,
|
||
|
|
"attachment_uid_512": a512,
|
||
|
|
"attachment_uid_256": a256,
|
||
|
|
"attachment_uid_64": a64,
|
||
|
|
},
|
||
|
|
["uid"],
|
||
|
|
)
|
||
|
|
revoke_award(uid, admin)
|
||
|
|
award = get_table("awards").find_one(uid=uid)
|
||
|
|
assert award.get("deleted_at")
|
||
|
|
stamps = {
|
||
|
|
get_table("attachments").find_one(uid=a512).get("deleted_at"),
|
||
|
|
get_table("attachments").find_one(uid=a256).get("deleted_at"),
|
||
|
|
get_table("attachments").find_one(uid=a64).get("deleted_at"),
|
||
|
|
}
|
||
|
|
assert len(stamps) == 1
|
||
|
|
assert award.get("deleted_at") in stamps
|