From 3f96961e35ecf8883f5779c8903b4cdc0be2c6e8 Mon Sep 17 00:00:00 2001 From: hay-kot Date: Sun, 14 Mar 2021 18:44:02 -0800 Subject: [PATCH] multi group supporot for job scheduler --- mealie/routes/setting_routes.py | 11 +++- mealie/schema/meal.py | 2 +- mealie/schema/scheduler.py | 10 +++ mealie/services/meal_services.py | 6 +- mealie/services/scheduler/scheduled_jobs.py | 73 +++++++++++++++------ mealie/utils/post_webhooks.py | 34 ++++++---- 6 files changed, 100 insertions(+), 36 deletions(-) create mode 100644 mealie/schema/scheduler.py diff --git a/mealie/routes/setting_routes.py b/mealie/routes/setting_routes.py index 51317d283..e8fc889e4 100644 --- a/mealie/routes/setting_routes.py +++ b/mealie/routes/setting_routes.py @@ -3,9 +3,12 @@ from db.db_setup import generate_session from fastapi import APIRouter, Depends from schema.settings import SiteSettings from schema.snackbar import SnackResponse +from schema.user import GroupInDB, UserInDB from sqlalchemy.orm.session import Session from utils.post_webhooks import post_webhooks +from routes.deps import manager + router = APIRouter(prefix="/api/site-settings", tags=["Settings"]) @@ -27,7 +30,11 @@ def update_settings(data: SiteSettings, session: Session = Depends(generate_sess @router.post("/webhooks/test") -def test_webhooks(): +def test_webhooks( + current_user: UserInDB = Depends(manager), + session: Session = Depends(generate_session), +): """ Run the function to test your webhooks """ + group_entry: GroupInDB = db.groups.get(session, current_user.group, "name") - return post_webhooks() + return post_webhooks(group_entry.id, session) diff --git a/mealie/schema/meal.py b/mealie/schema/meal.py index 831993db5..a875f04f2 100644 --- a/mealie/schema/meal.py +++ b/mealie/schema/meal.py @@ -27,7 +27,7 @@ class MealPlanIn(BaseModel): meals: List[MealIn] @validator("endDate") - def endDate_after_startDate(cls, v, values, **kwargs): + def endDate_after_startDate(v, values, config, field): if "startDate" in values and v < values["startDate"]: raise ValueError("EndDate should be greater than StartDate") return v diff --git a/mealie/schema/scheduler.py b/mealie/schema/scheduler.py new file mode 100644 index 000000000..12f8dee4f --- /dev/null +++ b/mealie/schema/scheduler.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel + + +class WebhookJob(BaseModel): + webhook_urls: list[str] = [] + webhook_time: str = "00:00" + webhook_enable: bool + + class Config: + orm_mode = True diff --git a/mealie/services/meal_services.py b/mealie/services/meal_services.py index ea4d83001..2d2851089 100644 --- a/mealie/services/meal_services.py +++ b/mealie/services/meal_services.py @@ -1,7 +1,7 @@ from datetime import date, timedelta from db.database import db -from schema.meal import MealIn, MealOut, MealPlanIn, MealPlanProcessed +from schema.meal import MealIn, MealOut, MealPlanIn, MealPlanInDB, MealPlanProcessed from schema.recipe import Recipe from sqlalchemy.orm.session import Session @@ -38,9 +38,9 @@ def process_meals(session: Session, meal_plan_base: MealPlanIn) -> MealPlanProce def get_todays_meal(session): - meal_plan = db.meals.get_all(session, limit=1, order_by="startDate") + meal_plan: MealPlanInDB = db.groups.get(session, limit=1, order_by="startDate") - for meal in meal_plan: + for meal in meal_plan.meals: meal: MealOut if meal.date == date.today(): return meal.slug diff --git a/mealie/services/scheduler/scheduled_jobs.py b/mealie/services/scheduler/scheduled_jobs.py index 36b630a4f..c8d6cdaf5 100644 --- a/mealie/services/scheduler/scheduled_jobs.py +++ b/mealie/services/scheduler/scheduled_jobs.py @@ -1,32 +1,35 @@ from apscheduler.schedulers.background import BackgroundScheduler +from db.database import db from db.db_setup import create_session +from fastapi.logger import logger +from schema.user import GroupInDB from services.backups.exports import auto_backup_job from services.scheduler.global_scheduler import scheduler from services.scheduler.scheduler_utils import Cron, cron_parser -from fastapi.logger import logger -from schema.settings import SiteSettings -from db.database import db from utils.post_webhooks import post_webhooks + # TODO Fix Scheduler -@scheduler.scheduled_job(trigger="interval", minutes=15) +@scheduler.scheduled_job(trigger="interval", minutes=30) def update_webhook_schedule(): """ - A scheduled background job that runs every 15 minutes to + A scheduled background job that runs every 30 minutes to poll the database for changes and reschedule the webhook time """ session = create_session() - settings = db.settings.get(session, "main") - settings = SiteSettings(**settings) - time = cron_parser(settings.webhooks.webhookTime) - job = JOB_STORE.get("webhooks") + all_groups: list[GroupInDB] = db.groups.get_all(session) - scheduler.reschedule_job( - job.scheduled_task.id, - trigger="cron", - hour=time.hours, - minute=time.minutes, - ) + for group in all_groups: + + time = cron_parser(group.webhook_time) + job = JOB_STORE.get(group.name) + + scheduler.reschedule_job( + job.scheduled_task.id, + trigger="cron", + hour=time.hours, + minute=time.minutes, + ) session.close() logger.info(scheduler.print_jobs()) @@ -34,7 +37,12 @@ def update_webhook_schedule(): class ScheduledFunction: def __init__( - self, scheduler: BackgroundScheduler, function, cron: Cron, name: str + self, + scheduler: BackgroundScheduler, + function, + cron: Cron, + name: str, + args: list = None, ) -> None: self.scheduled_task = scheduler.add_job( function, @@ -44,6 +52,7 @@ class ScheduledFunction: minute=cron.minutes, max_instances=1, replace_existing=True, + args=args, ) logger.info("New Function Scheduled") @@ -56,9 +65,35 @@ JOB_STORE = { "backup_job": ScheduledFunction( scheduler, auto_backup_job, Cron(hours=00, minutes=00), "backups" ), - "webhooks": ScheduledFunction( - scheduler, post_webhooks, Cron(hours=00, minutes=00), "webhooks" - ), } + +def init_webhook_schedule(scheduler, job_store: dict): + session = create_session() + all_groups: list[GroupInDB] = db.groups.get_all(session) + + for group in all_groups: + cron = cron_parser(group.webhook_time) + + job_store.update( + { + group.name: ScheduledFunction( + scheduler, + post_webhooks, + cron=cron, + name=group.name, + args=[group.id], + ) + } + ) + + session.close() + logger.info("Init Webhook Schedule \n", scheduler.print_jobs()) + + return job_store + + +JOB_STORE = init_webhook_schedule(scheduler=scheduler, job_store=JOB_STORE) + + scheduler.start() diff --git a/mealie/utils/post_webhooks.py b/mealie/utils/post_webhooks.py index d424d3263..fdf4d6482 100644 --- a/mealie/utils/post_webhooks.py +++ b/mealie/utils/post_webhooks.py @@ -1,23 +1,35 @@ import json +from datetime import date import requests from db.database import db from db.db_setup import create_session -from schema.settings import SiteSettings -from services.meal_services import get_todays_meal +from schema.meal import MealOut, MealPlanInDB +from schema.user import GroupInDB +from sqlalchemy.orm.session import Session -def post_webhooks(): - session = create_session() - all_settings = db.get(session, 1) - all_settings = SiteSettings(**all_settings) +def post_webhooks(group: int, session: Session = None): + session = session if session else create_session() + group_settings: GroupInDB = db.groups.get(session, group) + + if group_settings.webhook_enable: + today_slug = None + + for mealplan in group_settings.mealplans: + mealplan: MealPlanInDB + for meal in mealplan.meals: + meal: MealOut + if meal.date == date.today(): + today_slug = meal.slug + break + + if not today_slug: + return - if all_settings.webhooks.enabled: - today_slug = get_todays_meal(session) todays_meal = db.recipes.get(session, today_slug) - urls = all_settings.webhooks.webhookURLs - for url in urls: - requests.post(url, json.dumps(todays_meal, default=str)) + for url in group_settings.webhook_urls: + requests.post(url, json=todays_meal.json()) session.close()