corrected time record type, mismatch caused issues and kept credential verification from occuring

This commit is contained in:
Bryan Van Deusen
2026-01-26 22:51:03 -05:00
parent 204e8efcdc
commit d2e4d6c588
4 changed files with 19 additions and 14 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
"""Credential management API endpoints.""" """Credential management API endpoints."""
from datetime import datetime
from quart import Blueprint, request, jsonify, current_app from quart import Blueprint, request, jsonify, current_app
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.models.credential import Credential, CredentialType from app.models.credential import Credential, CredentialType
from app.models.setting import Setting, EXTENSION_API_KEY_SETTING, generate_api_key from app.models.setting import Setting, EXTENSION_API_KEY_SETTING, generate_api_key
from app.models.base import utcnow
from app.config import get_settings from app.config import get_settings
from app.utils.encryption import encrypt_data, decrypt_data from app.utils.encryption import encrypt_data, decrypt_data
@@ -176,7 +176,7 @@ async def verify_credentials():
# TODO: Implement actual verification by making test request # TODO: Implement actual verification by making test request
# For now, just mark as verified # For now, just mark as verified
verified_at = datetime.utcnow() verified_at = utcnow()
credential.last_verified = verified_at credential.last_verified = verified_at
await session.commit() await session.commit()
+2 -2
View File
@@ -1,11 +1,11 @@
"""Download history API endpoints.""" """Download history API endpoints."""
from datetime import datetime
from quart import Blueprint, request, jsonify, current_app from quart import Blueprint, request, jsonify, current_app
from sqlalchemy import select, func, and_ from sqlalchemy import select, func, and_
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from app.models.base import utcnow
from app.models.download import Download, DownloadStatus from app.models.download import Download, DownloadStatus
from app.models.source import Source from app.models.source import Source
from app.tasks.downloads import process_download from app.tasks.downloads import process_download
@@ -139,7 +139,7 @@ async def recent_activity():
days = int(request.args.get("days", 7)) days = int(request.args.get("days", 7))
from datetime import timedelta from datetime import timedelta
cutoff = datetime.utcnow() - timedelta(days=days) cutoff = utcnow() - timedelta(days=days)
async with current_app.db_engine.connect() as conn: async with current_app.db_engine.connect() as conn:
session = AsyncSession(bind=conn) session = AsyncSession(bind=conn)
+6 -2
View File
@@ -11,8 +11,12 @@ class Base(DeclarativeBase):
def utcnow(): def utcnow():
"""Return current UTC time as timezone-aware datetime.""" """Return current UTC time as naive datetime (no tzinfo).
return datetime.now(timezone.utc)
Uses naive datetimes because the database columns are
TIMESTAMP WITHOUT TIME ZONE. All datetimes are assumed UTC.
"""
return datetime.now(timezone.utc).replace(tzinfo=None)
def format_datetime(dt): def format_datetime(dt):
+9 -8
View File
@@ -11,6 +11,7 @@ from sqlalchemy.orm import selectinload
from app.config import get_settings from app.config import get_settings
from app.tasks.celery_app import celery_app from app.tasks.celery_app import celery_app
from app.models.base import utcnow
from app.models.source import Source from app.models.source import Source
from app.models.subscription import Subscription from app.models.subscription import Subscription
from app.models.download import Download, DownloadStatus, ErrorType as DBErrorType from app.models.download import Download, DownloadStatus, ErrorType as DBErrorType
@@ -77,7 +78,7 @@ async def _download_source_async(source_id: int) -> dict:
source_id=source.id, source_id=source.id,
url=source.url, url=source.url,
status=DownloadStatus.RUNNING, status=DownloadStatus.RUNNING,
started_at=datetime.utcnow(), started_at=utcnow(),
) )
session.add(download) session.add(download)
await session.commit() await session.commit()
@@ -123,7 +124,7 @@ async def _download_source_async(source_id: int) -> dict:
) )
# Update download record # Update download record
download.completed_at = datetime.utcnow() download.completed_at = utcnow()
download.file_count = dl_result.files_downloaded download.file_count = dl_result.files_downloaded
download.metadata_ = { download.metadata_ = {
"stdout": dl_result.stdout[:10000] if dl_result.stdout else None, # Truncate "stdout": dl_result.stdout[:10000] if dl_result.stdout else None, # Truncate
@@ -133,7 +134,7 @@ async def _download_source_async(source_id: int) -> dict:
if dl_result.success: if dl_result.success:
download.status = DownloadStatus.COMPLETED download.status = DownloadStatus.COMPLETED
source.last_success = datetime.utcnow() source.last_success = utcnow()
source.error_count = 0 source.error_count = 0
logger.info(f"Download completed for {subscription_name}/{source.platform}: {dl_result.files_downloaded} files") logger.info(f"Download completed for {subscription_name}/{source.platform}: {dl_result.files_downloaded} files")
@@ -164,7 +165,7 @@ async def _download_source_async(source_id: int) -> dict:
}) })
# Update source last_check # Update source last_check
source.last_check = datetime.utcnow() source.last_check = utcnow()
await session.commit() await session.commit()
return { return {
@@ -183,9 +184,9 @@ async def _download_source_async(source_id: int) -> dict:
download.status = DownloadStatus.FAILED download.status = DownloadStatus.FAILED
download.error_type = DBErrorType.UNKNOWN_ERROR download.error_type = DBErrorType.UNKNOWN_ERROR
download.error_message = str(e) download.error_message = str(e)
download.completed_at = datetime.utcnow() download.completed_at = utcnow()
source.error_count = (source.error_count or 0) + 1 source.error_count = (source.error_count or 0) + 1
source.last_check = datetime.utcnow() source.last_check = utcnow()
await session.commit() await session.commit()
@@ -219,7 +220,7 @@ async def _scheduled_check_async() -> dict:
try: try:
async with session_factory() as session: async with session_factory() as session:
now = datetime.utcnow() now = utcnow()
# Find sources due for checking: # Find sources due for checking:
# - enabled = True # - enabled = True
@@ -286,7 +287,7 @@ async def _cleanup_old_downloads_async() -> dict:
try: try:
async with session_factory() as session: async with session_factory() as session:
now = datetime.utcnow() now = utcnow()
# Delete completed downloads older than 30 days # Delete completed downloads older than 30 days
completed_cutoff = now - timedelta(days=30) completed_cutoff = now - timedelta(days=30)