major file restrucutre

This commit is contained in:
SowinskiBraeden committed 2026-06-24 19:53:19 -07:00
1 parent ac278065d2
commit 6da4c3e379
53 files changed
+188 -180

No files matched your search

+2 -60
View File
@@ -1,66 +1,8 @@
#!/usr/bin/env python3
from __future__ import annotations
import os
import click
from flask import Flask
from auth import current_user_id, is_logged_in
from config import Config, ProductionConfig
from db import database_extensions_available, db, init_database
from extensions import csrf, limiter, mail
from routes.account import account_bp
from routes.leagues import leagues_bp
from routes.public import public_bp
from storage import ensure_data_file
from utils import cents_to_dollars, safe_date_label
def create_app(config_overrides: dict | None = None) -> Flask:
app = Flask(__name__)
cfg = ProductionConfig if os.getenv("FLASK_ENV") == "production" else Config
app.config.from_object(cfg)
if config_overrides:
app.config.update(config_overrides)
ensure_data_file(app.config["DATA_PATH"])
init_database(app)
csrf.init_app(app)
limiter.init_app(app)
mail.init_app(app)
app.jinja_env.filters["money"] = cents_to_dollars
app.jinja_env.filters["pretty_date"] = safe_date_label
@app.context_processor
def inject_globals() -> dict:
return {
"app_version": app.config["APP_VERSION"],
"current_user_id": current_user_id(),
"is_logged_in": is_logged_in(),
}
app.register_blueprint(public_bp)
app.register_blueprint(account_bp)
app.register_blueprint(leagues_bp)
@app.cli.command("init-db")
def init_db_command() -> None:
if not database_extensions_available() or db is None:
raise click.ClickException(
"Database dependencies are not installed. Run pip install -r requirements.txt."
)
with app.app_context():
db.create_all()
click.echo("Initialized database tables.")
return app
from boker import create_app
app = create_app()
if __name__ == "__main__":
import os
app.run(debug=os.getenv("FLASK_DEBUG", "0") == "1")
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
from __future__ import annotations
import os
import click
from flask import Flask
from .auth import current_user_id, is_logged_in
from .config import Config, ProductionConfig
from .db import database_extensions_available, db, init_database
from .extensions import csrf, limiter, mail
from .routes.account import account_bp
from .routes.leagues import leagues_bp
from .routes.public import public_bp
from .storage import ensure_data_file
from .utils import cents_to_dollars, safe_date_label
def create_app(config_overrides: dict | None = None) -> Flask:
app = Flask(__name__)
cfg = ProductionConfig if os.getenv("FLASK_ENV") == "production" else Config
app.config.from_object(cfg)
if config_overrides:
app.config.update(config_overrides)
ensure_data_file(app.config["DATA_PATH"])
init_database(app)
csrf.init_app(app)
limiter.init_app(app)
mail.init_app(app)
app.jinja_env.filters["money"] = cents_to_dollars
app.jinja_env.filters["pretty_date"] = safe_date_label
@app.context_processor
def inject_globals() -> dict:
return {
"app_version": app.config["APP_VERSION"],
"current_user_id": current_user_id(),
"is_logged_in": is_logged_in(),
}
app.register_blueprint(public_bp)
app.register_blueprint(account_bp)
app.register_blueprint(leagues_bp)
@app.cli.command("init-db")
def init_db_command() -> None:
if not database_extensions_available() or db is None:
raise click.ClickException(
"Database dependencies are not installed. Run pip install -r requirements.txt."
)
with app.app_context():
db.create_all()
click.echo("Initialized database tables.")
return app
View File
File renamed without changes.
+2 -2
View File
@@ -4,8 +4,8 @@ from __future__ import annotations
from typing import Any
from models import SessionEntry, SessionSummary
from utils import net_result_bucket, session_chart_label, session_sort_key
from .models import SessionEntry, SessionSummary
from .utils import net_result_bucket, session_chart_label, session_sort_key
PLAYER_PALETTE = [
"#9b8cf0", # --line-1 violet
+2 -2
View File
@@ -4,12 +4,12 @@ from __future__ import annotations
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
BASE_DIR = Path(__file__).resolve().parent.parent
DATA_PATH = BASE_DIR / "data" / "entries.csv"
DEFAULT_DATABASE_URL = f"sqlite:///{BASE_DIR / 'data' / 'boker-dev.sqlite3'}"
ELIGIBLE_MIN_SESSIONS = 3
APP_VERSION = "2.3.0"
APP_VERSION = "2.3.1"
def load_local_env(env_path: Path) -> None:
+1 -1
View File
@@ -24,7 +24,7 @@ def init_database(app: Any) -> bool:
app.config["DATABASE_EXTENSIONS_AVAILABLE"] = False
return False
import db_models # noqa: F401 - registers SQLAlchemy models with metadata.
from . import db_models # noqa: F401 - registers SQLAlchemy models with metadata.
db.init_app(app)
migrate.init_app(app, db)
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import uuid
from datetime import date, datetime, timezone
from db import db
from .db import db
if db is None: # pragma: no cover - imported only when DB dependencies exist.
raise RuntimeError("Database dependencies are not installed.")
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
from flask import current_app
from flask_mail import Message
from extensions import mail
from .extensions import mail
def send_password_reset(to_email: str, reset_url: str) -> None:
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
@@ -5,13 +5,13 @@ import secrets
import string
from datetime import date
from auth import hash_password, normalize_email
from db import db
from ..auth import hash_password, normalize_email
from ..db import db
if db is None: # pragma: no cover - imported only when DB dependencies exist.
raise RuntimeError("Database dependencies are not installed.")
from db_models import ( # noqa: E402
from ..db_models import ( # noqa: E402
LedgerEvent,
League,
LeagueMembership,
@@ -24,7 +24,7 @@ from db_models import ( # noqa: E402
make_user,
normalize_lookup,
)
from utils import slugify
from ..utils import slugify
PUBLIC_KEY_ALPHABET = string.ascii_lowercase + string.digits
@@ -223,7 +223,7 @@ def set_session_status(session: PokerSession, status: str) -> PokerSession:
if status not in {"open", "closed"}:
raise ValueError(f"Unsupported session status: {status}")
from db_models import utc_now
from ..db_models import utc_now
session.status = status
if status == "open":
@@ -313,7 +313,7 @@ def add_league_member(
def remove_league_member(league_id: str, user_id: str) -> None:
from db_models import utc_now
from ..db_models import utc_now
membership = LeagueMembership.query.filter_by(
league_id=league_id,
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
from __future__ import annotations
from db import db
from ..db import db
if db is None: # pragma: no cover - imported only when DB dependencies exist.
raise RuntimeError("Database dependencies are not installed.")
from db_models import ( # noqa: E402
from ..db_models import ( # noqa: E402
CANONICAL_EVENT_TYPES,
LedgerEvent,
Player,
@@ -14,7 +14,7 @@ from db_models import ( # noqa: E402
User,
canonical_event_type,
)
from storage import EventRow # noqa: E402
from ..storage import EventRow # noqa: E402
def session_event_ref(session: PokerSession) -> str:
+1
View File
@@ -0,0 +1 @@
+16 -15
View File
@@ -5,7 +5,7 @@ from urllib.parse import urlparse
from flask import Blueprint, flash, redirect, render_template, request, url_for
from auth import (
from ..auth import (
current_user_id,
generate_invite_token,
generate_reset_token,
@@ -18,8 +18,8 @@ from auth import (
verify_password,
verify_reset_token,
)
from db import database_extensions_available, db
from extensions import limiter
from ..db import database_extensions_available, db
from ..extensions import limiter
account_bp = Blueprint("account", __name__, url_prefix="/account")
@@ -49,7 +49,7 @@ def register():
}
if request.method == "POST":
from league_repositories import create_user, find_user_by_email
from ..repositories.leagues import create_user, find_user_by_email
email = normalize_email(form["email"])
password = request.form.get("password", "")
@@ -88,7 +88,7 @@ def login():
}
if request.method == "POST":
from league_repositories import find_user_by_email
from ..repositories.leagues import find_user_by_email
user = find_user_by_email(form["email"])
password = request.form.get("password", "")
@@ -122,7 +122,7 @@ def settings():
flash("Account database is not available.", "error")
return redirect(url_for("leagues.index"))
from db_models import User
from ..db_models import User
user = db.session.get(User, current_user_id())
if user is None:
@@ -139,7 +139,7 @@ def update_email():
flash("Account database is not available.", "error")
return redirect(url_for("account.settings"))
from db_models import User
from ..db_models import User
user = db.session.get(User, current_user_id())
if user is None:
@@ -154,7 +154,7 @@ def update_email():
elif not verify_password(user.password_hash, current_password):
flash("Current password is incorrect.", "error")
else:
from league_repositories import find_user_by_email
from ..repositories.leagues import find_user_by_email
existing = find_user_by_email(new_email)
if existing and existing.id != user.id:
@@ -174,7 +174,7 @@ def update_password():
flash("Account database is not available.", "error")
return redirect(url_for("account.settings"))
from db_models import User
from ..db_models import User
user = db.session.get(User, current_user_id())
if user is None:
@@ -206,7 +206,7 @@ def delete_account():
flash("Account database is not available.", "error")
return redirect(url_for("account.settings"))
from db_models import League, User, utc_now
from ..db_models import League, User, utc_now
user = db.session.get(User, current_user_id())
if user is None:
@@ -246,9 +246,10 @@ def forgot_password():
flash("Account database is not available.", "error")
return redirect(url_for("account.forgot_password"))
from emails import send_password_reset
from flask import current_app
from league_repositories import find_user_by_email
from ..emails import send_password_reset
from ..repositories.leagues import find_user_by_email
email = normalize_email(request.form.get("email", ""))
user = find_user_by_email(email)
@@ -282,7 +283,7 @@ def reset_password(token):
flash("Account database is not available.", "error")
return redirect(url_for("account.login"))
from db_models import User
from ..db_models import User
user = db.session.get(User, user_id)
if user is None or user.disabled_at is not None:
@@ -320,8 +321,8 @@ def accept_invite(token):
flash("Account database is not available.", "error")
return redirect(url_for("leagues.index"))
from db_models import User
from league_repositories import add_league_member, find_league_by_id, find_membership
from ..db_models import User
from ..repositories.leagues import add_league_member, find_league_by_id, find_membership
user = db.session.get(User, current_user_id())
if user is None or user.email != data.get("email"):
+4 -4
View File
@@ -16,16 +16,16 @@ from flask import (
url_for,
)
from auth import is_admin
from services import (
from ..auth import is_admin
from ..services import (
build_session_summaries,
next_session_id,
pending_payout_carry_items,
prunable_empty_session_ids,
unique_player_names,
)
from storage import CSV_HEADERS, append_event, load_events, write_events
from utils import cents_to_dollars, session_label
from ..storage import CSV_HEADERS, append_event, load_events, write_events
from ..utils import cents_to_dollars, session_label
admin_bp = Blueprint("admin", __name__)
+59 -58
View File
@@ -9,12 +9,12 @@ from datetime import datetime, timezone
from flask import Blueprint, abort, flash, make_response, redirect, render_template, request, url_for
from auth import current_user_id, login_required, normalize_email
from charts import cumulative_profit_series, player_session_series
from db import database_extensions_available, db
from models import SessionSummary
from services import apply_rank_changes, build_leaderboard, build_session_summaries, session_events
from utils import cents_to_dollars, session_label, session_sort_key
from ..auth import current_user_id, login_required, normalize_email
from ..charts import cumulative_profit_series, player_session_series
from ..db import database_extensions_available, db
from ..models import SessionSummary
from ..services import apply_rank_changes, build_leaderboard, build_session_summaries, session_events
from ..utils import cents_to_dollars, session_label, session_sort_key
leagues_bp = Blueprint("leagues", __name__)
@@ -48,7 +48,7 @@ def split_league_ref(league_ref: str) -> tuple[str, str]:
def require_league(league_ref: str, allowed_roles: set[str]):
from league_repositories import find_league_by_public_key, user_has_league_role
from ..repositories.leagues import find_league_by_public_key, user_has_league_role
_slug, public_key = split_league_ref(league_ref)
league = find_league_by_public_key(public_key)
@@ -64,7 +64,7 @@ def require_league(league_ref: str, allowed_roles: set[str]):
def get_league_with_visibility_gate(league_ref: str):
"""Load league; if private, enforce login + membership. Returns (league, None) or (None, redirect)."""
from league_repositories import find_league_by_public_key, user_has_league_role
from ..repositories.leagues import find_league_by_public_key, user_has_league_role
_slug, public_key = split_league_ref(league_ref)
league = find_league_by_public_key(public_key)
@@ -99,8 +99,8 @@ def empty_session_summary(session) -> SessionSummary:
def session_ref_map(league_id: str) -> dict[str, str]:
from ledger_repositories import session_event_ref
from league_repositories import list_sessions_for_league
from ..repositories.ledger import session_event_ref
from ..repositories.leagues import list_sessions_for_league
return {session_event_ref(session): session.id for session in list_sessions_for_league(league_id)}
@@ -112,8 +112,8 @@ def index():
flash("League database is not available.", "error")
return render_template("leagues_index.html", leagues=[])
from league_repositories import list_leagues_for_user
from ledger_repositories import list_event_rows_for_league
from ..repositories.leagues import list_leagues_for_user
from ..repositories.ledger import list_event_rows_for_league
memberships = list_leagues_for_user(current_user_id() or "")
league_summaries = []
@@ -190,8 +190,8 @@ def new():
}
if request.method == "POST":
from db_models import User
from league_repositories import create_league, unique_league_slug
from ..db_models import User
from ..repositories.leagues import create_league, unique_league_slug
owner = db.session.get(User, current_user_id())
if owner is None:
@@ -221,7 +221,7 @@ def dashboard(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import league_counts, user_has_league_role
from ..repositories.leagues import league_counts, user_has_league_role
league, resp = get_league_with_visibility_gate(league_ref)
if resp:
@@ -242,7 +242,7 @@ def legacy_dashboard_redirect(league_id: str, league_slug: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import find_league_by_id, user_has_league_role
from ..repositories.leagues import find_league_by_id, user_has_league_role
league = find_league_by_id(league_id)
if league is None:
@@ -259,9 +259,9 @@ def leaderboard(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from config import ELIGIBLE_MIN_SESSIONS
from ledger_repositories import list_event_rows_for_league
from league_repositories import list_players_for_league, user_has_league_role
from ..config import ELIGIBLE_MIN_SESSIONS
from ..repositories.ledger import list_event_rows_for_league
from ..repositories.leagues import list_players_for_league, user_has_league_role
league, resp = get_league_with_visibility_gate(league_ref)
if resp:
@@ -366,12 +366,12 @@ def ledger(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import (
from ..repositories.ledger import (
append_ledger_event,
list_all_event_rows_for_league,
list_event_rows_for_league,
)
from league_repositories import (
from ..repositories.leagues import (
find_player_for_league,
find_session_for_league,
list_players_for_league,
@@ -506,7 +506,7 @@ def void_event(league_ref: str, event_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import void_ledger_event
from ..repositories.ledger import void_ledger_event
league = require_league(league_ref, {"owner"})
reason = request.form.get("void_reason", "").strip()
@@ -529,8 +529,8 @@ def player_detail(league_ref: str, player_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import list_event_rows_for_league
from league_repositories import find_player_for_league, user_has_league_role
from ..repositories.ledger import list_event_rows_for_league
from ..repositories.leagues import find_player_for_league, user_has_league_role
league, resp = get_league_with_visibility_gate(league_ref)
if resp:
@@ -588,7 +588,7 @@ def players(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import (
from ..repositories.leagues import (
create_player,
list_players_for_league,
player_name_exists,
@@ -627,7 +627,7 @@ def players(league_ref: str):
flash("Player added.", "success")
return redirect(url_for("leagues.players", **league_url_values(league)))
from ledger_repositories import list_event_rows_for_league
from ..repositories.ledger import list_event_rows_for_league
all_sessions = build_session_summaries(list_event_rows_for_league(league.id))
board = build_leaderboard(all_sessions)
@@ -661,7 +661,7 @@ def update_player_status(league_ref: str, player_id: str, status: str, message:
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import find_player_for_league, set_player_status
from ..repositories.leagues import find_player_for_league, set_player_status
league = require_league(league_ref, {"owner", "manager"})
player = find_player_for_league(league.id, player_id)
@@ -681,7 +681,7 @@ def edit_player(league_ref: str, player_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import find_player_for_league, player_name_taken, update_player
from ..repositories.leagues import find_player_for_league, player_name_taken, update_player
league = require_league(league_ref, {"owner", "manager"})
player = find_player_for_league(league.id, player_id)
@@ -709,8 +709,8 @@ def sessions(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import append_ledger_event
from league_repositories import (
from ..repositories.ledger import append_ledger_event
from ..repositories.leagues import (
create_poker_session,
list_sessions_for_league,
user_has_league_role,
@@ -747,7 +747,7 @@ def sessions(league_ref: str):
session.label = form["label"] or None
session.notes = form["notes"] or None
if status == "open":
from league_repositories import set_session_status
from ..repositories.leagues import set_session_status
set_session_status(session, "open")
@@ -765,8 +765,8 @@ def sessions(league_ref: str):
flash(f"Created {session.display_label}.", "success")
return redirect(url_for("leagues.sessions", **league_url_values(league)))
from db_models import LedgerEvent
from ledger_repositories import list_event_rows_for_league
from ..db_models import LedgerEvent
from ..repositories.ledger import list_event_rows_for_league
all_sessions = list_sessions_for_league(league.id)
summaries = build_session_summaries(list_event_rows_for_league(league.id))
@@ -803,8 +803,8 @@ def prune_empty_sessions(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from db_models import LedgerEvent, PokerSession
from league_repositories import list_sessions_for_league
from ..db_models import LedgerEvent, PokerSession
from ..repositories.leagues import list_sessions_for_league
league = require_league(league_ref, {"owner", "manager"})
@@ -839,7 +839,7 @@ def delete_session(league_ref: str, session_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import find_session_for_league
from ..repositories.leagues import find_session_for_league
league = require_league(league_ref, {"owner"})
session = find_session_for_league(league.id, session_id)
@@ -859,7 +859,7 @@ def edit_session(league_ref: str, session_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import find_session_for_league
from ..repositories.leagues import find_session_for_league
league = require_league(league_ref, {"owner", "manager"})
session = find_session_for_league(league.id, session_id)
@@ -877,7 +877,7 @@ def edit_session(league_ref: str, session_id: str):
return redirect(url_for("leagues.session_detail", league_ref=league.url_ref, session_id=session_id))
if new_date != session.session_date:
from db_models import PokerSession as _PS
from ..db_models import PokerSession as _PS
max_seq = db.session.query(db.func.max(_PS.sequence_on_date)).filter(
_PS.league_id == league.id,
_PS.session_date == new_date,
@@ -900,8 +900,8 @@ def session_detail(league_ref: str, session_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import append_ledger_event, list_all_event_rows_for_session, list_event_rows_for_session
from league_repositories import (
from ..repositories.ledger import append_ledger_event, list_all_event_rows_for_session, list_event_rows_for_session
from ..repositories.leagues import (
find_session_for_league,
list_players_for_league,
user_has_league_role,
@@ -989,9 +989,9 @@ def session_public_view(league_ref: str, session_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from charts import session_breakdown_series
from ledger_repositories import list_event_rows_for_league, list_event_rows_for_session
from league_repositories import find_league_by_public_key, find_session_for_league, list_sessions_for_league, user_has_league_role
from ..charts import session_breakdown_series
from ..repositories.ledger import list_event_rows_for_league, list_event_rows_for_session
from ..repositories.leagues import find_league_by_public_key, find_session_for_league, list_sessions_for_league, user_has_league_role
_slug, public_key = split_league_ref(league_ref)
league = find_league_by_public_key(public_key)
@@ -1062,8 +1062,8 @@ def update_session_status(league_ref: str, session_id: str, status: str, message
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import append_ledger_event
from league_repositories import find_session_for_league, set_session_status
from ..repositories.ledger import append_ledger_event
from ..repositories.leagues import find_session_for_league, set_session_status
league = require_league(league_ref, {"owner", "manager"})
session = find_session_for_league(league.id, session_id)
@@ -1114,7 +1114,7 @@ def league_settings(league_ref: str):
elif form["visibility"] not in ("private", "public"):
flash("Invalid visibility value.", "error")
else:
from utils import slugify
from ..utils import slugify
league.name = form["name"]
league.slug = slugify(form["name"])
@@ -1124,7 +1124,7 @@ def league_settings(league_ref: str):
flash("League settings saved.", "success")
return redirect(url_for("leagues.league_settings", league_ref=league.url_ref))
from league_repositories import list_members_for_league
from ..repositories.leagues import list_members_for_league
members = list_members_for_league(league.id)
return render_template("league_settings.html", league=league, form=form, is_owner=True, members=members)
@@ -1137,10 +1137,11 @@ def invite_member(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from auth import generate_invite_token
from emails import send_league_invite
from flask import current_app
from league_repositories import find_membership, find_user_by_email
from ..auth import generate_invite_token
from ..emails import send_league_invite
from ..repositories.leagues import find_membership, find_user_by_email
league = require_league(league_ref, {"owner"})
email = normalize_email(request.form.get("email", ""))
@@ -1181,7 +1182,7 @@ def remove_member(league_ref: str, user_id: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from league_repositories import remove_league_member
from ..repositories.leagues import remove_league_member
league = require_league(league_ref, {"owner"})
@@ -1202,7 +1203,7 @@ def archive_league(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from db_models import utc_now
from ..db_models import utc_now
league = require_league(league_ref, {"owner"})
confirm_name = request.form.get("confirm_name", "").strip()
@@ -1224,8 +1225,8 @@ def export_ledger_csv(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from ledger_repositories import list_event_rows_for_league
from storage import CSV_HEADERS
from ..repositories.ledger import list_event_rows_for_league
from ..storage import CSV_HEADERS
league = require_league(league_ref, {"owner", "manager", "viewer"})
rows = list_event_rows_for_league(league.id)
@@ -1250,14 +1251,14 @@ def import_ledger_csv(league_ref: str):
flash("League database is not available.", "error")
return redirect(url_for("public.home"))
from db_models import CANONICAL_EVENT_TYPES, canonical_event_type
from ledger_repositories import (
from ..db_models import CANONICAL_EVENT_TYPES, canonical_event_type
from ..repositories.ledger import (
append_ledger_event,
list_ledger_events_for_league,
session_event_ref,
)
from league_repositories import list_players_for_league, list_sessions_for_league
from storage import CSV_HEADERS
from ..repositories.leagues import list_players_for_league, list_sessions_for_league
from ..storage import CSV_HEADERS
league = require_league(league_ref, {"owner", "manager"})
+8 -8
View File
@@ -4,16 +4,16 @@ from __future__ import annotations
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask import current_app
from charts import cumulative_profit_series, player_session_series, session_breakdown_series
from config import ELIGIBLE_MIN_SESSIONS
from services import (
from ..charts import cumulative_profit_series, player_session_series, session_breakdown_series
from ..config import ELIGIBLE_MIN_SESSIONS
from ..services import (
apply_rank_changes,
build_leaderboard,
build_session_summaries,
session_events,
)
from storage import load_events
from utils import session_label, session_sort_key
from ..storage import load_events
from ..utils import session_label, session_sort_key
public_bp = Blueprint("public", __name__)
@@ -30,9 +30,9 @@ def help():
@public_bp.get("/explore")
def explore():
from auth import is_logged_in
from db import database_extensions_available
from league_repositories import league_counts, list_public_leagues
from ..auth import is_logged_in
from ..db import database_extensions_available
from ..repositories.leagues import league_counts, list_public_leagues
q = request.args.get("q", "").strip()
leagues = list_public_leagues(q) if database_extensions_available() else []
+3 -3
View File
@@ -4,9 +4,9 @@ from __future__ import annotations
from collections import defaultdict
from models import PlayerStats, SessionEntry, SessionSummary
from storage import EventRow
from utils import entry_sort_key, net_result_bucket, session_sort_key
from .models import PlayerStats, SessionEntry, SessionSummary
from .storage import EventRow
from .utils import entry_sort_key, net_result_bucket, session_sort_key
SESSION_MARKER_TYPES = {"session_open", "session_close"}
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -7,7 +7,7 @@ import re
from markupsafe import Markup
from models import SessionEntry, SessionSummary
from .models import SessionEntry, SessionSummary
BREAK_EVEN_TOLERANCE_CENTS = 100
+15 -13
View File
@@ -2,15 +2,17 @@ from pathlib import Path
import tempfile
import unittest
import app as app_module
from charts import player_session_series
from services import (
from boker import create_app
from boker.charts import player_session_series
from boker.services import (
build_leaderboard,
build_session_summaries,
pending_payout_carry_items,
)
from storage import load_events, write_events
from utils import session_sort_key
from boker.storage import load_events, write_events
from boker.utils import session_sort_key
_app = create_app()
def cents(amount: float) -> int:
@@ -203,8 +205,8 @@ class AccountingTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmpdir:
data_path = Path(tmpdir) / "entries.csv"
write_events(data_path, rows)
original_path = app_module.app.config["DATA_PATH"]
app_module.app.config["DATA_PATH"] = data_path
original_path = _app.config["DATA_PATH"]
_app.config["DATA_PATH"] = data_path
try:
sessions = build_session_summaries(load_events(data_path))
@@ -213,7 +215,7 @@ class AccountingTests(unittest.TestCase):
[{"player_name": "A", "amount_cents": cents(5)}],
)
with app_module.app.test_client() as client:
with _app.test_client() as client:
with client.session_transaction() as flask_session:
flask_session["is_admin"] = True
@@ -222,7 +224,7 @@ class AccountingTests(unittest.TestCase):
data={"session_id": "s2", "player_name": "A"},
)
finally:
app_module.app.config["DATA_PATH"] = original_path
_app.config["DATA_PATH"] = original_path
self.assertEqual(response.status_code, 302)
updated_sessions = build_session_summaries(load_events(data_path))
@@ -261,17 +263,17 @@ class AccountingTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmpdir:
data_path = Path(tmpdir) / "entries.csv"
write_events(data_path, rows)
original_path = app_module.app.config["DATA_PATH"]
app_module.app.config["DATA_PATH"] = data_path
original_path = _app.config["DATA_PATH"]
_app.config["DATA_PATH"] = data_path
try:
with app_module.app.test_client() as client:
with _app.test_client() as client:
with client.session_transaction() as flask_session:
flask_session["is_admin"] = True
response = client.post("/admin/prune-empty-sessions")
finally:
app_module.app.config["DATA_PATH"] = original_path
_app.config["DATA_PATH"] = original_path
self.assertEqual(response.status_code, 302)
remaining = load_events(data_path)
+3 -2
View File
@@ -1,6 +1,7 @@
import unittest
from stats import SessionEntry, SessionSummary, build_leaderboard
from boker.models import SessionEntry, SessionSummary
from boker.services import build_leaderboard
class CashInAccountingTest(unittest.TestCase):
@@ -78,7 +79,7 @@ class CashInAccountingTest(unittest.TestCase):
self.assertEqual(player.total_buy_in_cents, 2500)
self.assertEqual(player.total_front_collected_cents, 0)
self.assertEqual(player.total_cash_in_cents, 3000)
self.assertEqual(player.total_real_cash_in_cents, 2500)
if __name__ == "__main__":