diff --git a/.dockerignore b/.dockerignore index a7ff473..1a3a766 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,4 @@ .env bin lib +include diff --git a/Dockerfile b/Dockerfile index ce0950f..f812f0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,4 @@ RUN pip3 install -r requirements.txt COPY . . -CMD ["python", "-m", "matrix_bot_praying_times"] +ENTRYPOINT ["/bot/entrypoint.sh"] diff --git a/alembic/env.py b/alembic/env.py index 0d79cb1..f2ba3a7 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -6,6 +6,8 @@ from sqlalchemy import pool from alembic import context +from dotenv import load_dotenv +load_dotenv() # this is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/alembic/versions/c2bcd940c9e8_add_current_reminder_date.py b/alembic/versions/c2bcd940c9e8_add_current_reminder_date.py new file mode 100644 index 0000000..a8db828 --- /dev/null +++ b/alembic/versions/c2bcd940c9e8_add_current_reminder_date.py @@ -0,0 +1,30 @@ +"""Add current reminder date + +Revision ID: c2bcd940c9e8 +Revises: 12669d9a145b +Create Date: 2024-06-16 22:21:27.188128 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'c2bcd940c9e8' +down_revision: Union[str, None] = '12669d9a145b' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('user', sa.Column('current_reminder_date', sa.Date(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('user', 'current_reminder_date') + # ### end Alembic commands ### diff --git a/compose.yml b/compose.yml index e2e4fbb..c4e98b5 100644 --- a/compose.yml +++ b/compose.yml @@ -8,5 +8,6 @@ services: - BOT_HOMESERVER - BOT_USERNAME - BOT_PASSWORD + - DB_URI volumes: - ./data/:/bot/data diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..d9e2035 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh +alembic upgrade head +python -m matrix_bot_praying_times diff --git a/matrix_bot_praying_times/__main__.py b/matrix_bot_praying_times/__main__.py index 361253d..017e00d 100644 --- a/matrix_bot_praying_times/__main__.py +++ b/matrix_bot_praying_times/__main__.py @@ -5,6 +5,7 @@ import asyncio import pytz from typing import Dict import os +import logging from dotenv import load_dotenv from .models.user import User @@ -29,6 +30,20 @@ engine = create_engine(os.getenv("DB_URI")) Session = sessionmaker(bind=engine) session = Session() +logging.basicConfig(level=logging.INFO) + + +@bot.listener.on_startup +async def initial_schedule(room_id): + logging.info("starting praying times bot") + users = session.query(User).filter(User.location != "", User.reminder_time_in_minutes is not None).all() + for user in users: + logging.info("scheduling initial reminder for {}".format(user.username)) + # reset last reminder schedule time + user.current_reminder_date = None + session.add(user) + session.commit() + schedule_reminder(user.username) @bot.listener.on_message_event @@ -72,7 +87,7 @@ async def usage(room, message) -> None: - **!set-reminder** where X is the number of minutes you want to receive the reminder before praying """ - if match.is_not_from_this_bot() and not match.prefix(): + if match.is_not_from_this_bot() and not match.prefix() and room.room_id: await bot.api.send_markdown_message(room.room_id, response) @@ -113,8 +128,10 @@ async def set_reminder(room, message) -> None: response = "You did not set your location yet." await bot.api.send_markdown_message(room.room_id, response) else: - user.reminder_time_in_minues = minutes + user.reminder_time_in_minutes = minutes user.room_id = room.room_id + session.add(user) + session.commit() response = "Your reminder was set to {} minutes before praying.".format(minutes) schedule_reminder(username) await bot.api.send_markdown_message(room.room_id, response) @@ -132,22 +149,30 @@ def get_praying_times(date: datetime.date, username) -> Dict[str, str]: def schedule_reminder(username) -> None: + logging.info("scheduling reminder for {}".format(username)) now = datetime.datetime.now(datetime.UTC) user = session.query(User).filter_by(username=username).one_or_none() - # as a workaround until it's finished schedule the next 7 days - for i in range(7): - times = get_praying_times(datetime.date.today() + datetime.timedelta(days=i), username) - for prayer, time in times.items(): - praying_time = datetime.datetime.fromisoformat(time) - if praying_time > now: - seconds = int((praying_time - now).total_seconds()) - message = "{} is at {}".format(prayer, praying_time.strftime("%H:%M")) - asyncio.ensure_future(remind(username, message, seconds - user.reminder_time_in_minues * 60)) + user.current_reminder_date = datetime.date.today() + session.add(user) + session.commit() + times = get_praying_times(datetime.date.today(), username) + for prayer, time in times.items(): + praying_time = datetime.datetime.fromisoformat(time) + if praying_time > now: + # schedule praying times but skip the ones which already have been passed today + seconds = int((praying_time - now).total_seconds()) + message = "{} is at {}".format(prayer, praying_time.strftime("%H:%M")) + logging.info("scheduling reminder for {} with message: {}".format(username, message)) + asyncio.ensure_future(remind(username, message, seconds - user.reminder_time_in_minutes * 60)) + # save date of last schedule for user async def remind(username, message, seconds) -> None: await asyncio.sleep(seconds) user = session.query(User).filter_by(username=username).one_or_none() + # check if a new reminder has to be scheduled + if user.current_reminder_date < datetime.date.today(): + schedule_reminder(user.username) await bot.api.send_markdown_message(user.room_id, message) diff --git a/matrix_bot_praying_times/models/user.py b/matrix_bot_praying_times/models/user.py index a7acfdd..fc1fdcc 100644 --- a/matrix_bot_praying_times/models/user.py +++ b/matrix_bot_praying_times/models/user.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, String, Integer +from sqlalchemy import Column, String, Integer, Date from ..db import Base @@ -11,3 +11,4 @@ class User(Base): location = Column(String) room_id = Column(String) reminder_time_in_minutes = Column(Integer) + current_reminder_date = Column(Date)