Codebase hardening: 102 fixes across 35+ files
Deep audit identified 106 findings; 102 fixed, 4 deferred. Covers 8 areas: - Settings & deploy: env-gated DEBUG/SECRET_KEY, HTTPS headers, gunicorn, celery worker - Auth (registered_user): password write_only, request.data fixes, transaction safety, proper HTTP status codes - Workout app: IDOR protection, get_object_or_404, prefetch_related N+1 fixes, transaction.atomic - Video/scripts: path traversal sanitization, HLS trigger guard, auth on cache wipe - Models (exercise/equipment/muscle/superset): null-safe __str__, stable IDs, prefetch support - Generator views: helper for registered_user lookup, logger.exception, bulk_update, transaction wrapping - Generator core (rules/selector/generator): push-pull ratio, type affinity normalization, modality checks, side-pair exact match, word-boundary regex, equipment cache clearing - Generator services (plan_builder/analyzer/normalizer): transaction.atomic, muscle cache, bulk_update, glutes classification fix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -919,8 +919,8 @@ class Command(BaseCommand):
|
||||
verbose = options['verbose']
|
||||
strategy = options.get('classification_strategy', 'rules')
|
||||
|
||||
exercises = Exercise.objects.all()
|
||||
total = exercises.count()
|
||||
exercises = list(Exercise.objects.all())
|
||||
total = len(exercises)
|
||||
updated = 0
|
||||
stats = {
|
||||
'is_compound': {'True': 0, 'False': 0},
|
||||
@@ -938,6 +938,10 @@ class Command(BaseCommand):
|
||||
if ex.name:
|
||||
name_to_exercise[ex.name] = ex
|
||||
|
||||
# Collect exercises to bulk_update instead of saving one at a time
|
||||
exercises_to_update = []
|
||||
fields_to_update = set()
|
||||
|
||||
for ex in exercises:
|
||||
if strategy == 'regex':
|
||||
from generator.management.commands.classify_exercises import classify_exercise
|
||||
@@ -1003,7 +1007,9 @@ class Command(BaseCommand):
|
||||
ex.stretch_position = stretch
|
||||
if progression_target:
|
||||
ex.progression_of = progression_target
|
||||
ex.save()
|
||||
exercises_to_update.append(ex)
|
||||
for field, _, _ in changes:
|
||||
fields_to_update.add(field)
|
||||
updated += 1
|
||||
if verbose:
|
||||
prefix = '[DRY RUN] ' if dry_run else ''
|
||||
@@ -1011,6 +1017,12 @@ class Command(BaseCommand):
|
||||
for field, old, new in changes:
|
||||
self.stdout.write(f' {field}: {old} -> {new}')
|
||||
|
||||
# Bulk update all modified exercises in batches
|
||||
if exercises_to_update and not dry_run:
|
||||
Exercise.objects.bulk_update(
|
||||
exercises_to_update, list(fields_to_update), batch_size=500
|
||||
)
|
||||
|
||||
# Fix #11: Correct is_weight=True on known non-weight exercises
|
||||
NON_WEIGHT_OVERRIDES = ['wall sit', 'agility ladder', 'plank', 'dead hang', 'l sit']
|
||||
weight_fixed = 0
|
||||
|
||||
@@ -46,16 +46,18 @@ class Command(BaseCommand):
|
||||
dry_run = options['dry_run']
|
||||
rest_between_rounds = options['rest']
|
||||
|
||||
workouts = Workout.objects.all()
|
||||
workouts = Workout.objects.prefetch_related(
|
||||
'superset_workout__superset_exercises__exercise'
|
||||
).all()
|
||||
total = workouts.count()
|
||||
updated = 0
|
||||
|
||||
for workout in workouts:
|
||||
supersets = Superset.objects.filter(workout=workout).order_by('order')
|
||||
supersets = workout.superset_workout.all().order_by('order')
|
||||
workout_total_time = 0
|
||||
|
||||
for ss in supersets:
|
||||
exercises = SupersetExercise.objects.filter(superset=ss)
|
||||
exercises = ss.superset_exercises.all()
|
||||
active_time = 0.0
|
||||
|
||||
for se in exercises:
|
||||
|
||||
Reference in New Issue
Block a user