corrected time record type, mismatch caused issues and kept credential verification from occuring
This commit is contained in:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user