Initial commit: Sproutly plant tracking app
This commit is contained in:
86
backend/main.py
Normal file
86
backend/main.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from database import SessionLocal
|
||||
from models import Settings, NotificationLog
|
||||
from routers import varieties, batches, dashboard, settings, notifications
|
||||
from routers.notifications import build_daily_summary, send_ntfy
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("sproutly")
|
||||
|
||||
scheduler = AsyncIOScheduler()
|
||||
|
||||
|
||||
async def scheduled_daily_notification():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
s = db.query(Settings).filter(Settings.id == 1).first()
|
||||
if not s or not s.ntfy_topic:
|
||||
logger.info("Daily notification skipped: ntfy not configured")
|
||||
return
|
||||
summary = build_daily_summary(db)
|
||||
ok, detail = await send_ntfy(s, "Sproutly Daily Summary", summary, db)
|
||||
logger.info(f"Daily notification: {detail}")
|
||||
except Exception as e:
|
||||
logger.error(f"Daily notification error: {e}")
|
||||
log = NotificationLog(message="scheduler error", status="failed", error=str(e))
|
||||
db.add(log)
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def get_notification_schedule(db) -> tuple[int, int]:
|
||||
try:
|
||||
s = db.query(Settings).filter(Settings.id == 1).first()
|
||||
if s and s.notification_time:
|
||||
h, m = s.notification_time.split(":")
|
||||
return int(h), int(m)
|
||||
except Exception:
|
||||
pass
|
||||
return 7, 0
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
db = SessionLocal()
|
||||
hour, minute = get_notification_schedule(db)
|
||||
db.close()
|
||||
|
||||
scheduler.add_job(
|
||||
scheduled_daily_notification,
|
||||
CronTrigger(hour=hour, minute=minute),
|
||||
id="daily_summary",
|
||||
replace_existing=True,
|
||||
)
|
||||
scheduler.start()
|
||||
logger.info(f"Scheduler started — daily notification at {hour:02d}:{minute:02d}")
|
||||
yield
|
||||
scheduler.shutdown()
|
||||
|
||||
|
||||
app = FastAPI(title="Sproutly API", version="1.0.0", lifespan=lifespan)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(varieties.router)
|
||||
app.include_router(batches.router)
|
||||
app.include_router(dashboard.router)
|
||||
app.include_router(settings.router)
|
||||
app.include_router(notifications.router)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
return {"status": "ok", "service": "sproutly"}
|
||||
Reference in New Issue
Block a user