diff --git a/amivapi/cron.py b/amivapi/cron.py index b8f57922..3980cd84 100644 --- a/amivapi/cron.py +++ b/amivapi/cron.py @@ -99,7 +99,11 @@ def wrapped(): def schedule_task(time, func, *args): """ Schedule a task at some point in the future. """ - func_s = func_str(func) + if func_str(func) is "remindermail": + item = pickle.load(args) + func_s = "remindermail"+str(item['_id']) + else: + func_s = func_str(func) if func_s not in schedulable_functions: raise NotSchedulable("%s is not schedulable. Did you forget the " @@ -114,7 +118,11 @@ def schedule_task(time, func, *args): def update_scheduled_task(time, func, *args): """ Update a scheduled task that was previously registered. """ - func_s = func_str(func) + if func_str(func) is "remindermail": + item = pickle.load(args) + func_s = "remindermail_"+str(item['_id']) + else: + func_s = func_str(func) if func_s not in schedulable_functions: raise NotSchedulable("%s is not schedulable. Did you forget the " diff --git a/amivapi/events/__init__.py b/amivapi/events/__init__.py index 1850b4c9..0004830b 100644 --- a/amivapi/events/__init__.py +++ b/amivapi/events/__init__.py @@ -13,9 +13,11 @@ from amivapi.events.emails import ( add_confirmed_before_insert, add_confirmed_before_insert_bulk, + add_scheduled_remindermail, + add_scheduled_remindermail_bulk, email_blueprint, send_confirmmail_to_unregistered_users, - send_confirmmail_to_unregistered_users_bulk + send_confirmmail_to_unregistered_users_bulk, ) from amivapi.events.model import eventdomain from amivapi.events.projections import ( @@ -71,4 +73,8 @@ def init_app(app): app.on_inserted_eventsignups += update_waiting_list_after_insert_collection app.on_deleted_item_eventsignups += update_waiting_list_after_delete + # Schedule sending of reminder email at event creation + app.on_inserted_item_events += add_scheduled_remindermail + app.on_inserted_events += add_scheduled_remindermail_bulk + app.register_blueprint(email_blueprint) diff --git a/amivapi/events/emails.py b/amivapi/events/emails.py index 7279eab0..132ac462 100644 --- a/amivapi/events/emails.py +++ b/amivapi/events/emails.py @@ -7,12 +7,14 @@ Needed when external users want to sign up for public events. """ from bson import ObjectId +from datetime import datetime, timedelta from eve.methods.delete import deleteitem_internal from eve.methods.patch import patch_internal from flask import Blueprint, current_app, redirect, url_for from itsdangerous import BadSignature, Signer from amivapi.events.queue import update_waiting_list +from amivapi.cron import schedulable, schedule_task, update_scheduled_task from amivapi.utils import mail email_blueprint = Blueprint('emails', __name__) @@ -59,6 +61,91 @@ def send_confirmmail_to_unregistered_users_bulk(items): send_confirmmail_to_unregistered_users(item) +@schedulable +def remindermail(item): + """Send a reminder email to all participants registered to an event + + Args: + item: The item, which was just inserted into the database + """ + event = item + + # Fetch all the infos needed for the content + if event['title_en'] is not "": + title = event['title_en'] + else: + title = event['title_de'] + + if event['location'] is not "": + location = event['location'] + else: + location = "" + + if event['time_start'] is not None: + date_time_event = event['time_start'].strftime(' %d %B %Y at %-H:%M ') + else: + date_time_event = " NaN " + + fields = { + 'location': location, + 'datetime': date_time_event, + 'title': title + } + + # Populate content text with fetched infos + email_content = current_app.config['REMINDER_EMAIL_TEXT'] % fields + + # Fetch the related eventsignups to get the emails. + eventsignups = current_app.data.find( + 'eventsignups', + **{current_app.config['event']: item['event']}) + + participants_list = list() + for signup in eventsignups: + participants_list.append(signup['email']) + + mail(current_app.config['API_MAIL'], + participants_list, + 'Reminder for AMIV event %s' % title, + email_content) + + +def add_scheduled_remindermail(item): + """ Schedule the sending of a remindermail by [REMINDER_EMAIL_DAYS2EVENT] + days before the event time_start. If no time_start is defined, + then no remindermail will be sent. + """ + if 'time_start' in item: + time_start_event = datetime.strptime(item['time_start'], + '%Y-%m-%dT%H:%M:%SZ') + datetime_reminder = time_start_event - \ + timedelta( + days=int(current_app.config['REMINDER_EMAIL_DAYS2EVENT'])) + schedule_task(datetime_reminder, + remindermail, + item) + + +def add_scheduled_remindermail_bulk(items): + for item in items: + add_scheduled_remindermail(item) + + +def update_scheduled_remindermail(item): + """ Update the schedule of a remindermal to fit updated time_start + or other infos of the event + """ + if 'time_start' in item: + time_start_event = datetime.strptime(item['time_start'], + '%Y-%m-%dT%H:%M:%SZ') + datetime_reminder = time_start_event - \ + timedelta( + days=int(current_app.config['REMINDER_EMAIL_DAYS2EVENT'])) + update_scheduled_task(datetime_reminder, + remindermail, + item) + + def add_confirmed_before_insert(item): """Add the confirmed field to a event signup before it is inserted to the database. We accept all registered users instantly, others need to click the