From 23bbee82713bf3171dad27fa503051d3105a4603 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 13 Jun 2017 18:19:16 +0200 Subject: [PATCH] Adds basic email notifications when new flats have been found (fixes #47). --- flatisfy/cmds.py | 9 +++++ flatisfy/config.py | 19 +++++++++++ flatisfy/email.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 flatisfy/email.py diff --git a/flatisfy/cmds.py b/flatisfy/cmds.py index 7683a58..d158f69 100644 --- a/flatisfy/cmds.py +++ b/flatisfy/cmds.py @@ -9,6 +9,7 @@ import logging import flatisfy.filters from flatisfy import database +from flatisfy import email from flatisfy.models import flat as flat_model from flatisfy.models import postal_code as postal_code_model from flatisfy.models import public_transport as public_transport_model @@ -143,6 +144,8 @@ def import_and_filter(config, load_from_db=False): # Create database connection get_session = database.init_db(config["database"], config["search_index"]) + new_flats = [] + LOGGER.info("Merging fetched flats in database...") # Flatten the flats_by_status dict flatten_flats_by_status = collections.defaultdict(list) @@ -182,8 +185,14 @@ def import_and_filter(config, load_from_db=False): # just set the status field without worrying for flat in flats_objects.values(): flat.status = getattr(flat_model.FlatStatus, status) + if flat.status == flat_model.FlatStatus.new: + new_flats.append(flat) session.add_all(flats_objects.values()) + + if config["send_email"]: + email.send_notification(config, new_flats) + LOGGER.info("Done!") diff --git a/flatisfy/config.py b/flatisfy/config.py index 84c7a77..b7797da 100644 --- a/flatisfy/config.py +++ b/flatisfy/config.py @@ -62,6 +62,15 @@ DEFAULT_CONFIG = { "webserver": None, # List of Weboob backends to use (default to any backend available) "backends": None, + # Should email notifications be sent? + "send_email": False, + "smtp_server": 'localhost', + "smtp_port": 25, + "smtp_from": "noreply@flatisfy.org", + "smtp_to": [], + # The web site url, to be used in email notifications. (doesn't matter + # whether the trailing slash is present or not) + "website_url": "http://127.0.0.1:8080" } LOGGER = logging.getLogger(__name__) @@ -149,6 +158,11 @@ def validate_config(config): assert config["webserver"] is None or isinstance(config["webserver"], str) # noqa: E501 assert config["backends"] is None or isinstance(config["backends"], list) # noqa: E501 + assert isinstance(config["send_email"], bool) + assert config["smtp_server"] is None or isinstance(config["smtp_server"], (str, unicode)) + assert config["smtp_port"] is None or isinstance(config["smtp_port"], int) + assert config["smtp_to"] is None or isinstance(config["smtp_to"], list) + return True except (AssertionError, KeyError): _, _, exc_traceback = sys.exc_info() @@ -242,6 +256,11 @@ def load_config(args=None): if k in constraints_filter } + # Sanitize website url + if config_data["website_url"] is not None: + if config_data["website_url"][-1] != '/': + config_data["website_url"] += '/' + config_validation = validate_config(config_data) if config_validation is True: LOGGER.info("Config has been fully initialized.") diff --git a/flatisfy/email.py b/flatisfy/email.py new file mode 100644 index 0000000..7bb01b8 --- /dev/null +++ b/flatisfy/email.py @@ -0,0 +1,82 @@ +# coding: utf-8 + +""" +Email notifications. +""" + +from __future__ import absolute_import, print_function, unicode_literals +import smtplib + +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +def send_email(server, port, subject, _from, to, txt, html): + if len(to) == 0: + LOGGER.warn("No recipients for the email notifications, aborting.") + return + + server = smtplib.SMTP(server, port) + + msg = MIMEMultipart('alternative') + msg['Subject'] = subject + msg['From'] = _from + msg['To'] = ', '.join(to) + + msg.attach(MIMEText(txt, 'plain', 'utf-8')) + msg.attach(MIMEText(html, 'html', 'utf-8')) + + server.sendmail(_from, to, msg.as_string()) + server.quit() + +def send_notification(config, flats): + # Don't send an email if there are no new flats. + if len(flats) == 0: + return + + txt = u'Hello dear user,\n\nThe following new flats have been found:\n\n' + html = """ + + + +

Hello dear user!

+

The following new flats have been found: + +

" + + SIGNATURE = u"\nHope you'll find what you were looking for.\n\nBye!\nFlatisfy" + txt += SIGNATURE + html += SIGNATURE.replace('\n', '
') + + html += """

+ + """ + + send_email(config["smtp_server"], + config["smtp_port"], + "New flats found!", + config["smtp_from"], + config["smtp_to"], + txt, + html)