From 3819f5c039993f1a87bb3e41d2864f4999f34037 Mon Sep 17 00:00:00 2001 From: Vel-San <13340023+Vel-San@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:52:19 +0100 Subject: [PATCH] feat+ci: Added support for notifications via e-mail and Secrets Leaks for CI --- .github/workflows/check_leaks.yml | 17 ++++++ README.md | 16 ++++++ wbmbot_v2/helpers/constants.py | 3 ++ wbmbot_v2/helpers/notifications.py | 54 ++++++++++++++++++++ wbmbot_v2/helpers/webDriverOperations.py | 19 +++++-- wbmbot_v2/httpsWrapper/httpPageDownloader.py | 2 +- wbmbot_v2/requirements.txt | 1 + 7 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/check_leaks.yml create mode 100644 wbmbot_v2/helpers/notifications.py diff --git a/.github/workflows/check_leaks.yml b/.github/workflows/check_leaks.yml new file mode 100644 index 0000000..c6bbac9 --- /dev/null +++ b/.github/workflows/check_leaks.yml @@ -0,0 +1,17 @@ +name: Secret Detection + +on: + push: + branches: + - main + +jobs: + scan-secrets: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run TruffleHog OSS + uses: trufflesecurity/trufflehog@v3.67.6 \ No newline at end of file diff --git a/README.md b/README.md index 9d81672..b825b16 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ - [Installation](#installation) - [Quick Start](#quick-start) - [Configuration File Example](#configuration-file-example) + - [Notifications (E-mails)](#notifications-e-mails) - [Outputs](#outputs) - [Command-Line Interface](#command-line-interface) - [Docker](#docker) @@ -78,6 +79,18 @@ Alternatively, you can manually create the `configs/wbm_config.json` file with t } ``` +## Notifications (E-mails) + +The bot will be able to send you e-mail notifications (from YOURSELF) once it applies for a flat. + +To do so, you need to export `EMAIL_PASSWORD` to your environment variables. If this variable is not found, no e-mails will be sent. + +**NOTE**: If your email has 2FA (MFA), you need to create an `App Password` from your Outlook online settings. + +**NOTE**: Only `@outlook.com` emails are currently supported + +> export EMAIL_PASSWORD=(password) + ## Outputs You will get outputs such as: @@ -117,6 +130,9 @@ options: ### Run If running for the first time, use `-it` to setup your config, if you already have the config ready in the correct directory, use `-d` + +If you want to send emails as well to yourself as notifications, please add `-e "EMAIL_PASSWORD="` to the command + ```bash docker run -it \ -v /PATH_HERE/offline_viewings:/home/offline_viewings \ diff --git a/wbmbot_v2/helpers/constants.py b/wbmbot_v2/helpers/constants.py index d4ab496..0582420 100644 --- a/wbmbot_v2/helpers/constants.py +++ b/wbmbot_v2/helpers/constants.py @@ -7,6 +7,9 @@ now = dt.datetime.now() now = now.strftime("%Y-%m-%d_%H-%M") +# Retrieve email and password from environment variables +email_password = os.environ.get("EMAIL_PASSWORD") + # WBM Config File Name wbm_config_name = f"{os.getcwd()}/configs/wbm_config.json" diff --git a/wbmbot_v2/helpers/notifications.py b/wbmbot_v2/helpers/notifications.py new file mode 100644 index 0000000..2e16265 --- /dev/null +++ b/wbmbot_v2/helpers/notifications.py @@ -0,0 +1,54 @@ +import os + +import yagmail +from helpers import constants +from logger import wbm_logger + +__appname__ = os.path.splitext(os.path.basename(__file__))[0] +color_me = wbm_logger.ColoredLogger(__appname__) +LOG = color_me.create_logger() + + +def send_email_notification( + email: str, subject: str, body: str, attachment: str = None +): + """Send email notification with optional attachment. + + Args: + email (str): Sender's email address. + subject (str): Email subject. + body (str): Email body. + attachment (str, optional): Path to the attachment file. Defaults to None. + """ + + if not constants.email_password: + LOG.warning( + color_me.yellow( + f"E-mail password not found in the ENV variables! I will not be able to send you e-mails." + ) + ) + return + + try: + # Initialize yagmail SMTP connection + yag = yagmail.SMTP( + email, + constants.email_password, + smtp_starttls=True, + smtp_ssl=False, + smtp_skip_login=False, + host="smtp-mail.outlook.com", + port=587, + ) + + # Send email with attachment if provided + if attachment: + yag.send(to=email, subject=subject, contents=body, attachments=attachment) + else: + yag.send(to=email, subject=subject, contents=body) + + LOG.info(color_me.green(f"Email notification sent successfully to '{email}'")) + except Exception as e: + LOG.error( + color_me.red(f"Failed to send email notification to '{email}' | {str(e)}") + ) diff --git a/wbmbot_v2/helpers/webDriverOperations.py b/wbmbot_v2/helpers/webDriverOperations.py index 14c1de5..c77e305 100644 --- a/wbmbot_v2/helpers/webDriverOperations.py +++ b/wbmbot_v2/helpers/webDriverOperations.py @@ -2,7 +2,7 @@ import time from handlers import flat -from helpers import constants +from helpers import constants, notifications from httpsWrapper import httpPageDownloader as hpd from logger import wbm_logger from selenium.common.exceptions import (NoSuchElementException, @@ -85,9 +85,10 @@ def download_expose_as_pdf(web_driver, flat_name: str): # Log the href attribute of the found button download_link = download_button.get_attribute("href") - hpd.download_pdf_file( + pdf_path = hpd.download_pdf_file( download_link, f"{constants.offline_apartment_path}{constants.now}" ) + return pdf_path def continue_btn(web_driver, flat_element): @@ -338,17 +339,25 @@ def apply_to_flat(web_driver, flat_element, flat_title, user_profile, email): """Apply to the flat using the provided email.""" # Find and click "Ansehen" button on current flat - continue_btn(web_driver, flat_element) + flat_link = continue_btn(web_driver, flat_element) # Fill out application form on current flat using info stored in user object fill_form(web_driver, user_profile, email) # Download as PDF - download_expose_as_pdf(web_driver, flat_title) + pdf_path = download_expose_as_pdf(web_driver, flat_title) # Submit form web_driver.find_element(By.XPATH, "//button[@type='submit']").click() + # Send e-mail + notifications.send_email_notification( + email, + f"[Applied] {flat_title}", + f"Appartment Link: {flat_link}\n\nYour Profile: {user_profile}", + pdf_path, + ) + def process_flats( web_driver, @@ -412,7 +421,7 @@ def process_flats( else: LOG.info( color_me.cyan( - f"Applying to flat: {flat_obj.title} for {email}" + f"Applying to flat: {flat_obj.title} for '{email}'" ) ) apply_to_flat( diff --git a/wbmbot_v2/httpsWrapper/httpPageDownloader.py b/wbmbot_v2/httpsWrapper/httpPageDownloader.py index bfe1139..7fed9d7 100644 --- a/wbmbot_v2/httpsWrapper/httpPageDownloader.py +++ b/wbmbot_v2/httpsWrapper/httpPageDownloader.py @@ -2,7 +2,6 @@ import os import warnings -import requests from pywebcopy import save_webpage from utility import io_operations @@ -63,5 +62,6 @@ def download_pdf_file(url: str, local_dir: str) -> None: if chunk: pdf_file.write(chunk) + return file_path except requests.exceptions.RequestException as e: None diff --git a/wbmbot_v2/requirements.txt b/wbmbot_v2/requirements.txt index 9a02a8f..2971587 100644 --- a/wbmbot_v2/requirements.txt +++ b/wbmbot_v2/requirements.txt @@ -2,3 +2,4 @@ colorama==0.4.6 pywebcopy==7.0.2 selenium==4.17.2 webdriver_manager==4.0.1 +yagmail==0.15.293