chore(lint): trier les imports, sauf la facade des modeles

Active la regle isort (I) de ruff. 45 fichiers reordonnes, aucun
changement de comportement : la suite passe avant comme apres.

app/models/__init__.py en est exclu. Ses imports sont ranges en onze
couches commentees qui decrivent le graphe de dependances ; trier par
ordre alphabetique laisse chaque titre au-dessus d un import qu il ne
decrit pas, et ce fichier n a qu un role, etre lu.

Commit isole, comme le formatage : un diff de brassage ne doit pas
servir de couverture a un changement de comportement.
This commit is contained in:
GGThed
2026-08-11 11:40:41 -04:00
parent ab0b975211
commit 47ff544848
45 changed files with 213 additions and 170 deletions
+9 -8
View File
@@ -7,14 +7,15 @@ the Flask application instance with comprehensive security hardening.
import os import os
import secrets import secrets
from flask import Flask, g, request, redirect, jsonify, render_template, url_for
from flask_cors import CORS
from app.extensions import db, login_manager, csrf, limiter, babel
from sqlalchemy import text
from werkzeug.exceptions import HTTPException
import markupsafe import markupsafe
from dotenv import load_dotenv from dotenv import load_dotenv
from flask import Flask, g, jsonify, redirect, render_template, request, url_for
from flask_cors import CORS
from sqlalchemy import text
from werkzeug.exceptions import HTTPException
from app import i18n from app import i18n
from app.extensions import babel, csrf, db, limiter, login_manager
load_dotenv() load_dotenv()
@@ -265,13 +266,13 @@ def create_app(config=None):
configure_logging(app) configure_logging(app)
from app.routes.auth import auth_bp from app.routes.auth import auth_bp
from app.routes.tryouts import tryouts_bp
from app.routes.evaluations import evaluations_bp from app.routes.evaluations import evaluations_bp
from app.routes.users import users_bp
from app.routes.main import main_bp from app.routes.main import main_bp
from app.routes.teams import teams_bp
from app.routes.matches import matches_bp from app.routes.matches import matches_bp
from app.routes.team_matches import team_matches_bp from app.routes.team_matches import team_matches_bp
from app.routes.teams import teams_bp
from app.routes.tryouts import tryouts_bp
from app.routes.users import users_bp
app.register_blueprint(auth_bp) app.register_blueprint(auth_bp)
app.register_blueprint(tryouts_bp) app.register_blueprint(tryouts_bp)
+13 -11
View File
@@ -6,21 +6,22 @@ This module provides a persistent bot that handles:
- Daily reminders at 18:00 EDT for upcoming events - Daily reminders at 18:00 EDT for upcoming events
""" """
import os import asyncio
import json import json
import logging import logging
import os
import tempfile import tempfile
import time
import asyncio
import threading import threading
import time
import traceback import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta
from queue import Empty, Queue
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from queue import Queue, Empty
from discord import Intents
from discord.ext import commands
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
from discord import Intents
from discord.ext import commands
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv() load_dotenv()
@@ -453,8 +454,8 @@ class TeamTryoutsBot(commands.Bot):
async def handle_one_on_one_approve(self, coach, message_id, request_id, channel): async def handle_one_on_one_approve(self, coach, message_id, request_id, channel):
"""Handle coach approving a One on One request.""" """Handle coach approving a One on One request."""
try: try:
from app.models import OneOnOneRequest
from app.extensions import db from app.extensions import db
from app.models import OneOnOneRequest
request = OneOnOneRequest.query.get(request_id) request = OneOnOneRequest.query.get(request_id)
if not request: if not request:
@@ -498,8 +499,8 @@ class TeamTryoutsBot(commands.Bot):
async def handle_one_on_one_reject(self, coach, message_id, request_id, channel): async def handle_one_on_one_reject(self, coach, message_id, request_id, channel):
"""Handle coach rejecting a One on One request.""" """Handle coach rejecting a One on One request."""
try: try:
from app.models import OneOnOneRequest
from app.extensions import db from app.extensions import db
from app.models import OneOnOneRequest
request = OneOnOneRequest.query.get(request_id) request = OneOnOneRequest.query.get(request_id)
if not request: if not request:
@@ -743,14 +744,15 @@ class TeamTryoutsBot(commands.Bot):
async def _send_daily_reminders_impl(self): async def _send_daily_reminders_impl(self):
"""Internal implementation of daily reminders with proper app context.""" """Internal implementation of daily reminders with proper app context."""
try: try:
from sqlalchemy.orm import joinedload
from app.models import ( from app.models import (
Match, Match,
Tryout,
MatchParticipant, MatchParticipant,
TryoutRegistration,
OneOnOneRequest, OneOnOneRequest,
Tryout,
TryoutRegistration,
) )
from sqlalchemy.orm import joinedload
now = datetime.now(self.timezone) now = datetime.now(self.timezone)
tomorrow = now.date() + timedelta(days=1) tomorrow = now.date() + timedelta(days=1)
+5 -5
View File
@@ -1,10 +1,10 @@
from flask_sqlalchemy import SQLAlchemy from flask_babel import Babel
from flask_login import LoginManager
from flask_wtf.csrf import CSRFProtect
from werkzeug.security import generate_password_hash, check_password_hash
from flask_limiter import Limiter from flask_limiter import Limiter
from flask_limiter.util import get_remote_address from flask_limiter.util import get_remote_address
from flask_babel import Babel from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
from werkzeug.security import check_password_hash, generate_password_hash
# Database and extension initialization # Database and extension initialization
db = SQLAlchemy() db = SQLAlchemy()
+1 -1
View File
@@ -11,8 +11,8 @@ Usage:
import logging import logging
import os import os
from logging.handlers import RotatingFileHandler
import re import re
from logging.handlers import RotatingFileHandler
class SensitiveDataFilter(logging.Filter): class SensitiveDataFilter(logging.Filter):
-1
View File
@@ -2,7 +2,6 @@
from app.extensions import db from app.extensions import db
org_team_coaches = db.Table( org_team_coaches = db.Table(
'org_team_coaches', 'org_team_coaches',
db.Column( db.Column(
+1 -1
View File
@@ -1,7 +1,7 @@
"""Availability models — BaseAvailability and its concrete subclasses.""" """Availability models — BaseAvailability and its concrete subclasses."""
from app.models.availability.base import BaseAvailability from app.models.availability.base import BaseAvailability
from app.models.availability.player_disponibility import PlayerDisponibility
from app.models.availability.coach_availability import CoachAvailability from app.models.availability.coach_availability import CoachAvailability
from app.models.availability.player_disponibility import PlayerDisponibility
__all__ = ['BaseAvailability', 'PlayerDisponibility', 'CoachAvailability'] __all__ = ['BaseAvailability', 'PlayerDisponibility', 'CoachAvailability']
+2 -1
View File
@@ -1,8 +1,9 @@
"""Abstract base class for availability models (PlayerDisponibility + CoachAvailability).""" """Abstract base class for availability models (PlayerDisponibility + CoachAvailability)."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class BaseAvailability(db.Model): class BaseAvailability(db.Model):
"""Shared schema for player disponibilities and coach availabilities.""" """Shared schema for player disponibilities and coach availabilities."""
+3 -2
View File
@@ -1,8 +1,9 @@
"""Contract documents for players to sign.""" """Contract documents for players to sign."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class Contract(db.Model): class Contract(db.Model):
"""Contract documents for players to sign.""" """Contract documents for players to sign."""
@@ -48,8 +49,8 @@ class Contract(db.Model):
return True return True
from app.models.user_model.admin import Admin from app.models.user_model.admin import Admin
from app.models.user_model.manager import Manager
from app.models.user_model.coach import Coach from app.models.user_model.coach import Coach
from app.models.user_model.manager import Manager
from app.models.user_model.user import User from app.models.user_model.user import User
from app.permissions import coach_can_access_player from app.permissions import coach_can_access_player
+2 -1
View File
@@ -1,8 +1,9 @@
"""Player evaluation record.""" """Player evaluation record."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class Evaluation(db.Model): class Evaluation(db.Model):
"""Player evaluation record.""" """Player evaluation record."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Abstract base class for match models (Match + TeamMatch).""" """Abstract base class for match models (Match + TeamMatch)."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class BaseMatch(db.Model): class BaseMatch(db.Model):
"""Shared schema for tryout-scoped matches and regular-season team matches.""" """Shared schema for tryout-scoped matches and regular-season team matches."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Request from player to coach for a One on One session.""" """Request from player to coach for a One on One session."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class OneOnOneRequest(db.Model): class OneOnOneRequest(db.Model):
"""Request from player to coach for a One on One session.""" """Request from player to coach for a One on One session."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Persistent organisation team (e.g. Varsity, JV).""" """Persistent organisation team (e.g. Varsity, JV)."""
from datetime import datetime
from app.extensions import db from app.extensions import db
from app.models._associations import org_team_coaches, org_team_managers from app.models._associations import org_team_coaches, org_team_managers
from datetime import datetime
class OrgTeam(db.Model): class OrgTeam(db.Model):
+2 -1
View File
@@ -1,8 +1,9 @@
"""Many-to-many junction: player to org-team.""" """Many-to-many junction: player to org-team."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class TeamPlayer(db.Model): class TeamPlayer(db.Model):
"""Many-to-many: player to org-team.""" """Many-to-many: player to org-team."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Abstract base class for match participant models.""" """Abstract base class for match participant models."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class BaseParticipant(db.Model): class BaseParticipant(db.Model):
"""Shared schema for match participants.""" """Shared schema for match participants."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Personal notes from coach to individual player.""" """Personal notes from coach to individual player."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class PersonalNote(db.Model): class PersonalNote(db.Model):
"""Personal notes from coach to individual player.""" """Personal notes from coach to individual player."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Tryout-specific team (e.g. Alpha, Bravo within a single tryout).""" """Tryout-specific team (e.g. Alpha, Bravo within a single tryout)."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class Team(db.Model): class Team(db.Model):
"""Tryout-specific team (e.g. Alpha, Bravo within a single tryout).""" """Tryout-specific team (e.g. Alpha, Bravo within a single tryout)."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Link between a player and a tryout-specific team.""" """Link between a player and a tryout-specific team."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class TeamMember(db.Model): class TeamMember(db.Model):
"""Link between a player and a tryout-specific team.""" """Link between a player and a tryout-specific team."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Team improvement notes from coach.""" """Team improvement notes from coach."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class TeamNote(db.Model): class TeamNote(db.Model):
"""Team improvement notes from coach.""" """Team improvement notes from coach."""
+2 -1
View File
@@ -1,8 +1,9 @@
"""Tryout event for player evaluations and team formation.""" """Tryout event for player evaluations and team formation."""
from datetime import datetime
from app.extensions import db from app.extensions import db
from app.models._associations import tryout_coaches from app.models._associations import tryout_coaches
from datetime import datetime
class Tryout(db.Model): class Tryout(db.Model):
+2 -1
View File
@@ -1,8 +1,9 @@
"""Registration linking a player to a tryout.""" """Registration linking a player to a tryout."""
from app.extensions import db
from datetime import datetime from datetime import datetime
from app.extensions import db
class TryoutRegistration(db.Model): class TryoutRegistration(db.Model):
"""Registration linking a player to a tryout.""" """Registration linking a player to a tryout."""
+3 -2
View File
@@ -1,9 +1,10 @@
"""Store gamertag per game for each user.""" """Store gamertag per game for each user."""
from app.extensions import db
from app.models._constants import TRN_URLS, PLATFORM_CODES, PLATFORM_DEFAULTS
from urllib.parse import quote from urllib.parse import quote
from app.extensions import db
from app.models._constants import PLATFORM_CODES, PLATFORM_DEFAULTS, TRN_URLS
class UserGamertag(db.Model): class UserGamertag(db.Model):
"""Store gamertag per game for each user.""" """Store gamertag per game for each user."""
+2 -2
View File
@@ -1,10 +1,10 @@
"""User hierarchy — single-table polymorphic inheritance (User → Admin, Manager, Coach, Player, Scout).""" """User hierarchy — single-table polymorphic inheritance (User → Admin, Manager, Coach, Player, Scout)."""
from app.models.user_model.user import User
from app.models.user_model.admin import Admin from app.models.user_model.admin import Admin
from app.models.user_model.manager import Manager
from app.models.user_model.coach import Coach from app.models.user_model.coach import Coach
from app.models.user_model.manager import Manager
from app.models.user_model.player import Player from app.models.user_model.player import Player
from app.models.user_model.scout import Scout from app.models.user_model.scout import Scout
from app.models.user_model.user import User
__all__ = ['User', 'Admin', 'Manager', 'Coach', 'Player', 'Scout'] __all__ = ['User', 'Admin', 'Manager', 'Coach', 'Player', 'Scout']
+2 -1
View File
@@ -27,9 +27,10 @@ class Manager(User):
return True return True
def get_visible_tryouts(self): def get_visible_tryouts(self):
from app.models.tryout.tryout import Tryout
from sqlalchemy import or_ from sqlalchemy import or_
from app.models.tryout.tryout import Tryout
return ( return (
Tryout.query.filter(or_(Tryout.created_by == self.id, Tryout.manager_id == self.id)) Tryout.query.filter(or_(Tryout.created_by == self.id, Tryout.manager_id == self.id))
.order_by(Tryout.date) .order_by(Tryout.date)
+1 -1
View File
@@ -9,9 +9,9 @@ class Player(User):
__mapper_args__ = {'polymorphic_identity': 'player'} __mapper_args__ = {'polymorphic_identity': 'player'}
def get_visible_tryouts(self): def get_visible_tryouts(self):
from app.models.tryout.tryout import Tryout
from app.models.match_model.match import Match from app.models.match_model.match import Match
from app.models.participant.match_participant import MatchParticipant from app.models.participant.match_participant import MatchParticipant
from app.models.tryout.tryout import Tryout
# tryouts they registered for # tryouts they registered for
player_tryout_ids = [r.tryout_id for r in self.tryout_registrations.all()] player_tryout_ids = [r.tryout_id for r in self.tryout_registrations.all()]
+4 -2
View File
@@ -1,9 +1,11 @@
"""Base User model — shared fields and polymorphic configuration.""" """Base User model — shared fields and polymorphic configuration."""
from app.extensions import db
from flask_login import UserMixin
from datetime import datetime from datetime import datetime
from flask_login import UserMixin
from app.extensions import db
class User(UserMixin, db.Model): class User(UserMixin, db.Model):
"""Base user model — shared fields for every role. """Base user model — shared fields for every role.
-1
View File
@@ -28,7 +28,6 @@ and from tests without a request context.
from app.extensions import db from app.extensions import db
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Team attachment # Team attachment
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
+12 -10
View File
@@ -5,21 +5,23 @@ protection, logout with session clearing, and new user registration with
password policy enforcement and CAPTCHA verification. password policy enforcement and CAPTCHA verification.
""" """
import uuid
import os import os
import secrets import secrets
import uuid
from datetime import datetime, timedelta from datetime import datetime, timedelta
from flask import Blueprint, render_template, redirect, url_for, flash, request, session from urllib.parse import urlencode, urlparse
from flask_login import login_user, logout_user, login_required, current_user
from app.extensions import db, hash_password, check_password, limiter import requests
from app.models import User, Player, ESPORT_GAMES from flask import Blueprint, flash, redirect, render_template, request, session, url_for
from app.validators import RegisterSchema, LoginSchema from flask_babel import gettext as _
from flask_login import current_user, login_required, login_user, logout_user
from marshmallow import ValidationError
from app.extensions import check_password, db, hash_password, limiter
from app.i18n import LOCALE_SESSION_KEY from app.i18n import LOCALE_SESSION_KEY
from app.logging_config import log_auth_event from app.logging_config import log_auth_event
from flask_babel import gettext as _ from app.models import ESPORT_GAMES, Player, User
from marshmallow import ValidationError from app.validators import LoginSchema, RegisterSchema
from urllib.parse import urlparse, urlencode
import requests
#: Session key holding the pending OAuth2 anti-forgery token. #: Session key holding the pending OAuth2 anti-forgery token.
DISCORD_STATE_KEY = 'discord_oauth_state' DISCORD_STATE_KEY = 'discord_oauth_state'
+13 -12
View File
@@ -3,22 +3,23 @@
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import login_required, current_user
from flask_babel import gettext as _ from flask_babel import gettext as _
from app.extensions import db from flask_login import current_user, login_required
from app.models import (
Admin,
Player,
User,
Tryout,
Evaluation,
TryoutRegistration,
GAME_POSITIONS,
)
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from app.extensions import db
from app.models import (
GAME_POSITIONS,
Admin,
Evaluation,
Player,
Tryout,
TryoutRegistration,
User,
)
evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations') evaluations_bp = Blueprint('evaluations', __name__, url_prefix='/evaluations')
+13 -11
View File
@@ -3,27 +3,29 @@
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request from datetime import date
from flask_login import login_required, current_user
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required
from sqlalchemy import func
from app.extensions import db from app.extensions import db
from app.models import ( from app.models import (
Admin, Admin,
Manager,
Coach, Coach,
Player,
Scout,
User,
Tryout,
Evaluation, Evaluation,
TryoutRegistration, Manager,
TeamMember,
Match, Match,
MatchParticipant, MatchParticipant,
Player,
Scout,
TeamMember,
Tryout,
TryoutRegistration,
User,
) )
from app.permissions import coach_tryout_ids from app.permissions import coach_tryout_ids
from sqlalchemy import func
from datetime import date
main_bp = Blueprint('main', __name__) main_bp = Blueprint('main', __name__)
+15 -14
View File
@@ -3,30 +3,31 @@
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify from datetime import datetime, timedelta
from flask_login import login_required, current_user
from flask import Blueprint, flash, jsonify, redirect, render_template, request, url_for
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required
from sqlalchemy.orm import joinedload
from app.extensions import db from app.extensions import db
from app.models import ( from app.models import (
Admin, Admin,
Manager,
Coach, Coach,
Player, Manager,
Scout,
User,
Tryout,
Match, Match,
MatchParticipant, MatchParticipant,
Team,
TeamMember,
TryoutRegistration,
PlayerDisponibility,
OneOnOneRequest, OneOnOneRequest,
PersonalNote, PersonalNote,
Player,
PlayerDisponibility,
Scout,
Team,
TeamMember,
Tryout,
TryoutRegistration,
User,
) )
from datetime import datetime, timedelta
from sqlalchemy.orm import joinedload
from app.services.scheduling import notify_participants, zip_participants from app.services.scheduling import notify_participants, zip_participants
matches_bp = Blueprint('matches', __name__, url_prefix='/matches') matches_bp = Blueprint('matches', __name__, url_prefix='/matches')
+7 -5
View File
@@ -3,22 +3,24 @@
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify from datetime import datetime, timedelta
from flask_login import login_required, current_user
from flask import Blueprint, flash, jsonify, redirect, render_template, request, url_for
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required
from app.extensions import db from app.extensions import db
from app.models import ( from app.models import (
Admin, Admin,
Manager,
Coach, Coach,
Player, Manager,
OrgTeam, OrgTeam,
Player,
TeamMatch, TeamMatch,
TeamMatchParticipant, TeamMatchParticipant,
TeamPlayer, TeamPlayer,
) )
from app.permissions import can_manage_org_team, coach_org_teams, visible_org_teams from app.permissions import can_manage_org_team, coach_org_teams, visible_org_teams
from datetime import datetime, timedelta
from app.services.scheduling import notify_participants, zip_participants from app.services.scheduling import notify_participants, zip_participants
team_matches_bp = Blueprint('team_matches', __name__, url_prefix='/team-matches') team_matches_bp = Blueprint('team_matches', __name__, url_prefix='/team-matches')
+14 -12
View File
@@ -3,27 +3,29 @@
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify from datetime import datetime
from flask_login import login_required, current_user
from flask import Blueprint, flash, jsonify, redirect, render_template, request, url_for
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required
from app.extensions import db from app.extensions import db
from app.models import ( from app.models import (
Admin, Admin,
Manager,
Coach, Coach,
Player,
OrgTeam,
User,
PersonalNote,
TeamNote,
Tryout,
TeamPlayer,
TeamMatch,
Contract, Contract,
Manager,
OneOnOneRequest, OneOnOneRequest,
OrgTeam,
PersonalNote,
Player,
TeamMatch,
TeamNote,
TeamPlayer,
Tryout,
User,
) )
from app.permissions import visible_org_teams from app.permissions import visible_org_teams
from datetime import datetime
teams_bp = Blueprint('teams', __name__, url_prefix='/teams') teams_bp = Blueprint('teams', __name__, url_prefix='/teams')
+20 -18
View File
@@ -4,30 +4,32 @@ This module handles CRUD operations for tryouts and player registrations.
Uses polymorphic isinstance checks instead of role-string comparisons. Uses polymorphic isinstance checks instead of role-string comparisons.
""" """
from flask import Blueprint, render_template, redirect, url_for, flash, request, abort from datetime import datetime
from flask_login import login_required, current_user
from flask import Blueprint, abort, flash, redirect, render_template, request, url_for
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required
from app.extensions import db from app.extensions import db
from app.models import ( from app.models import (
Admin,
Manager,
Coach,
Player,
Scout,
User,
Tryout,
TryoutRegistration,
Evaluation,
Team,
TeamMember,
OrgTeam,
Match,
MatchParticipant,
PersonalNote,
ESPORT_GAMES, ESPORT_GAMES,
GAME_POSITIONS, GAME_POSITIONS,
Admin,
Coach,
Evaluation,
Manager,
Match,
MatchParticipant,
OrgTeam,
PersonalNote,
Player,
Scout,
Team,
TeamMember,
Tryout,
TryoutRegistration,
User,
) )
from datetime import datetime
tryouts_bp = Blueprint('tryouts', __name__, url_prefix='/tryouts') tryouts_bp = Blueprint('tryouts', __name__, url_prefix='/tryouts')
+9 -8
View File
@@ -9,16 +9,16 @@ keeps its single `from app.routes.users import users_bp`. The blueprint
itself lives in blueprint.py to keep that import one-directional. itself lives in blueprint.py to keep that import one-directional.
""" """
from app.routes.users.blueprint import users_bp
# Imported for their side effect: each module attaches its routes to # Imported for their side effect: each module attaches its routes to
# users_bp. Order does not matter; none of them import each other. # users_bp. Order does not matter; none of them import each other.
from app.routes.users import accounts # noqa: F401,E402 from app.routes.users import (
from app.routes.users import availability # noqa: F401,E402 accounts, # noqa: F401,E402
from app.routes.users import contracts # noqa: F401,E402 availability, # noqa: F401,E402
from app.routes.users import notes # noqa: F401,E402 contracts, # noqa: F401,E402
from app.routes.users import one_on_one # noqa: F401,E402 notes, # noqa: F401,E402
from app.routes.users import profile # noqa: F401,E402 one_on_one, # noqa: F401,E402
profile, # noqa: F401,E402
)
# Re-exported because tests and other modules reach for them by name. # Re-exported because tests and other modules reach for them by name.
from app.routes.users._shared import ( # noqa: F401,E402 from app.routes.users._shared import ( # noqa: F401,E402
@@ -26,6 +26,7 @@ from app.routes.users._shared import ( # noqa: F401,E402
ALLOWED_SIGNED_EXTENSIONS, ALLOWED_SIGNED_EXTENSIONS,
pdf_upload_error, pdf_upload_error,
) )
from app.routes.users.blueprint import users_bp
__all__ = [ __all__ = [
'ALLOWED_CONTRACT_EXTENSIONS', 'ALLOWED_CONTRACT_EXTENSIONS',
+1 -1
View File
@@ -8,7 +8,7 @@ from flask import flash, request
from flask_babel import gettext as _ from flask_babel import gettext as _
from app.extensions import db from app.extensions import db
from app.models import Admin, Coach, Manager, Player, Scout, GAME_PLATFORMS, UserGamertag from app.models import GAME_PLATFORMS, Admin, Coach, Manager, Player, Scout, UserGamertag
ALLOWED_CONTRACT_EXTENSIONS = {'pdf'} ALLOWED_CONTRACT_EXTENSIONS = {'pdf'}
ALLOWED_SIGNED_EXTENSIONS = {'pdf'} ALLOWED_SIGNED_EXTENSIONS = {'pdf'}
+3 -3
View File
@@ -12,12 +12,13 @@ from marshmallow import ValidationError
from app.extensions import db, hash_password from app.extensions import db, hash_password
from app.logging_config import log_auth_event from app.logging_config import log_auth_event
from app.models import ( from app.models import (
ESPORT_GAMES,
GAME_PLATFORMS,
USER_TYPES,
Admin, Admin,
CoachAvailability, CoachAvailability,
Contract, Contract,
ESPORT_GAMES,
Evaluation, Evaluation,
GAME_PLATFORMS,
Match, Match,
MatchParticipant, MatchParticipant,
OneOnOneRequest, OneOnOneRequest,
@@ -31,7 +32,6 @@ from app.models import (
TeamPlayer, TeamPlayer,
Tryout, Tryout,
TryoutRegistration, TryoutRegistration,
USER_TYPES,
User, User,
UserGamertag, UserGamertag,
) )
-1
View File
@@ -15,7 +15,6 @@ from app.extensions import db
from app.models import Coach, CoachAvailability, PlayerDisponibility, User from app.models import Coach, CoachAvailability, PlayerDisponibility, User
from app.routes.users.blueprint import users_bp from app.routes.users.blueprint import users_bp
DAY_NAMES = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] DAY_NAMES = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
+2 -1
View File
@@ -119,7 +119,8 @@ def one_on_one():
return redirect(url_for('users.one_on_one')) return redirect(url_for('users.one_on_one'))
# Build list of upcoming dates that have coach availability # Build list of upcoming dates that have coach availability
from datetime import date as date_cls, timedelta as td from datetime import date as date_cls
from datetime import timedelta as td
today = date_cls.today() today = date_cls.today()
available_days = {av['day_of_week'] for av in coach_availability} available_days = {av['day_of_week'] for av in coach_availability}
+3 -3
View File
@@ -8,11 +8,11 @@ from marshmallow import ValidationError
from app.extensions import db, hash_password from app.extensions import db, hash_password
from app.logging_config import log_auth_event from app.logging_config import log_auth_event
from app.models import ( from app.models import (
CoachAvailability,
Coach,
Contract,
ESPORT_GAMES, ESPORT_GAMES,
GAME_PLATFORMS, GAME_PLATFORMS,
Coach,
CoachAvailability,
Contract,
Player, Player,
User, User,
) )
+3 -1
View File
@@ -13,10 +13,12 @@ Accept the self-signed certificate warning in your browser to proceed.
import os import os
import socket import socket
import subprocess
import ssl import ssl
import subprocess
import sys import sys
from waitress.server import create_server from waitress.server import create_server
from app.app import create_app from app.app import create_app
CERT_FILE = 'certs/localhost.pem' CERT_FILE = 'certs/localhost.pem'
+4 -4
View File
@@ -12,12 +12,12 @@ Usage:
python security_scan.py [--url http://localhost:5000] python security_scan.py [--url http://localhost:5000]
""" """
import os
import sys
import json import json
import subprocess import os
import urllib.request
import ssl import ssl
import subprocess
import sys
import urllib.request
from datetime import datetime from datetime import datetime
+8 -7
View File
@@ -11,18 +11,19 @@ Usage:
""" """
import re import re
from flask_babel import lazy_gettext as _l from flask_babel import lazy_gettext as _l
from marshmallow import ( from marshmallow import (
Schema,
fields,
validate,
ValidationError,
pre_load,
validates_schema,
EXCLUDE, EXCLUDE,
Schema,
ValidationError,
fields,
pre_load,
validate,
validates_schema,
) )
from app.models import USER_TYPES
from app.models import USER_TYPES
# ============================================================================= # =============================================================================
# Custom Validators # Custom Validators
+12 -6
View File
@@ -42,11 +42,10 @@ exclude = [".venv", "venv", "migrations", "docs"]
# RET return-flow tidiness # RET return-flow tidiness
# SIM obvious simplifications # SIM obvious simplifications
# UP syntax available on the 3.12 this targets # UP syntax available on the 3.12 this targets
# # I isort; enabled in its own commit, for the same reason the
# isort (I) is not enabled yet: it would reorder imports in 48 files, i.e. a # formatting got one — the diff is churn and must not hide
# second sweep of pure churn right after the formatting commit. Worth doing, # behind a behavioural change
# worth doing on its own. select = ["E4", "E7", "E9", "F", "B", "C4", "RET", "SIM", "UP", "I"]
select = ["E4", "E7", "E9", "F", "B", "C4", "RET", "SIM", "UP"]
# Forcing a ternary reads worse than the if/else it replaces in the one place # Forcing a ternary reads worse than the if/else it replaces in the one place
# it fires (evaluations.py, choosing a sort direction). # it fires (evaluations.py, choosing a sort direction).
@@ -56,7 +55,14 @@ ignore = ["SIM108"]
# Intentional re-export facade: `from app.models import User, Tryout, ...` # Intentional re-export facade: `from app.models import User, Tryout, ...`
# is the documented entry point, and importing the modules is what # is the documented entry point, and importing the modules is what
# registers every model with SQLAlchemy. # registers every model with SQLAlchemy.
"app/models/__init__.py" = ["F401"] #
# I001 is off here too. The imports are grouped into eleven commented
# layers that spell out the dependency graph (constants → users → teams →
# tryouts → matches → participants). Alphabetising them leaves every
# heading above an import it does not describe, and the file's one job is
# to be read. The order is documentation, not a requirement: the suite
# passes either way.
"app/models/__init__.py" = ["F401", "I001"]
"app/models/user_model/__init__.py" = ["F401"] "app/models/user_model/__init__.py" = ["F401"]
"tests/conftest.py" = ["E402"] "tests/conftest.py" = ["E402"]
+2 -1
View File
@@ -98,9 +98,10 @@ class TestHorizontalAccess:
def test_player_cannot_delete_another_players_availability( def test_player_cannot_delete_another_players_availability(
self, app, client, as_role, make_user self, app, client, as_role, make_user
): ):
from app.models import PlayerDisponibility
from datetime import time from datetime import time
from app.models import PlayerDisponibility
owner_id = make_user('player') owner_id = make_user('player')
with app.app_context(): with app.app_context():
slot = PlayerDisponibility( slot = PlayerDisponibility(
+2 -1
View File
@@ -12,8 +12,9 @@ Configuration via environment variables:
WAITRESS_THREADS: Number of worker threads (default: CPU*2+1) WAITRESS_THREADS: Number of worker threads (default: CPU*2+1)
""" """
import os
import multiprocessing import multiprocessing
import os
from app.app import create_app from app.app import create_app
app = create_app() app = create_app()