diff --git a/.github/workflows/README.md b/.github/workflows/README.md deleted file mode 100644 index 33b01b656..000000000 --- a/.github/workflows/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Instructions for Github Actions setup - -## Idea -We can schedule to run a script on the GitHub Actions servers. - -## Instructions -1. Create GitHub Actions secrets below: - - CREDENTIALS - See the README.md in the project root directory for more info about the contents. - - RECEIVERS - Same as above. - - FAIL_MAIL_USERNAME - Gmail alert address for the workflow fails alerts. - - FAIL_MAIL_PASSWORD - Gmail password for the above. User is advised to check - [Sign in with App Passwords](https://support.google.com/accounts/answer/185833?p=InvalidSecondFactor&visit_id=637593941018469305-643690772&rd=1) - -2. Manually run Github Action workflow. It is normal if the Download artifacts from the last workflow -step fails because there is no workflows beforehand. - -3. Thats it. The Github Action workflow should run as scheduled and the Python script should be -executed once per day. diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml deleted file mode 100644 index fb8381c1e..000000000 --- a/.github/workflows/unit_tests.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Unit tests - -on: - # Trigger the workflow on push or pull request, - # but only for the master branch - push: - branches: - - master - pull_request: - branches: - - master - # Also trigger on page_build, as well as release created events - page_build: - release: - types: # This configuration does not affect the page_build event above - - created - workflow_dispatch: - -jobs: - run: - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f - # Fix Python version. Probably works with other versions. - - uses: actions/setup-python@dc73133d4da04e56a135ae2246682783cc7c7cb6 - with: - python-version: '3.8.5' - - - name: Install requirements - run: make init - - - name: Run Unit tests - run: make test diff --git a/.github/workflows/weather_check.yml b/.github/workflows/weather_check.yml index 3c913b61a..18323cdf9 100644 --- a/.github/workflows/weather_check.yml +++ b/.github/workflows/weather_check.yml @@ -2,58 +2,28 @@ name: Weather check on: schedule: - # Run every 25th minute - - cron: '*/25 * * * *' + # Run every day at 3:00 UTC (5:00 CEST) + - cron: '0 3 * * *' workflow_dispatch: jobs: run: runs-on: ubuntu-20.04 - # if there is no artifact to download - continue-on-error: true env: ACTION_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f - - # Fix Python version. Probably works with other versions. - uses: actions/setup-python@dc73133d4da04e56a135ae2246682783cc7c7cb6 with: python-version: '3.8.5' - # This step is using CREDENTIALS and RECEIVERS Github Actions secrets. - # View the README.md file for instructions about secrets contents. - - name: Create Credentials and Receivers files + - name: Setup environment variables env: - CREDENTIALS: ${{ secrets.CREDENTIALS }} + SENDER_EMAIL: ${{ secrets.SENDER_EMAIL }} + SENDER_PASSWORD: ${{ secrets.SENDER_PASSWORD }} RECEIVERS: ${{ secrets.RECEIVERS }} - run: | - echo "$CREDENTIALS" > credentials/credentials.yaml - echo "$RECEIVERS" > credentials/receivers.txt - - - name: Install requirements - run: make init - # if Download exec timetable step failed still run the script - name: Run main application - run: make run - - # This step uses Github Actions secrets FAIL_MAIL_USERNAME and FAIL_MAIL_PASSWORD - # which are Gmail username and password respectively. - #- name: Send an email alert if there are any failed steps - # if: failure() - # uses: dawidd6/action-send-mail@db36373cbed0fba7d5e12c338b580277550bdba1 - # with: - # server_address: smtp.gmail.com - # server_port: 465 - # username: ${{ secrets.FAIL_MAIL_USERNAME }} - # password: ${{ secrets.FAIL_MAIL_PASSWORD }} - # subject: rain_alert app run ${{ github.run_number }} failed - # # send to itself - # to: ${{ secrets.FAIL_MAIL_USERNAME }} - # from: https://github.com/IvanVnucec/rain_alert - # body: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - # # TODO: Add the workflow logs to the attachments - # #attachments: + run: python3 main.py diff --git a/.gitignore b/.gitignore index 6a89d363d..7b62f12d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,2 @@ -venv __pycache__ -credentials/credentials.yaml -credentials/receivers.txt -logs/exec_timetable.json.aes +.vscode \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index b74b6b081..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Current File", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/main.py", - "console": "integratedTerminal" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0cffe0616..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "python.formatting.provider": "autopep8", - "python.formatting.autopep8Args": ["--max-line-length", "80"], - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.linting.lintOnSave": true, - "python.pythonPath": "venv/bin/python3.8", -} \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 6211ab843..000000000 --- a/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -run: init - . venv/bin/activate; python main.py - -PHONY: init -init: venv - -PHONY: test -test: venv - . venv/bin/activate; python -m unittest -v - -PHONY: clean -clean: - rm -rf venv - find -iname "*.pyc" -delete - -.PHONY: list -list: - @echo "run - Run app," - @echo "init - Install all the dependancies with virtualenv," - @echo "test - Run unit tests," - @echo "clean - Clean virtualenv directory." - @echo "list - List all the makefile commands." - -venv: venv/touchfile - -venv/touchfile: requirements.txt - python3 -m pip install virtualenv - test -d venv || python -m virtualenv venv - . venv/bin/activate; pip install -Ur requirements.txt - touch venv/touchfile diff --git a/README.md b/README.md index a68dbef42..4b3a2f26d 100644 --- a/README.md +++ b/README.md @@ -1,113 +1,22 @@ +# rain_alert + [![App running](https://github.com/IvanVnucec/rain_alert/actions/workflows/weather_check.yml/badge.svg?branch=master&event=schedule)](https://github.com/IvanVnucec/rain_alert/actions/workflows/weather_check.yml) -# rain_alert -You will not forget your umbrella anymore. :umbrella: +You will not forget your :umbrella: anymore. ## About -Check every morning at 5 AM local time if it will be raining that day, if yes -send an email with forecast message like this: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hour [h]Probability [%]
60
70
80
90
1010
1122
1235
1360
1486
15100
16100
17100
18100
1972
2036
215
220
230
- + +Check the weather at 5AM Zagreb time and send an email if it will rain today. ## Get started -0. Create Gmail account and enable the Less secure app access and also create an OpenWeather API Key. -1. Create `credentials/credentials.yaml` file and put Gmail and OpenWeather credentials from step 0. -``` -senderEmail: -senderPassword: -openWeatherApiKey: -``` -2. Create `credentials/receivers.txt` file put in email subscribers. For example: -``` -example1@email.com, Zagreb -example2@email.com, Berlin -example3@email.com, Milwaukee -example4@email.com, Mobile Alabama -example5@email.com, Nashville Tennessee -example6@email.com, Nashville Indiana -``` -3. Run the app using Makefile as `make run` -4. (Recommended) You can schedule the script to run on GitHub servers like we did in -[our GitHub Actions CI workflow](https://github.com/IvanVnucec/rain_alert/blob/master/.github/workflows/weather_check.yml). -See the [Instructions](./.github/workflows/README.md) for more info. + +1. Create Gmail account and enable the Less secure app access. +2. Add the following environment variables to GitHub actions: + - `SENDER_EMAIL` - sender Gmail email + - `SENDER_PASSWORD` - Gmail email password + - `RECEIVERS` - list of email addresses to send the alert to +3. Run the GitHub Action workflow manually to check if everything is working. ## License + [MIT](LICENSE.md) diff --git a/credentials/.gitkeep b/credentials/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/exec_tracker.py b/exec_tracker.py deleted file mode 100644 index 3797d8e75..000000000 --- a/exec_tracker.py +++ /dev/null @@ -1,100 +0,0 @@ -""" -Because GitHub actions sometimes runs in irregular intervals -caused by high server demand and not strictly once every hour, -we will track and store latest execution times. If the script -was not executed that morning at 5 AM local time, GitHub Actions -would run it sometimes later that day. -If the script is ran more than once per day, it would check every -time if it was already executed. If yes then skip. -Execution times are being saved in exec_timetable.json file. -Before closing execution timetable file it is being encrypted -with AES into exec_timetable.json.aes file with some password. -Be sure that the password is kept as a secret. -""" - -from datetime import datetime -import json -from os import path, remove, system -from pyAesCrypt import encryptFile, decryptFile -from utils import debug, get_github_actions_url - -DATE_FORMAT = '%m/%d/%Y, %H:%M:%S' -TIMETABLE_PATH = path.abspath(path.join('logs', 'exec_timetable.json')) -TIMETABLE_PATH_ENCRYPTED = TIMETABLE_PATH + '.aes' -BUFFERSIZE = 64 * 1024 - - -class ExecTracker: - def __init__(self, password): - self.timetable_modified = False - self.__password = password - - if path.exists(TIMETABLE_PATH_ENCRYPTED): - debug('Found exec timetable file') - decryptFile(TIMETABLE_PATH_ENCRYPTED, TIMETABLE_PATH, self.__password, BUFFERSIZE) - else: - debug('Did not found exec timetable file. Creating new.') - self.timetable = open(TIMETABLE_PATH, 'w') - self.timetable.write('{}') - self.timetable.close() - - self.timetable = open(TIMETABLE_PATH, 'r') - self.exec_times = json.load(self.timetable) - debug(self.exec_times) - self.timetable.close() - - def close(self): - if self.timetable_modified: - debug('Timetable is modified. Saving now.') - self.timetable = open(TIMETABLE_PATH, 'r+') - json.dump(self.exec_times, self.timetable, indent=4) - self.timetable.close() - else: - debug('Timetable was not modified.') - - debug('Showing execution timetable before encryption.') - debug(self.exec_times) - - debug('Encrypting file.') - if path.exists(TIMETABLE_PATH_ENCRYPTED): - remove(TIMETABLE_PATH_ENCRYPTED) - encryptFile(TIMETABLE_PATH, TIMETABLE_PATH_ENCRYPTED, self.__password, BUFFERSIZE) - - debug('Deleting original file.') - remove(TIMETABLE_PATH) - - - def script_executed_today(self, location): - if location.name in self.exec_times: - local_time = location.get_local_time() - - for exec_time_str in self.exec_times[location.name]: - exec_time = datetime.strptime(exec_time_str, DATE_FORMAT) - - if exec_time.date() == local_time.date(): - return True - - return False - - def mark_exec_time(self, location): - self.timetable_modified = True - - location_name = location.name - local_time_str = location.get_local_time().strftime(DATE_FORMAT) - - if location_name in self.exec_times: - self.exec_times[location_name].append(local_time_str) - else: - self.exec_times[location_name] = [local_time_str] - - def is_timetable_modified(self): - return self.timetable_modified - - def add_and_commit_timetable(self): - system('git config --global user.email "you@example.com"') - system('git config --global user.name "GitHub Actions"') - debug('git add encrypted timetable') - system(f'git add {TIMETABLE_PATH_ENCRYPTED}') - debug('git commit encrypted timetable') - system(f"git commit -m 'update timetable {get_github_actions_url()}'") - system("git push") diff --git a/forecast.py b/forecast.py deleted file mode 100644 index 05633ca38..000000000 --- a/forecast.py +++ /dev/null @@ -1,140 +0,0 @@ -from open_weather import OpenWeather -from utils import debug, get_github_actions_url - -DAY_START_HOUR = 6 -DAY_END_HOUR = 23 -RAIN_PROB_TRESHOLD = 0.5 - - - -class Forecast: - def __init__(self, location): - self.location = location - self.forecastToday = self.get_forecast_today() - - def get_forecast_today(self): - forecastToday = [] - - lat, lon = self.location.get_latitude_longitude() - - ow = OpenWeather() - forecasts = ow.get_forecast(lat, lon) - localDate = self.location.get_local_time().date() - - for forecast in forecasts: - forecastDate = forecast['t'].date() - forecastHour = forecast['t'].hour - probability = forecast['p'] - - sameDayForecast = localDate == forecastDate - inTimeRange = forecastHour >= DAY_START_HOUR and forecastHour <= DAY_END_HOUR - highRainProbability = probability >= RAIN_PROB_TRESHOLD - - if sameDayForecast and inTimeRange: - forecastToday.append( - {'b': highRainProbability, 'p': probability, 'h': forecastHour}) - - return forecastToday - - def get_rain_start_hour(self): - hour = None - - for forecast in self.forecastToday: - if forecast['b']: - hour = forecast['h'] - break - - return hour - - def __construct_plain_message(self, locationName): - plain = f'{locationName} forecast\n\n' - for forecast in self.forecastToday: - hourStr = str(forecast['h']) - probStr = str(round(forecast['p'] * 100)) - plain += f'{hourStr : <2}h {probStr : >3}%\n' - - action_url = get_github_actions_url() - plain += action_url + '\n\n' - - return plain - - def __construct_html_message(self, locationName): - html = """ - - - - - -

