AtmoAssistant/app/utils.py

150 lines
4.8 KiB
Python
Raw Normal View History

2025-01-20 20:09:02 -05:00
from datetime import datetime, timedelta, timezone
import json
from urllib import parse
import logging
import re
import typing as t
2025-01-20 23:15:24 -05:00
import requests
import traceback
2025-01-20 20:09:02 -05:00
2025-01-23 00:25:56 -05:00
from models import db, Stats, Weather, Zipcode
from config import env_OWM_KEY, env_OWM_UNITS, env_CACHE_TIME
2025-01-20 20:09:02 -05:00
logger = logging.getLogger("gunicorn.error")
weather_template = "The current temperature is: {0}. The real feel temperature is: {1}. The high is: {2}. The low is: {3}. The current humidity is: {4} percent. The summary for today is: {5}."
2025-01-20 20:09:02 -05:00
def str_none(x):
if x is None:
return ""
else:
return str(x)
def string_validator(input_str: str):
# Decode the input string
decoded_str = parse.unquote(input_str)
# Sanitize the string
sanitized = re.sub(r"[\s]", "", decoded_str)
sanitized = re.sub(r'[<>"\'%;]', "", sanitized)
# Check length of the string
if len(sanitized) < 1:
return None
return sanitized
def validate_data_presence(data: t.Dict[str, t.Any], keys: list[str]) -> bool:
"""
Validate that all given keys are present in the data.
Args:
data (Dict[str, Any]): The JSON data to be validated.
keys (list[str]): A list of keys to look for in the data.
Returns:
bool: If any key is missing, returns False. Otherwise, returns True.
"""
for key in keys:
if key not in data:
return False
return True
2025-01-20 23:15:24 -05:00
2025-01-22 19:13:36 -05:00
def strq(str: str) -> str:
return "\"" + str + "\""
2025-01-20 23:15:24 -05:00
def _get_weather(lat, long):
try:
if lat is None or long is None:
return "An error has occured and the provided zipcode could not be understood."
weather_json = _get_weather_json(lat, long)
if weather_json is None:
return "An error has occured and the weather could not be retrieved."
weather = weather_template.format(
round(weather_json["current"]["temp"]),
round(weather_json["current"]["feels_like"]),
round(weather_json["daily"][0]["temp"]["max"]),
round(weather_json["daily"][0]["temp"]["min"]),
round(weather_json["current"]["humidity"]),
2025-01-22 19:54:01 -05:00
weather_json["daily"][0]["summary"],
2025-01-20 23:15:24 -05:00
)
2025-01-23 00:25:56 -05:00
lat_long = str(lat) + "," + str(long)
s = Stats(lat_long=lat_long)
db.session.add(s)
db.session.commit()
2025-01-20 23:15:24 -05:00
return weather
except Exception as e:
2025-01-22 19:54:01 -05:00
logger.error("Error in _get_weather: " + str(e))
logger.error(traceback.format_exc())
2025-01-20 23:15:24 -05:00
return "An error has occured and the weather could not be retrieved."
def _get_weather_json(lat, long):
url = "https://api.openweathermap.org/data/3.0/onecall?lat={0}&lon={1}&exclude=alerts,minutely,hourly&units={2}&appid={3}".format(
lat, long, env_OWM_UNITS, env_OWM_KEY
)
2025-01-23 00:25:56 -05:00
lat_long = str(lat) + "," + str(long)
current_time = datetime.now(timezone.utc)
2025-01-20 23:15:24 -05:00
try:
2025-01-23 00:25:56 -05:00
w = Weather.query.filter(Weather.lat_long == lat_long).first()
if w and w.last_timestamp.replace(tzinfo=timezone.utc) >= current_time - timedelta(minutes=env_CACHE_TIME):
logger.info("Weather cache hit!")
return w.results
logger.info("Weather cache miss!")
2025-01-20 23:15:24 -05:00
response = requests.get(url)
if response.status_code == 200:
weather = response.json()
2025-01-23 00:25:56 -05:00
if w:
w.results = weather
w.last_timestamp = current_time
else:
w = Weather(lat_long=lat_long, results=weather)
db.session.add(w)
db.session.commit()
2025-01-20 23:15:24 -05:00
return weather
else:
logger.error("Error in _get_weather_json: " + str(response.status_code))
return None
except requests.exceptions.RequestException as e:
2025-01-22 19:54:01 -05:00
logger.error("Error in _get_weather_json: " + str(e))
logger.error(traceback.format_exc())
2025-01-20 23:15:24 -05:00
return None
def _get_cords(zipcode):
url = "http://api.openweathermap.org/geo/1.0/zip?zip={0},US&appid={1}".format(
zipcode, env_OWM_KEY
)
try:
2025-01-23 00:25:56 -05:00
z = Zipcode.query.filter_by(zip=zipcode).first()
if z:
logger.info("Zipcode cache hit!")
return z.results["lat"], z.results["lon"]
logger.info("Zipcode cache miss!")
2025-01-20 23:15:24 -05:00
response = requests.get(url)
if response.status_code == 200:
locale = response.json()
2025-01-22 19:54:01 -05:00
logger.info(locale)
2025-01-23 00:25:56 -05:00
new_z = Zipcode(zip=zipcode, results=locale)
db.session.add(new_z)
db.session.commit()
2025-01-22 19:54:01 -05:00
return locale["lat"], locale["lon"]
2025-01-20 23:15:24 -05:00
else:
logger.error("Error in _get_cords: " + str(response.status_code))
return None, None
except requests.exceptions.RequestException as e:
2025-01-22 19:54:01 -05:00
logger.error("Error in _get_cords: " + str(e))
logger.error(traceback.format_exc())
2025-01-20 23:15:24 -05:00
return None, None