mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-18 04:33:59 -05:00
Use timezone-aware timestamps and update tests
This commit is contained in:
@@ -11,6 +11,7 @@ from sqlalchemy import select
|
|||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
# Password hashing
|
# Password hashing
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
@@ -33,9 +34,9 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
|
|||||||
"""Create a JWT access token"""
|
"""Create a JWT access token"""
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
if expires_delta:
|
if expires_delta:
|
||||||
expire = datetime.utcnow() + expires_delta
|
expire = utc_now() + expires_delta
|
||||||
else:
|
else:
|
||||||
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
expire = utc_now() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
|
|
||||||
to_encode.update({"exp": expire, "type": "access"})
|
to_encode.update({"exp": expire, "type": "access"})
|
||||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||||
@@ -45,7 +46,7 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -
|
|||||||
def create_refresh_token(data: dict) -> str:
|
def create_refresh_token(data: dict) -> str:
|
||||||
"""Create a JWT refresh token"""
|
"""Create a JWT refresh token"""
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
|
expire = utc_now() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
|
||||||
to_encode.update({"exp": expire, "type": "refresh"})
|
to_encode.update({"exp": expire, "type": "refresh"})
|
||||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from typing import Optional
|
|||||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Float, JSON, ForeignKey, Text
|
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Float, JSON, ForeignKey, Text
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from app.database import Base
|
from app.database import Base
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
|
|
||||||
class Device(Base):
|
class Device(Base):
|
||||||
@@ -59,8 +60,8 @@ class Device(Base):
|
|||||||
owner = relationship("User", back_populates="devices")
|
owner = relationship("User", back_populates="devices")
|
||||||
|
|
||||||
# Timestamps
|
# Timestamps
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
created_at = Column(DateTime, default=utc_now)
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
updated_at = Column(DateTime, default=utc_now, onupdate=utc_now)
|
||||||
|
|
||||||
# Relations
|
# Relations
|
||||||
metrics = relationship("DeviceMetric", back_populates="device", cascade="all, delete-orphan")
|
metrics = relationship("DeviceMetric", back_populates="device", cascade="all, delete-orphan")
|
||||||
@@ -76,7 +77,7 @@ class DeviceMetric(Base):
|
|||||||
device_id = Column(Integer, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False)
|
device_id = Column(Integer, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False)
|
||||||
|
|
||||||
# Metric data
|
# Metric data
|
||||||
timestamp = Column(DateTime, default=datetime.utcnow, index=True)
|
timestamp = Column(DateTime, default=utc_now, index=True)
|
||||||
cpu_usage = Column(Float)
|
cpu_usage = Column(Float)
|
||||||
ram_usage = Column(Float)
|
ram_usage = Column(Float)
|
||||||
disk_usage = Column(Float)
|
disk_usage = Column(Float)
|
||||||
@@ -100,7 +101,7 @@ class DeviceLog(Base):
|
|||||||
device_id = Column(Integer, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False)
|
device_id = Column(Integer, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False)
|
||||||
|
|
||||||
# Log data
|
# Log data
|
||||||
timestamp = Column(DateTime, default=datetime.utcnow, index=True)
|
timestamp = Column(DateTime, default=utc_now, index=True)
|
||||||
level = Column(String(20), nullable=False) # info, warning, error, critical
|
level = Column(String(20), nullable=False) # info, warning, error, critical
|
||||||
category = Column(String(50)) # system, network, service, hardware
|
category = Column(String(50)) # system, network, service, hardware
|
||||||
message = Column(Text, nullable=False)
|
message = Column(Text, nullable=False)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from app.database import get_db
|
|||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.ai_chat import Conversation, Message, MessageRole
|
from app.models.ai_chat import Conversation, Message, MessageRole
|
||||||
from app.auth import get_current_active_user
|
from app.auth import get_current_active_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/ai-chat", tags=["AI Chat"])
|
router = APIRouter(prefix="/api/ai-chat", tags=["AI Chat"])
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ async def send_message(
|
|||||||
|
|
||||||
# Update conversation
|
# Update conversation
|
||||||
conversation.message_count += 2
|
conversation.message_count += 2
|
||||||
conversation.updated_at = datetime.utcnow()
|
conversation.updated_at = utc_now()
|
||||||
|
|
||||||
if not conversation.title or conversation.title == "New Conversation":
|
if not conversation.title or conversation.title == "New Conversation":
|
||||||
# Auto-generate title from first message
|
# Auto-generate title from first message
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import asyncio
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/health", tags=["health"])
|
router = APIRouter(prefix="/api/health", tags=["health"])
|
||||||
@@ -47,7 +49,7 @@ async def check_api_status(name: str, check_func) -> Dict[str, Any]:
|
|||||||
"name": name,
|
"name": name,
|
||||||
"status": "connected" if result.get("connected") else "not_configured",
|
"status": "connected" if result.get("connected") else "not_configured",
|
||||||
"message": result.get("message", ""),
|
"message": result.get("message", ""),
|
||||||
"last_checked": datetime.utcnow().isoformat(),
|
"last_checked": utc_now().isoformat(),
|
||||||
"configuration": {
|
"configuration": {
|
||||||
k: v for k, v in result.items()
|
k: v for k, v in result.items()
|
||||||
if k.endswith("_configured") or k == "connected"
|
if k.endswith("_configured") or k == "connected"
|
||||||
@@ -60,7 +62,7 @@ async def check_api_status(name: str, check_func) -> Dict[str, Any]:
|
|||||||
"name": name,
|
"name": name,
|
||||||
"status": "error",
|
"status": "error",
|
||||||
"message": f"Health check failed: {str(e)}",
|
"message": f"Health check failed: {str(e)}",
|
||||||
"last_checked": datetime.utcnow().isoformat(),
|
"last_checked": utc_now().isoformat(),
|
||||||
"configuration": {},
|
"configuration": {},
|
||||||
"error": str(e)
|
"error": str(e)
|
||||||
}
|
}
|
||||||
@@ -154,7 +156,7 @@ async def check_all_apis():
|
|||||||
|
|
||||||
return SystemHealthStatus(
|
return SystemHealthStatus(
|
||||||
status=overall_status,
|
status=overall_status,
|
||||||
timestamp=datetime.utcnow().isoformat(),
|
timestamp=utc_now().isoformat(),
|
||||||
total_apis=total_apis,
|
total_apis=total_apis,
|
||||||
connected_apis=connected_count,
|
connected_apis=connected_count,
|
||||||
not_configured_apis=not_configured_count,
|
not_configured_apis=not_configured_count,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from app.auth import (
|
|||||||
)
|
)
|
||||||
from app.services.blockchain import BlockchainService
|
from app.services.blockchain import BlockchainService
|
||||||
from app.services.crypto import wallet_crypto, WalletKeyEncryptionError
|
from app.services.crypto import wallet_crypto, WalletKeyEncryptionError
|
||||||
from datetime import datetime
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/auth", tags=["Authentication"])
|
router = APIRouter(prefix="/api/auth", tags=["Authentication"])
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ async def register(user_data: UserCreate, db: AsyncSession = Depends(get_db)):
|
|||||||
wallet_address=wallet_address,
|
wallet_address=wallet_address,
|
||||||
wallet_private_key=encrypted_private_key,
|
wallet_private_key=encrypted_private_key,
|
||||||
balance=100.0, # Starting bonus
|
balance=100.0, # Starting bonus
|
||||||
created_at=datetime.utcnow()
|
created_at=utc_now()
|
||||||
)
|
)
|
||||||
|
|
||||||
db.add(user)
|
db.add(user)
|
||||||
@@ -131,7 +131,7 @@ async def login(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Update last login
|
# Update last login
|
||||||
user.last_login = datetime.utcnow()
|
user.last_login = utc_now()
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
# Create tokens
|
# Create tokens
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from fastapi import APIRouter, Depends, HTTPException, Query
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from datetime import datetime
|
|
||||||
import httpx
|
import httpx
|
||||||
from urllib.parse import urlparse, quote
|
from urllib.parse import urlparse, quote
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -21,6 +20,7 @@ from ..database import get_db
|
|||||||
from ..auth import get_current_user
|
from ..auth import get_current_user
|
||||||
from ..models import User
|
from ..models import User
|
||||||
from pydantic import BaseModel, HttpUrl
|
from pydantic import BaseModel, HttpUrl
|
||||||
|
from ..utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/browser", tags=["browser"])
|
router = APIRouter(prefix="/api/browser", tags=["browser"])
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ async def add_bookmark(
|
|||||||
"title": bookmark.title,
|
"title": bookmark.title,
|
||||||
"url": bookmark.url,
|
"url": bookmark.url,
|
||||||
"folder": bookmark.folder,
|
"folder": bookmark.folder,
|
||||||
"created_at": datetime.utcnow().isoformat()
|
"created_at": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -208,10 +208,10 @@ async def add_history_entry(
|
|||||||
):
|
):
|
||||||
"""Add a history entry"""
|
"""Add a history entry"""
|
||||||
new_entry = {
|
new_entry = {
|
||||||
"id": hashlib.md5(f"{entry.url}{datetime.utcnow()}".encode()).hexdigest()[:8],
|
"id": hashlib.md5(f"{entry.url}{utc_now()}".encode()).hexdigest()[:8],
|
||||||
"url": entry.url,
|
"url": entry.url,
|
||||||
"title": entry.title,
|
"title": entry.title,
|
||||||
"visited_at": datetime.utcnow().isoformat()
|
"visited_at": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -232,7 +232,7 @@ async def clear_history(
|
|||||||
@router.get("/search")
|
@router.get("/search")
|
||||||
async def web_search(
|
async def web_search(
|
||||||
q: str = Query(..., min_length=1, description="Search query"),
|
q: str = Query(..., min_length=1, description="Search query"),
|
||||||
engine: str = Query("duckduckgo", regex="^(duckduckgo|google|bing)$"),
|
engine: str = Query("duckduckgo", pattern="^(duckduckgo|google|bing)$"),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -397,7 +397,7 @@ async def open_new_tab(
|
|||||||
"""Open a new tab"""
|
"""Open a new tab"""
|
||||||
return {
|
return {
|
||||||
"tab": {
|
"tab": {
|
||||||
"id": hashlib.md5(f"{url}{datetime.utcnow()}".encode()).hexdigest()[:8],
|
"id": hashlib.md5(f"{url}{utc_now()}".encode()).hexdigest()[:8],
|
||||||
"url": url,
|
"url": url,
|
||||||
"title": "Loading...",
|
"title": "Loading...",
|
||||||
"active": True
|
"active": True
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from ..database import get_db
|
|||||||
from ..auth import get_current_user
|
from ..auth import get_current_user
|
||||||
from ..models import User, Device, Email, Post, Video, File, Conversation, Block, Transaction
|
from ..models import User, Device, Email, Post, Video, File, Conversation, Block, Transaction
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from ..utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
|
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
|
||||||
|
|
||||||
@@ -201,7 +202,7 @@ async def get_dashboard_overview(
|
|||||||
},
|
},
|
||||||
"services": services,
|
"services": services,
|
||||||
"system_health": system_health,
|
"system_health": system_health,
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -356,7 +357,7 @@ async def get_recent_activity(
|
|||||||
"icon": "📧",
|
"icon": "📧",
|
||||||
"action": "Received new email",
|
"action": "Received new email",
|
||||||
"description": "Meeting reminder from Sarah",
|
"description": "Meeting reminder from Sarah",
|
||||||
"timestamp": (datetime.utcnow() - timedelta(minutes=5)).isoformat()
|
"timestamp": (utc_now() - timedelta(minutes=5)).isoformat()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
@@ -364,7 +365,7 @@ async def get_recent_activity(
|
|||||||
"icon": "⛓️",
|
"icon": "⛓️",
|
||||||
"action": "Transaction completed",
|
"action": "Transaction completed",
|
||||||
"description": "Sent 10 RoadCoins to wallet abc123",
|
"description": "Sent 10 RoadCoins to wallet abc123",
|
||||||
"timestamp": (datetime.utcnow() - timedelta(minutes=15)).isoformat()
|
"timestamp": (utc_now() - timedelta(minutes=15)).isoformat()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
@@ -372,7 +373,7 @@ async def get_recent_activity(
|
|||||||
"icon": "⛏️",
|
"icon": "⛏️",
|
||||||
"action": "Block mined",
|
"action": "Block mined",
|
||||||
"description": "Mined block #1234, earned 50 RoadCoins",
|
"description": "Mined block #1234, earned 50 RoadCoins",
|
||||||
"timestamp": (datetime.utcnow() - timedelta(hours=1)).isoformat()
|
"timestamp": (utc_now() - timedelta(hours=1)).isoformat()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
@@ -380,7 +381,7 @@ async def get_recent_activity(
|
|||||||
"icon": "🥧",
|
"icon": "🥧",
|
||||||
"action": "Device connected",
|
"action": "Device connected",
|
||||||
"description": "Raspberry Pi 4 - Living Room came online",
|
"description": "Raspberry Pi 4 - Living Room came online",
|
||||||
"timestamp": (datetime.utcnow() - timedelta(hours=2)).isoformat()
|
"timestamp": (utc_now() - timedelta(hours=2)).isoformat()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
@@ -388,7 +389,7 @@ async def get_recent_activity(
|
|||||||
"icon": "🌐",
|
"icon": "🌐",
|
||||||
"action": "New like",
|
"action": "New like",
|
||||||
"description": "Mike liked your post",
|
"description": "Mike liked your post",
|
||||||
"timestamp": (datetime.utcnow() - timedelta(hours=3)).isoformat()
|
"timestamp": (utc_now() - timedelta(hours=3)).isoformat()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from app.database import get_db
|
|||||||
from app.models.device import Device, DeviceMetric, DeviceLog
|
from app.models.device import Device, DeviceMetric, DeviceLog
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.routers.auth import get_current_user
|
from app.routers.auth import get_current_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/devices", tags=["devices"])
|
router = APIRouter(prefix="/api/devices", tags=["devices"])
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ async def update_device(
|
|||||||
if device_data.description is not None:
|
if device_data.description is not None:
|
||||||
device.description = device_data.description
|
device.description = device_data.description
|
||||||
|
|
||||||
device.updated_at = datetime.utcnow()
|
device.updated_at = utc_now()
|
||||||
|
|
||||||
await db.commit()
|
await db.commit()
|
||||||
await db.refresh(device)
|
await db.refresh(device)
|
||||||
@@ -265,7 +266,7 @@ async def device_heartbeat(
|
|||||||
# Update device status
|
# Update device status
|
||||||
device.is_online = True
|
device.is_online = True
|
||||||
device.status = "online"
|
device.status = "online"
|
||||||
device.last_seen = datetime.utcnow()
|
device.last_seen = utc_now()
|
||||||
|
|
||||||
# Update system info if provided
|
# Update system info if provided
|
||||||
if heartbeat_data.ip_address:
|
if heartbeat_data.ip_address:
|
||||||
@@ -308,7 +309,7 @@ async def device_heartbeat(
|
|||||||
# Save metric snapshot
|
# Save metric snapshot
|
||||||
metric = DeviceMetric(
|
metric = DeviceMetric(
|
||||||
device_id=device.id,
|
device_id=device.id,
|
||||||
timestamp=datetime.utcnow(),
|
timestamp=utc_now(),
|
||||||
cpu_usage=heartbeat_data.cpu_usage_percent,
|
cpu_usage=heartbeat_data.cpu_usage_percent,
|
||||||
ram_usage=heartbeat_data.ram_usage_percent,
|
ram_usage=heartbeat_data.ram_usage_percent,
|
||||||
disk_usage=heartbeat_data.disk_usage_percent,
|
disk_usage=heartbeat_data.disk_usage_percent,
|
||||||
@@ -392,7 +393,7 @@ async def ssh_connect(
|
|||||||
"device_id": device_id,
|
"device_id": device_id,
|
||||||
"ip_address": device.ip_address,
|
"ip_address": device.ip_address,
|
||||||
"hostname": device.hostname,
|
"hostname": device.hostname,
|
||||||
"connection_token": f"ssh_token_{device_id}_{datetime.utcnow().timestamp()}",
|
"connection_token": f"ssh_token_{device_id}_{utc_now().timestamp()}",
|
||||||
"status": "connected",
|
"status": "connected",
|
||||||
"message": f"SSH connection established to {device.hostname or device.ip_address}"
|
"message": f"SSH connection established to {device.hostname or device.ip_address}"
|
||||||
}
|
}
|
||||||
@@ -448,7 +449,7 @@ async def ssh_execute_command(
|
|||||||
"command": command_data.command,
|
"command": command_data.command,
|
||||||
"output": output,
|
"output": output,
|
||||||
"exit_code": 0,
|
"exit_code": 0,
|
||||||
"executed_at": datetime.utcnow().isoformat()
|
"executed_at": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -511,7 +512,7 @@ async def deploy_to_device(
|
|||||||
"deploy_path": deploy_config.deploy_path,
|
"deploy_path": deploy_config.deploy_path,
|
||||||
"steps": deployment_steps,
|
"steps": deployment_steps,
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"deployed_at": datetime.utcnow().isoformat(),
|
"deployed_at": utc_now().isoformat(),
|
||||||
"message": "Deployment completed successfully"
|
"message": "Deployment completed successfully"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import httpx
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/discord", tags=["discord"])
|
router = APIRouter(prefix="/api/discord", tags=["discord"])
|
||||||
@@ -304,5 +306,5 @@ async def discord_health_check():
|
|||||||
"service": "discord",
|
"service": "discord",
|
||||||
"status": "operational" if DISCORD_BOT_TOKEN else "not_configured",
|
"status": "operational" if DISCORD_BOT_TOKEN else "not_configured",
|
||||||
"webhook_status": "operational" if DISCORD_WEBHOOK_URL else "not_configured",
|
"webhook_status": "operational" if DISCORD_WEBHOOK_URL else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from app.database import get_db
|
|||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.email import Email, EmailFolder, EmailFolderType
|
from app.models.email import Email, EmailFolder, EmailFolderType
|
||||||
from app.auth import get_current_active_user
|
from app.auth import get_current_active_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/email", tags=["Email"])
|
router = APIRouter(prefix="/api/email", tags=["Email"])
|
||||||
|
|
||||||
@@ -154,7 +155,7 @@ async def send_email(
|
|||||||
bcc=",".join(email_data.bcc) if email_data.bcc else None,
|
bcc=",".join(email_data.bcc) if email_data.bcc else None,
|
||||||
is_read=False,
|
is_read=False,
|
||||||
is_draft=False,
|
is_draft=False,
|
||||||
sent_at=datetime.utcnow()
|
sent_at=utc_now()
|
||||||
)
|
)
|
||||||
|
|
||||||
db.add(email)
|
db.add(email)
|
||||||
@@ -193,7 +194,7 @@ async def get_email(
|
|||||||
# Mark as read if recipient is viewing
|
# Mark as read if recipient is viewing
|
||||||
if email.recipient_id == current_user.id and not email.is_read:
|
if email.recipient_id == current_user.id and not email.is_read:
|
||||||
email.is_read = True
|
email.is_read = True
|
||||||
email.read_at = datetime.utcnow()
|
email.read_at = utc_now()
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
return email
|
return email
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from app.database import get_db
|
|||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.file import File, Folder
|
from app.models.file import File, Folder
|
||||||
from app.auth import get_current_active_user
|
from app.auth import get_current_active_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/files", tags=["Files"])
|
router = APIRouter(prefix="/api/files", tags=["Files"])
|
||||||
|
|
||||||
@@ -217,7 +218,7 @@ async def get_file(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Update last accessed
|
# Update last accessed
|
||||||
file.last_accessed = datetime.utcnow()
|
file.last_accessed = utc_now()
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
return file
|
return file
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import random
|
|||||||
from ..database import get_db
|
from ..database import get_db
|
||||||
from ..auth import get_current_user
|
from ..auth import get_current_user
|
||||||
from ..models import User
|
from ..models import User
|
||||||
|
from ..utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/games", tags=["games"])
|
router = APIRouter(prefix="/api/games", tags=["games"])
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ async def list_cities(
|
|||||||
"money": 45000,
|
"money": 45000,
|
||||||
"level": 5,
|
"level": 5,
|
||||||
"created_at": "2024-01-01T00:00:00Z",
|
"created_at": "2024-01-01T00:00:00Z",
|
||||||
"updated_at": datetime.utcnow().isoformat()
|
"updated_at": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ async def list_commits(
|
|||||||
async def list_pull_requests(
|
async def list_pull_requests(
|
||||||
owner: str,
|
owner: str,
|
||||||
repo: str,
|
repo: str,
|
||||||
state: str = Query("open", regex="^(open|closed|all)$"),
|
state: str = Query("open", pattern="^(open|closed|all)$"),
|
||||||
page: int = Query(1, ge=1),
|
page: int = Query(1, ge=1),
|
||||||
per_page: int = Query(30, ge=1, le=100),
|
per_page: int = Query(30, ge=1, le=100),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
@@ -220,7 +220,7 @@ async def list_pull_requests(
|
|||||||
async def list_issues(
|
async def list_issues(
|
||||||
owner: str,
|
owner: str,
|
||||||
repo: str,
|
repo: str,
|
||||||
state: str = Query("open", regex="^(open|closed|all)$"),
|
state: str = Query("open", pattern="^(open|closed|all)$"),
|
||||||
page: int = Query(1, ge=1),
|
page: int = Query(1, ge=1),
|
||||||
per_page: int = Query(30, ge=1, le=100),
|
per_page: int = Query(30, ge=1, le=100),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class InferenceRequest(BaseModel):
|
|||||||
async def list_models(
|
async def list_models(
|
||||||
search: Optional[str] = Query(None),
|
search: Optional[str] = Query(None),
|
||||||
filter_task: Optional[str] = Query(None, alias="task"),
|
filter_task: Optional[str] = Query(None, alias="task"),
|
||||||
sort: str = Query("downloads", regex="^(downloads|likes|trending)$"),
|
sort: str = Query("downloads", pattern="^(downloads|likes|trending)$"),
|
||||||
limit: int = Query(20, ge=1, le=100),
|
limit: int = Query(20, ge=1, le=100),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
@@ -146,7 +146,7 @@ async def run_inference(
|
|||||||
@router.get("/datasets")
|
@router.get("/datasets")
|
||||||
async def list_datasets(
|
async def list_datasets(
|
||||||
search: Optional[str] = Query(None),
|
search: Optional[str] = Query(None),
|
||||||
sort: str = Query("downloads", regex="^(downloads|likes|trending)$"),
|
sort: str = Query("downloads", pattern="^(downloads|likes|trending)$"),
|
||||||
limit: int = Query(20, ge=1, le=100),
|
limit: int = Query(20, ge=1, le=100),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
@@ -194,7 +194,7 @@ async def get_dataset_info(
|
|||||||
@router.get("/spaces")
|
@router.get("/spaces")
|
||||||
async def list_spaces(
|
async def list_spaces(
|
||||||
search: Optional[str] = Query(None),
|
search: Optional[str] = Query(None),
|
||||||
sort: str = Query("likes", regex="^(likes|trending)$"),
|
sort: str = Query("likes", pattern="^(likes|trending)$"),
|
||||||
limit: int = Query(20, ge=1, le=100),
|
limit: int = Query(20, ge=1, le=100),
|
||||||
current_user: User = Depends(get_current_user)
|
current_user: User = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from app.database import get_db
|
|||||||
from app.models.blockchain import Block, Wallet
|
from app.models.blockchain import Block, Wallet
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.routers.auth import get_current_user
|
from app.routers.auth import get_current_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/miner", tags=["miner"])
|
router = APIRouter(prefix="/api/miner", tags=["miner"])
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ async def get_miner_status(
|
|||||||
"""Get current miner status and performance metrics."""
|
"""Get current miner status and performance metrics."""
|
||||||
uptime_seconds = 0
|
uptime_seconds = 0
|
||||||
if miner_state.started_at:
|
if miner_state.started_at:
|
||||||
uptime_seconds = int((datetime.utcnow() - miner_state.started_at).total_seconds())
|
uptime_seconds = int((utc_now() - miner_state.started_at).total_seconds())
|
||||||
|
|
||||||
# Simulate some variance in hashrate
|
# Simulate some variance in hashrate
|
||||||
current_hashrate = miner_state.hashrate_mhs
|
current_hashrate = miner_state.hashrate_mhs
|
||||||
@@ -242,7 +243,7 @@ async def control_miner(
|
|||||||
raise HTTPException(status_code=400, detail="Miner is already running")
|
raise HTTPException(status_code=400, detail="Miner is already running")
|
||||||
|
|
||||||
miner_state.is_mining = True
|
miner_state.is_mining = True
|
||||||
miner_state.started_at = datetime.utcnow()
|
miner_state.started_at = utc_now()
|
||||||
miner_state.hashrate_mhs = random.uniform(38.0, 45.0) # Simulate hashrate
|
miner_state.hashrate_mhs = random.uniform(38.0, 45.0) # Simulate hashrate
|
||||||
|
|
||||||
if control.pool_url:
|
if control.pool_url:
|
||||||
@@ -268,7 +269,7 @@ async def control_miner(
|
|||||||
miner_state.is_mining = False
|
miner_state.is_mining = False
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
miner_state.is_mining = True
|
miner_state.is_mining = True
|
||||||
miner_state.started_at = datetime.utcnow()
|
miner_state.started_at = utc_now()
|
||||||
miner_state.hashrate_mhs = random.uniform(38.0, 45.0)
|
miner_state.hashrate_mhs = random.uniform(38.0, 45.0)
|
||||||
|
|
||||||
background_tasks.add_task(simulate_mining)
|
background_tasks.add_task(simulate_mining)
|
||||||
@@ -314,5 +315,5 @@ async def get_pool_info(
|
|||||||
"pool_fee": "1%",
|
"pool_fee": "1%",
|
||||||
"min_payout": 10.0,
|
"min_payout": 10.0,
|
||||||
"payment_interval_hours": 24,
|
"payment_interval_hours": 24,
|
||||||
"last_block_found": (datetime.utcnow() - timedelta(minutes=random.randint(5, 120))).isoformat(),
|
"last_block_found": (utc_now() - timedelta(minutes=random.randint(5, 120))).isoformat(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import httpx
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/railway", tags=["railway"])
|
router = APIRouter(prefix="/api/railway", tags=["railway"])
|
||||||
@@ -389,5 +391,5 @@ async def railway_health_check():
|
|||||||
return {
|
return {
|
||||||
"service": "railway",
|
"service": "railway",
|
||||||
"status": "operational" if RAILWAY_TOKEN else "not_configured",
|
"status": "operational" if RAILWAY_TOKEN else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import httpx
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/sentry", tags=["sentry"])
|
router = APIRouter(prefix="/api/sentry", tags=["sentry"])
|
||||||
@@ -376,5 +378,5 @@ async def sentry_health_check():
|
|||||||
return {
|
return {
|
||||||
"service": "sentry",
|
"service": "sentry",
|
||||||
"status": "operational" if SENTRY_AUTH_TOKEN else "not_configured",
|
"status": "operational" if SENTRY_AUTH_TOKEN else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ Provides endpoints for sending messages, managing channels, and interacting with
|
|||||||
from fastapi import APIRouter, HTTPException, status
|
from fastapi import APIRouter, HTTPException, status
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, Optional, Dict, Any
|
from typing import List, Optional, Dict, Any
|
||||||
from datetime import datetime
|
|
||||||
import httpx
|
import httpx
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/slack", tags=["slack"])
|
router = APIRouter(prefix="/api/slack", tags=["slack"])
|
||||||
@@ -277,5 +278,5 @@ async def slack_health_check():
|
|||||||
"service": "slack",
|
"service": "slack",
|
||||||
"status": "operational" if SLACK_BOT_TOKEN else "not_configured",
|
"status": "operational" if SLACK_BOT_TOKEN else "not_configured",
|
||||||
"webhook_status": "operational" if SLACK_WEBHOOK_URL else "not_configured",
|
"webhook_status": "operational" if SLACK_WEBHOOK_URL else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ Stripe is a payment processing platform for online businesses.
|
|||||||
from fastapi import APIRouter, HTTPException, status
|
from fastapi import APIRouter, HTTPException, status
|
||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
from typing import List, Optional, Dict, Any
|
from typing import List, Optional, Dict, Any
|
||||||
from datetime import datetime
|
|
||||||
import httpx
|
import httpx
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/stripe", tags=["stripe"])
|
router = APIRouter(prefix="/api/stripe", tags=["stripe"])
|
||||||
@@ -324,5 +325,5 @@ async def stripe_health_check():
|
|||||||
return {
|
return {
|
||||||
"service": "stripe",
|
"service": "stripe",
|
||||||
"status": "operational" if STRIPE_SECRET_KEY else "not_configured",
|
"status": "operational" if STRIPE_SECRET_KEY else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import base64
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/twilio", tags=["twilio"])
|
router = APIRouter(prefix="/api/twilio", tags=["twilio"])
|
||||||
@@ -255,5 +257,5 @@ async def twilio_health_check():
|
|||||||
return {
|
return {
|
||||||
"service": "twilio",
|
"service": "twilio",
|
||||||
"status": "operational" if (TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN) else "not_configured",
|
"status": "operational" if (TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN) else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import httpx
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/vercel", tags=["vercel"])
|
router = APIRouter(prefix="/api/vercel", tags=["vercel"])
|
||||||
@@ -420,5 +422,5 @@ async def vercel_health_check():
|
|||||||
return {
|
return {
|
||||||
"service": "vercel",
|
"service": "vercel",
|
||||||
"status": "operational" if VERCEL_TOKEN else "not_configured",
|
"status": "operational" if VERCEL_TOKEN else "not_configured",
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": utc_now().isoformat()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from app.database import get_db
|
|||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.video import Video, VideoView, VideoLike
|
from app.models.video import Video, VideoView, VideoLike
|
||||||
from app.auth import get_current_active_user
|
from app.auth import get_current_active_user
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/videos", tags=["Videos"])
|
router = APIRouter(prefix="/api/videos", tags=["Videos"])
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ async def upload_video(
|
|||||||
category=video_data.category,
|
category=video_data.category,
|
||||||
tags=video_data.tags,
|
tags=video_data.tags,
|
||||||
is_public=True,
|
is_public=True,
|
||||||
published_at=datetime.utcnow()
|
published_at=utc_now()
|
||||||
)
|
)
|
||||||
|
|
||||||
db.add(video)
|
db.add(video)
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ from fastapi import APIRouter, Depends, HTTPException, Query
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from ..database import get_db
|
from ..database import get_db
|
||||||
from ..auth import get_current_user
|
from ..auth import get_current_user
|
||||||
from ..models import User, File, Folder
|
from ..models import User, File, Folder
|
||||||
|
from ..utils import utc_now
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/vscode", tags=["vscode"])
|
router = APIRouter(prefix="/api/vscode", tags=["vscode"])
|
||||||
@@ -120,7 +120,7 @@ async def update_file_content(
|
|||||||
raise HTTPException(status_code=404, detail="File not found")
|
raise HTTPException(status_code=404, detail="File not found")
|
||||||
|
|
||||||
# In a real implementation, save to S3 or file system
|
# In a real implementation, save to S3 or file system
|
||||||
file.updated_at = datetime.utcnow()
|
file.updated_at = utc_now()
|
||||||
file.size = len(content.encode('utf-8'))
|
file.size = len(content.encode('utf-8'))
|
||||||
|
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import httpx
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from app.utils import utc_now
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -93,23 +95,23 @@ class APIClient:
|
|||||||
if response.status_code < 500:
|
if response.status_code < 500:
|
||||||
self.status = APIStatus.CONNECTED
|
self.status = APIStatus.CONNECTED
|
||||||
self.error_message = None
|
self.error_message = None
|
||||||
self.last_check = datetime.utcnow()
|
self.last_check = utc_now()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.status = APIStatus.ERROR
|
self.status = APIStatus.ERROR
|
||||||
self.error_message = f"Server error: {response.status_code}"
|
self.error_message = f"Server error: {response.status_code}"
|
||||||
self.last_check = datetime.utcnow()
|
self.last_check = utc_now()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except httpx.TimeoutException:
|
except httpx.TimeoutException:
|
||||||
self.status = APIStatus.ERROR
|
self.status = APIStatus.ERROR
|
||||||
self.error_message = "Connection timeout"
|
self.error_message = "Connection timeout"
|
||||||
self.last_check = datetime.utcnow()
|
self.last_check = utc_now()
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.status = APIStatus.ERROR
|
self.status = APIStatus.ERROR
|
||||||
self.error_message = str(e)
|
self.error_message = str(e)
|
||||||
self.last_check = datetime.utcnow()
|
self.last_check = utc_now()
|
||||||
logger.error(f"Health check failed for {self.name}: {e}")
|
logger.error(f"Health check failed for {self.name}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""Blockchain service"""
|
"""Blockchain service"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select, desc
|
from sqlalchemy import select, desc
|
||||||
@@ -9,6 +8,7 @@ from app.models.blockchain import Block, Transaction, Wallet
|
|||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.services.crypto import wallet_crypto, WalletKeyDecryptionError
|
from app.services.crypto import wallet_crypto, WalletKeyDecryptionError
|
||||||
|
from app.utils import utc_now
|
||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class BlockchainService:
|
|||||||
if existing:
|
if existing:
|
||||||
return existing
|
return existing
|
||||||
|
|
||||||
timestamp = datetime.utcnow()
|
timestamp = utc_now()
|
||||||
genesis_hash = BlockchainService.calculate_hash(0, str(timestamp), "0", [], 0)
|
genesis_hash = BlockchainService.calculate_hash(0, str(timestamp), "0", [], 0)
|
||||||
|
|
||||||
genesis_block = Block(
|
genesis_block = Block(
|
||||||
@@ -69,7 +69,7 @@ class BlockchainService:
|
|||||||
latest_block = await BlockchainService.create_genesis_block(db)
|
latest_block = await BlockchainService.create_genesis_block(db)
|
||||||
|
|
||||||
new_index = latest_block.index + 1
|
new_index = latest_block.index + 1
|
||||||
timestamp = datetime.utcnow()
|
timestamp = utc_now()
|
||||||
previous_hash = latest_block.hash
|
previous_hash = latest_block.hash
|
||||||
difficulty = settings.BLOCKCHAIN_DIFFICULTY
|
difficulty = settings.BLOCKCHAIN_DIFFICULTY
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ class BlockchainService:
|
|||||||
tx.block_index = new_block.index
|
tx.block_index = new_block.index
|
||||||
tx.is_confirmed = True
|
tx.is_confirmed = True
|
||||||
tx.confirmations = 1
|
tx.confirmations = 1
|
||||||
tx.confirmed_at = datetime.utcnow()
|
tx.confirmed_at = utc_now()
|
||||||
|
|
||||||
# Reward miner
|
# Reward miner
|
||||||
user.balance += settings.MINING_REWARD
|
user.balance += settings.MINING_REWARD
|
||||||
@@ -152,7 +152,7 @@ class BlockchainService:
|
|||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
# Generate transaction hash
|
# Generate transaction hash
|
||||||
tx_data = f"{from_address}{to_address}{amount}{datetime.utcnow()}"
|
tx_data = f"{from_address}{to_address}{amount}{utc_now()}"
|
||||||
transaction_hash = hashlib.sha256(tx_data.encode()).hexdigest()
|
transaction_hash = hashlib.sha256(tx_data.encode()).hexdigest()
|
||||||
|
|
||||||
# Sign transaction (simplified)
|
# Sign transaction (simplified)
|
||||||
|
|||||||
4
backend/app/utils/__init__.py
Normal file
4
backend/app/utils/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
"""Utility helpers for the BlackRoad backend."""
|
||||||
|
|
||||||
|
from .datetime import utc_now # noqa: F401
|
||||||
|
|
||||||
9
backend/app/utils/datetime.py
Normal file
9
backend/app/utils/datetime.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
"""Datetime utilities."""
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
def utc_now() -> datetime:
|
||||||
|
"""Return a timezone-aware UTC datetime."""
|
||||||
|
return datetime.now(timezone.utc)
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Miner integration tests"""
|
"""Miner integration tests"""
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
@@ -44,7 +44,7 @@ async def test_miner_stats_respects_wallet(
|
|||||||
"""Ensure /api/miner/stats reports only the authenticated user's blocks."""
|
"""Ensure /api/miner/stats reports only the authenticated user's blocks."""
|
||||||
wallet_address = test_user["wallet_address"]
|
wallet_address = test_user["wallet_address"]
|
||||||
user_id = test_user["id"]
|
user_id = test_user["id"]
|
||||||
now = datetime.utcnow()
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
await _create_block(
|
await _create_block(
|
||||||
db_session,
|
db_session,
|
||||||
@@ -91,7 +91,7 @@ async def test_miner_blocks_endpoint_returns_only_user_blocks(
|
|||||||
"""Ensure /api/miner/blocks only returns the authenticated user's blocks."""
|
"""Ensure /api/miner/blocks only returns the authenticated user's blocks."""
|
||||||
wallet_address = test_user["wallet_address"]
|
wallet_address = test_user["wallet_address"]
|
||||||
user_id = test_user["id"]
|
user_id = test_user["id"]
|
||||||
now = datetime.utcnow()
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
await _create_block(
|
await _create_block(
|
||||||
db_session,
|
db_session,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Tests for VS Code integration endpoints"""
|
"""Tests for VS Code integration endpoints"""
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -11,7 +11,7 @@ from app.models import File
|
|||||||
|
|
||||||
async def _create_file(db: AsyncSession, user_id: int, name: str, file_type: Optional[str]) -> File:
|
async def _create_file(db: AsyncSession, user_id: int, name: str, file_type: Optional[str]) -> File:
|
||||||
"""Helper to create a file record for tests."""
|
"""Helper to create a file record for tests."""
|
||||||
now = datetime.utcnow()
|
now = datetime.now(timezone.utc)
|
||||||
file = File(
|
file = File(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
name=name,
|
name=name,
|
||||||
|
|||||||
Reference in New Issue
Block a user