{locationName} forecast

- - - - - """ - - # populate cells - for id, forecast in enumerate(self.forecastToday): - hourStr = str(forecast['h']) - probStr = str(round(forecast['p'] * 100)) - html += f""" - - - - - """ - - html += """ -
Hour [h]Probability [%]
{hourStr}{probStr}
""" - action_url = get_github_actions_url() - html += f""" -

GitHub Action Run

- - -""" - debug(html) - return html - - def get_forecast_message(self): - rainStartHour = self.get_rain_start_hour() - locationName = self.location.get_location_name() - - subject = f'Rain in {locationName} from {rainStartHour}h' - - plain = self.__construct_plain_message(locationName) - html = self.__construct_html_message(locationName) - - return (subject, plain, html) - - def rain_today(self): - # for debug only - debug(f"Hourly forecast in {self.location.get_location_name()}") - for byhour_forecast in self.forecastToday: - debug(str(byhour_forecast)) - - return True in [forecast['b'] for forecast in self.forecastToday] diff --git a/gmail.py b/gmail.py deleted file mode 100644 index 56451b844..000000000 --- a/gmail.py +++ /dev/null @@ -1,36 +0,0 @@ -import smtplib -import ssl -from email.mime.text import MIMEText -from email.mime.multipart import MIMEMultipart -from utils import error - - -SSL_PORT = 465 -SMTP_GMAIL = 'smtp.gmail.com' - - -class Gmail: - def __init__(self, sender_email, password): - self.sender = sender_email - - context = ssl.create_default_context() - self.__server = smtplib.SMTP_SSL(SMTP_GMAIL, SSL_PORT, context=context) - - try: - self.__server.login(self.sender, password) - except smtplib.SMTPAuthenticationError: - error('Wrong username or password.') - - def send(self, receiver, subject, content, contentHtml=None): - message = MIMEMultipart("alternative") - - message['From'] = self.sender - message['To'] = receiver - message['Subject'] = subject - - message.attach(MIMEText(content, "plain")) - - if contentHtml: - message.attach(MIMEText(contentHtml, "html")) - - self.__server.send_message(message, self.sender, receiver) diff --git a/location.py b/location.py deleted file mode 100644 index 16c07e3b8..000000000 --- a/location.py +++ /dev/null @@ -1,44 +0,0 @@ -from timezonefinder import TimezoneFinder -from datetime import datetime -from geopy import geocoders -import pytz -from utils import error, debug - -GEOLOC_APP_NAME = 'Locator-request-app' - - -class Location: - def __init__(self, name): - self.name = name - - # get latitude, longitude - try: - geolocator = geocoders.Nominatim(user_agent=GEOLOC_APP_NAME) - self.point = geolocator.geocode(self.name) - except Exception as e: - error(str(e)) - else: - if self.point == None: - error(f"Could not find '{self.name}'.") - - # get timezone - tf = TimezoneFinder() - self.timezone = tf.timezone_at( - lat=self.point.latitude, lng=self.point.longitude) - debug(f'Timezone: {self.timezone}') - - def get_location_name(self): - return self.name - - def get_local_time(self): - tz = pytz.timezone(self.timezone) - local_time = datetime.now(tz) - debug(f'Local time: {local_time}') - return local_time - - def get_local_time_utc(self): - local_time = self.get_local_time() - return local_time.astimezone(pytz.utc) - - def get_latitude_longitude(self): - return self.point.latitude, self.point.longitude diff --git a/logs/.gitkeep b/logs/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/logs/exec_timetable.json.aes b/logs/exec_timetable.json.aes deleted file mode 100644 index 495e68aa4..000000000 Binary files a/logs/exec_timetable.json.aes and /dev/null differ diff --git a/main.py b/main.py index 023a2a79d..6d89ed10f 100644 --- a/main.py +++ b/main.py @@ -1,70 +1,94 @@ -from datetime import time -from utils import error, get_email_credentials, get_github_actions_url, get_receivers, debug -from gmail import Gmail -from forecast import Forecast -from location import Location -from exec_tracker import ExecTracker - -SEND_EMAIL_HOUR = 5 # AM local time - - -def send_forecast_message(gmail, receiver, message): - subject, msgPlain, msgHtml = message - gmail.send(receiver, subject, msgPlain, msgHtml) - - -def main(): - debug(get_github_actions_url()) - sender, password = get_email_credentials() - receivers = get_receivers() - if len(receivers) == 0: error('No receivers imported.') - - gmail = Gmail(sender, password) - - # use password from email to encrypt exec tracker file - track = ExecTracker(password) - - for locationName, emails in receivers.items(): - location = Location(locationName) - - executed_today = track.script_executed_today(location) - time_to_send_email = location.get_local_time().hour >= SEND_EMAIL_HOUR - - if executed_today: - debug('Script already executed today, no need to fetch forecast.') - if not time_to_send_email: - debug(f'Its not time to send an email. Waiting for {SEND_EMAIL_HOUR} A.M. local time.') - - if not executed_today and time_to_send_email: - """ mark execution time only when time to send en email because - we don't want to exceed the number of free OpenWeather API calls """ - debug("Script not executed today and its time to send en email.") - debug('Mark executed time.') - track.mark_exec_time(location) - - forecast = Forecast(location) - - if forecast.rain_today(): - debug('It will rain today.') - message = forecast.get_forecast_message() - - for email in emails: - debug('Sending email message.') - send_forecast_message(gmail, email, message) - else: - debug('It will not rain today.') - - debug('Closing execution timetable.') - track.close() - debug('Checking if timetable is modified') - if track.is_timetable_modified(): - debug('Timetable modified') - track.add_and_commit_timetable() - else: - debug('Timetable not modified') - - debug("Application finished.") - - -if __name__ == "__main__": - main() +import os + +# Get hourly precipitation probability for Zagreb +import urllib.request +import json +ZAGREB_WEATHER_API = "https://api.open-meteo.com/v1/forecast?latitude=45.8144&longitude=15.978&hourly=precipitation_probability&timezone=Europe%2FBerlin&forecast_days=1" +with urllib.request.urlopen(ZAGREB_WEATHER_API) as response: + assert response.status == 200 + data = json.loads(response.read()) + +from datetime import datetime +data_hourly = data["hourly"] +precipitation = [(datetime.fromisoformat(time), int(prob)) for time, prob in zip(data_hourly["time"], data_hourly["precipitation_probability"])] + +# If there is a high probability of rain, send an email +if any(prob >= 0.5 for _, prob in precipitation): + import smtplib + import ssl + from email.mime.text import MIMEText + from email.mime.multipart import MIMEMultipart + SSL_PORT = 465 + SMTP_GMAIL = 'smtp.gmail.com' + context = ssl.create_default_context() + server = smtplib.SMTP_SSL(SMTP_GMAIL, SSL_PORT, context=context) + sender_email, password = os.getenv('SENDER_EMAIL'), os.getenv('SENDER_PASSWORD') + assert sender_email is not None and password is not None + server.login(sender_email, password) + + # get first high probability of rain + hour_start = [time for time, prob in precipitation if prob >= 0.5][0] + # Construct message subject and HTML content + subject = f"Padaline u Zagrebu od {hour_start.strftime('%H:%M')}h" + content = """ + + + + + +

Zagreb forecast

+ + + + + """ + for id,forecast in enumerate(precipitation): + hourStr = str(forecast[0].hour) + probStr = str(forecast[1]) + content += f""" + + + + + """ + + content += """
Hour [h]Probability [%]
{hourStr}{probStr}
""" + action_url = os.getenv('ACTION_URL') or "Unknown" + content += f""" +

GitHub Action Run

+ + +""" + print(content) + receivers = os.getenv('RECEIVERS') + assert receivers is not None + receivers = receivers.split('\n') + for receiver in receivers: + message = MIMEMultipart("alternative") + message['From'] = sender_email + message['To'] = receiver + message['Subject'] = subject + message.attach(MIMEText(content, "html")) + server.send_message(message, sender_email, receiver) diff --git a/open_weather.py b/open_weather.py deleted file mode 100644 index 924db7cde..000000000 --- a/open_weather.py +++ /dev/null @@ -1,46 +0,0 @@ -import requests -from datetime import datetime -from utils import get_openWeather_api_key, error, debug - - -class OpenWeather: - # we want to get API key only once - __API_KEY = get_openWeather_api_key() - - def __init__(self): - pass - - def _get_data_from_api(self, latitude, longitude): - - API_URL = 'http://api.openweathermap.org/data/2.5/onecall?'\ - f'&lat={latitude}'\ - f'&lon={longitude}'\ - '&exclude=current,minutely,daily,alerts&units=metric'\ - f'&appid={self.__API_KEY}' - - try: - response = requests.get(API_URL) - except: - error('OpenWeather API request failed.') - - return response.json() - - def get_forecast(self, latitude, longitude): - forecastByHour = [] - - data = self._get_data_from_api(latitude, longitude) - debug(data) - - timezoneOffset = data['timezone_offset'] - byHours = data['hourly'] - - for hour in byHours: - unixTime = hour['dt'] + timezoneOffset - localTime = datetime.utcfromtimestamp(unixTime) - - rainProbability = hour['pop'] - - rainData = {'t': localTime, 'p': rainProbability} - forecastByHour.append(rainData) - - return forecastByHour diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 957faf686..000000000 --- a/requirements.txt +++ /dev/null @@ -1,24 +0,0 @@ -astroid==2.5.2 -autopep8==1.5.6 -certifi==2020.12.5 -cffi==1.14.5 -chardet==4.0.0 -cryptography==3.4.7 -geographiclib==1.50 -geopy==2.1.0 -idna==2.10 -isort==5.8.0 -lazy-object-proxy==1.6.0 -mccabe==0.6.1 -numpy==1.20.2 -pyAesCrypt==6.0.0 -pycodestyle==2.7.0 -pycparser==2.20 -pylint==2.7.4 -pytz==2021.1 -PyYAML==5.4.1 -requests==2.25.1 -timezonefinder==5.2.0 -toml==0.10.2 -urllib3==1.26.4 -wrapt==1.12.1 diff --git a/tests/context.py b/tests/context.py deleted file mode 100644 index d81038992..000000000 --- a/tests/context.py +++ /dev/null @@ -1,5 +0,0 @@ -import os -import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -import rain_alert.utils as utils diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 1f23f333b..000000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,22 +0,0 @@ -from rain_alert.utils import RECEIVERS_FILE_PATH -import unittest - -from .context import utils - -import os - - -class TestGetReceivers(unittest.TestCase): - def test_no_file(self): - # set the path of the receivers to this folder because in tests folder - # we dont have the receivers file - utils.RECEIVERS_FILE_PATH = os.path.split(utils.RECEIVERS_FILE_PATH)[-1] - self.assertTrue(True) - -""" -class TestGetCredentials(unittest.TestCase): - ... -""" - -if __name__ == '__main__': - unittest.main() diff --git a/utils.py b/utils.py deleted file mode 100644 index 4ae13519b..000000000 --- a/utils.py +++ /dev/null @@ -1,85 +0,0 @@ -import yaml -from os import path, getenv - -DEBUG = True -CREDENTIALS_FILE_PATH = path.abspath( - path.join('credentials', 'credentials.yaml')) -RECEIVERS_FILE_PATH = path.abspath(path.join('credentials', 'receivers.txt')) -ACTION_URL_ENV = 'ACTION_URL' # defined in weather_check.yml - - -def get_email_credentials(): - try: - with open(CREDENTIALS_FILE_PATH, 'r') as file: - credentials = yaml.load(file, Loader=yaml.FullLoader) - except: - error( - f"Could not open {CREDENTIALS_FILE_PATH}. Check if the file exist with the correct name.") - - try: - sender = credentials['senderEmail'] - password = credentials['senderPassword'] - except: - error("Could not retrieve Email or Email password from the Credentials file.") - - return sender, password - - -def get_openWeather_api_key(): - try: - with open(CREDENTIALS_FILE_PATH, 'r') as file: - credentials = yaml.load(file, Loader=yaml.FullLoader) - except: - error( - f"Could not open {CREDENTIALS_FILE_PATH}. Check if the file exist with the correct name.") - - try: - key = credentials['openWeatherApiKey'] - except: - error("Could not get the OpenWeather API key from Credentials file.") - - return key - - -def get_receivers(): - try: - with open(RECEIVERS_FILE_PATH, 'r') as file: - lines = file.read().splitlines() - except FileNotFoundError: - error(f"Could not open {RECEIVERS_FILE_PATH}. Check if the file exist with the correct name.") - else: - locations = {} - - for line in lines: - receiver, _, location = line.partition(',') - receiver = receiver.strip() - location = location.strip() - - if not location in locations: - locations[location] = [] - - locations[location].append(receiver) - - return locations - - -def get_github_actions_url(): - action_url = getenv(ACTION_URL_ENV) - if action_url is None: - debug('Cannot get GitHub Actions link') - action_url = '' - - return action_url - - -def debug(msg): - if DEBUG: - if type(msg) is dict: - print('DEBUG: ') - print(msg) - else: - print('DEBUG: ' + msg) - - -def error(msg): - exit('ERROR: ' + msg)