Almost there

parent 7fc35762
...@@ -633,6 +633,14 @@ class UpdatesResponseHandler(ResponseHandler): ...@@ -633,6 +633,14 @@ class UpdatesResponseHandler(ResponseHandler):
if not zip_filename: if not zip_filename:
continue continue
# Check if ZIP has already been validated successfully
if match.zip_validation_status == 'valid':
logger.debug(f"ZIP file already validated: {zip_filename} for fixture {fixture_id}")
continue
elif match.zip_validation_status == 'validating':
logger.debug(f"ZIP file validation in progress: {zip_filename} for fixture {fixture_id}")
continue
logger.debug(f"Validating ZIP file: {zip_filename} for fixture {fixture_id}") logger.debug(f"Validating ZIP file: {zip_filename} for fixture {fixture_id}")
zip_path = self.zip_storage_dir / zip_filename zip_path = self.zip_storage_dir / zip_filename
...@@ -649,6 +657,9 @@ class UpdatesResponseHandler(ResponseHandler): ...@@ -649,6 +657,9 @@ class UpdatesResponseHandler(ResponseHandler):
fixture_valid = False fixture_valid = False
else: else:
logger.debug(f"ZIP file validation passed: {zip_filename}") logger.debug(f"ZIP file validation passed: {zip_filename}")
# Mark as validated in database
match.zip_validation_status = 'valid'
session.commit()
if not fixture_valid: if not fixture_valid:
logger.warning(f"Fixture {fixture_id} has invalid/missing ZIP files: {missing_or_invalid_zips}") logger.warning(f"Fixture {fixture_id} has invalid/missing ZIP files: {missing_or_invalid_zips}")
......
This diff is collapsed.
...@@ -526,7 +526,7 @@ class MatchTimerComponent(ThreadedComponent): ...@@ -526,7 +526,7 @@ class MatchTimerComponent(ThreadedComponent):
# Find the most recently completed match in this fixture # Find the most recently completed match in this fixture
last_match = session.query(MatchModel).filter( last_match = session.query(MatchModel).filter(
MatchModel.fixture_id == fixture_id, MatchModel.fixture_id == fixture_id,
MatchModel.status.in_(['done', 'cancelled', 'failed']), MatchModel.status.in_(['done', 'end', 'cancelled', 'failed']),
MatchModel.active_status == True MatchModel.active_status == True
).order_by(MatchModel.updated_at.desc()).first() ).order_by(MatchModel.updated_at.desc()).first()
...@@ -547,7 +547,7 @@ class MatchTimerComponent(ThreadedComponent): ...@@ -547,7 +547,7 @@ class MatchTimerComponent(ThreadedComponent):
# Build query for completed matches # Build query for completed matches
# Exclude matches from fixtures that contain "_recycle_" in the fixture name # Exclude matches from fixtures that contain "_recycle_" in the fixture name
query = session.query(MatchModel).filter( query = session.query(MatchModel).filter(
MatchModel.status.in_(['done', 'cancelled', 'failed']), MatchModel.status.in_(['done', 'end', 'cancelled', 'failed']),
MatchModel.active_status == True, MatchModel.active_status == True,
~MatchModel.fixture_id.like('%_recycle_%') ~MatchModel.fixture_id.like('%_recycle_%')
) )
......
...@@ -2316,6 +2316,50 @@ class Migration_029_ChangeMatchNumberToUniqueWithinFixture(DatabaseMigration): ...@@ -2316,6 +2316,50 @@ class Migration_029_ChangeMatchNumberToUniqueWithinFixture(DatabaseMigration):
logger.error(f"Failed to revert match_number constraint: {e}") logger.error(f"Failed to revert match_number constraint: {e}")
return False return False
class Migration_030_AddZipValidationStatus(DatabaseMigration):
"""Add zip_validation_status field to matches table"""
def __init__(self):
super().__init__("030", "Add zip_validation_status field to matches table")
def up(self, db_manager) -> bool:
"""Add zip_validation_status column to matches table"""
try:
with db_manager.engine.connect() as conn:
# Check if zip_validation_status column already exists
result = conn.execute(text("PRAGMA table_info(matches)"))
columns = [row[1] for row in result.fetchall()]
if 'zip_validation_status' not in columns:
# Add zip_validation_status column with default value 'pending'
conn.execute(text("""
ALTER TABLE matches
ADD COLUMN zip_validation_status VARCHAR(20) DEFAULT 'pending'
"""))
# Add index for zip_validation_status column
conn.execute(text("""
CREATE INDEX IF NOT EXISTS ix_matches_zip_validation_status
ON matches(zip_validation_status)
"""))
conn.commit()
logger.info("zip_validation_status column added to matches table")
else:
logger.info("zip_validation_status column already exists in matches table")
return True
except Exception as e:
logger.error(f"Failed to add zip_validation_status field to matches: {e}")
return False
def down(self, db_manager) -> bool:
"""Remove zip_validation_status column - SQLite doesn't support DROP COLUMN easily"""
logger.warning("SQLite doesn't support DROP COLUMN - zip_validation_status column will remain")
return True
# Registry of all migrations in order # Registry of all migrations in order
MIGRATIONS: List[DatabaseMigration] = [ MIGRATIONS: List[DatabaseMigration] = [
Migration_001_InitialSchema(), Migration_001_InitialSchema(),
...@@ -2347,6 +2391,7 @@ MIGRATIONS: List[DatabaseMigration] = [ ...@@ -2347,6 +2391,7 @@ MIGRATIONS: List[DatabaseMigration] = [
Migration_027_AddDefaultIntroTemplatesConfig(), Migration_027_AddDefaultIntroTemplatesConfig(),
Migration_028_AddFixtureRefreshIntervalConfig(), Migration_028_AddFixtureRefreshIntervalConfig(),
Migration_029_ChangeMatchNumberToUniqueWithinFixture(), Migration_029_ChangeMatchNumberToUniqueWithinFixture(),
Migration_030_AddZipValidationStatus(),
] ]
......
...@@ -472,6 +472,7 @@ class MatchModel(BaseModel): ...@@ -472,6 +472,7 @@ class MatchModel(BaseModel):
Index('ix_matches_file_sha1sum', 'file_sha1sum'), Index('ix_matches_file_sha1sum', 'file_sha1sum'),
Index('ix_matches_zip_sha1sum', 'zip_sha1sum'), Index('ix_matches_zip_sha1sum', 'zip_sha1sum'),
Index('ix_matches_zip_upload_status', 'zip_upload_status'), Index('ix_matches_zip_upload_status', 'zip_upload_status'),
Index('ix_matches_zip_validation_status', 'zip_validation_status'),
Index('ix_matches_created_by', 'created_by'), Index('ix_matches_created_by', 'created_by'),
Index('ix_matches_fixture_active_time', 'fixture_active_time'), Index('ix_matches_fixture_active_time', 'fixture_active_time'),
Index('ix_matches_composite', 'active_status', 'zip_upload_status', 'created_at'), Index('ix_matches_composite', 'active_status', 'zip_upload_status', 'created_at'),
...@@ -504,6 +505,7 @@ class MatchModel(BaseModel): ...@@ -504,6 +505,7 @@ class MatchModel(BaseModel):
zip_sha1sum = Column(String(255), comment='SHA1 checksum of ZIP file') zip_sha1sum = Column(String(255), comment='SHA1 checksum of ZIP file')
zip_upload_status = Column(String(20), default='pending', comment='Upload status: pending, uploading, completed, failed') zip_upload_status = Column(String(20), default='pending', comment='Upload status: pending, uploading, completed, failed')
zip_upload_progress = Column(Float, default=0.0, comment='Upload progress percentage (0.0-100.0)') zip_upload_progress = Column(Float, default=0.0, comment='Upload progress percentage (0.0-100.0)')
zip_validation_status = Column(String(20), default='pending', comment='Validation status: pending, validating, valid, invalid, failed')
# User tracking # User tracking
created_by = Column(Integer, ForeignKey('users.id'), comment='User who created this record') created_by = Column(Integer, ForeignKey('users.id'), comment='User who created this record')
......
This diff is collapsed.
...@@ -116,6 +116,7 @@ ...@@ -116,6 +116,7 @@
<th>Fighters</th> <th>Fighters</th>
<th>Status</th> <th>Status</th>
<th>Start Time</th> <th>Start Time</th>
<th>End Time</th>
<th>Result</th> <th>Result</th>
<th>Outcomes</th> <th>Outcomes</th>
<th>Actions</th> <th>Actions</th>
...@@ -391,6 +392,7 @@ function renderMatchesTable(matches) { ...@@ -391,6 +392,7 @@ function renderMatchesTable(matches) {
matches.forEach(match => { matches.forEach(match => {
const row = document.createElement('tr'); const row = document.createElement('tr');
const startTimeDisplay = match.start_time ? new Date(match.start_time).toLocaleString() : 'Not set'; const startTimeDisplay = match.start_time ? new Date(match.start_time).toLocaleString() : 'Not set';
const endTimeDisplay = match.end_time ? new Date(match.end_time).toLocaleString() : 'Not set';
const resultDisplay = match.result || 'Not available'; const resultDisplay = match.result || 'Not available';
const outcomesCount = match.outcome_count || 0; const outcomesCount = match.outcome_count || 0;
...@@ -403,6 +405,7 @@ function renderMatchesTable(matches) { ...@@ -403,6 +405,7 @@ function renderMatchesTable(matches) {
</td> </td>
<td>${getStatusBadge(match)}</td> <td>${getStatusBadge(match)}</td>
<td><small class="text-info">${startTimeDisplay}</small></td> <td><small class="text-info">${startTimeDisplay}</small></td>
<td><small class="text-success">${endTimeDisplay}</small></td>
<td><small class="text-muted">${resultDisplay}</small></td> <td><small class="text-muted">${resultDisplay}</small></td>
<td><span class="badge bg-light text-dark">${outcomesCount} outcomes</span></td> <td><span class="badge bg-light text-dark">${outcomesCount} outcomes</span></td>
<td> <td>
...@@ -438,6 +441,7 @@ function updateMatchesTable(matches) { ...@@ -438,6 +441,7 @@ function updateMatchesTable(matches) {
processedMatches.add(match.id); processedMatches.add(match.id);
const startTimeDisplay = match.start_time ? new Date(match.start_time).toLocaleString() : 'Not set'; const startTimeDisplay = match.start_time ? new Date(match.start_time).toLocaleString() : 'Not set';
const endTimeDisplay = match.end_time ? new Date(match.end_time).toLocaleString() : 'Not set';
const resultDisplay = match.result || 'Not available'; const resultDisplay = match.result || 'Not available';
const outcomesCount = match.outcome_count || 0; const outcomesCount = match.outcome_count || 0;
...@@ -450,6 +454,7 @@ function updateMatchesTable(matches) { ...@@ -450,6 +454,7 @@ function updateMatchesTable(matches) {
</td> </td>
<td>${getStatusBadge(match)}</td> <td>${getStatusBadge(match)}</td>
<td><small class="text-info">${startTimeDisplay}</small></td> <td><small class="text-info">${startTimeDisplay}</small></td>
<td><small class="text-success">${endTimeDisplay}</small></td>
<td><small class="text-muted">${resultDisplay}</small></td> <td><small class="text-muted">${resultDisplay}</small></td>
<td><span class="badge bg-light text-dark">${outcomesCount} outcomes</span></td> <td><span class="badge bg-light text-dark">${outcomesCount} outcomes</span></td>
<td> <td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment