""" Utility functions for the Pasig Full Disclosure API. This module provides functions for fetching, caching, and managing HTML data from the Pasig City government website. All timestamps use UTC+8 (Philippine Time). """ import requests import os from datetime import datetime, timezone, timedelta from typing import Optional, Dict # Mapping of data paths to their corresponding URLs on the Pasig City website path_to_url: Dict[str, str] = { "resolutions": "https://pasigcity.gov.ph/city-resolutions", "ordinances": "https://pasigcity.gov.ph/city-ordinances", "executive-orders": "https://pasigcity.gov.ph/executive-orders", "bids-and-awards": "https://pasigcity.gov.ph/bids-and-awards" } def refresh_html(path: str) -> None: """ Fetch HTML content from the Pasig City website and save it to a local file. Args: path: The data path (e.g., 'resolutions', 'ordinances', 'executive-orders', 'bids-and-awards'). Must be a key in the path_to_url dictionary. Returns: None Side Effects: - Creates the 'data' directory if it doesn't exist - Creates or overwrites the file 'data/{path}.html' with fetched content """ url = path_to_url[path] html = requests.get(url) # Create data folder if it doesn't exist os.makedirs("data", exist_ok = True) # Write the HTML content to file (creates new or replaces existing) filename = os.path.join("data", f"{path}.html") with open(filename, "w", encoding = "utf-8") as f: f.write(html.text) def update_time(path: str) -> None: """ Update the last refresh timestamp for a specific data path in UTC+8. This function reads the existing timestamps from 'data/last_updated.txt', updates the timestamp for the specified path with the current time, and writes all timestamps back to the file. Creates the file and directory if they don't exist. Args: path: The data path to update (e.g., 'resolutions', 'ordinances'). Returns: None Side Effects: - Creates the 'data' directory if it doesn't exist - Creates or updates 'data/last_updated.txt' with the current timestamp - Preserves timestamps for other paths in the file """ # Ensure data directory exists os.makedirs("data", exist_ok = True) # Use UTC+8 timezone (Philippine Time) utc_plus_8 = timezone(timedelta(hours = 8)) current_time = datetime.now(utc_plus_8).isoformat() # Read existing times times = {} last_updated_file = "data/last_updated.txt" if os.path.exists(last_updated_file): with open(last_updated_file, "r", encoding = "utf-8") as f: for line in f: line = line.strip() if line and ":" in line: key, value = line.split(":", 1) times[key.strip()] = value.strip() # Update the time for the given path times[path] = current_time # Write all times back to file (creates file if it doesn't exist) with open(last_updated_file, "w", encoding = "utf-8") as f: for key, value in times.items(): f.write(f"{key}: {value}\n") def get_time(path: str) -> Optional[str]: """ Retrieve the last refresh timestamp for a specific data path. Args: path: The data path to look up (e.g., 'resolutions', 'ordinances'). Returns: The ISO-format timestamp string in UTC+8 if found, None otherwise. Returns None if the file doesn't exist or the path is not found. Example: >>> get_time("resolutions") '2025-11-05T17:29:40.443171+08:00' """ last_updated_file = "data/last_updated.txt" # Return None if file doesn't exist (app can rebuild from scratch) if not os.path.exists(last_updated_file): return None # Read the file and search for the path try: with open(last_updated_file, "r", encoding = "utf-8") as f: for line in f: line = line.strip() if line and ":" in line: key, value = line.split(":", 1) if key.strip() == path: return value.strip() except (IOError, OSError): # Handle any file reading errors gracefully return None return None def update_if_needed(path: str, refresh_timer: timedelta = timedelta(days = 1)) -> None: """ Refresh HTML content if the cached version is outdated. This function checks the last update timestamp for the specified path and refreshes the HTML content if the time elapsed since the last update is greater than or equal to the refresh_timer. If no timestamp exists, it refreshes immediately. Args: path: The data path to check and potentially refresh. refresh_timer: The minimum time between refreshes (default: 1 day). Returns: None Side Effects: - May fetch new HTML content and update the local cache - May update the timestamp in 'data/last_updated.txt' - Creates the 'data' directory if it doesn't exist Example: >>> # Refresh if older than 1 day (default) >>> update_if_needed("resolutions") >>> >>> # Refresh if older than 12 hours >>> update_if_needed("ordinances", refresh_timer = timedelta(hours = 12)) """ # Ensure data directory exists (app can rebuild from scratch) os.makedirs("data", exist_ok = True) # Get the last updated time for the path last_updated_str = get_time(path) # If no record exists, refresh immediately if last_updated_str is None: refresh_html(path) update_time(path) return # Parse the last updated time last_updated = datetime.fromisoformat(last_updated_str) # Get current time in UTC+8 utc_plus_8 = timezone(timedelta(hours = 8)) current_time = datetime.now(utc_plus_8) # Check if refresh is needed time_difference = current_time - last_updated if time_difference >= refresh_timer: refresh_html(path) update_time(path) return def get_current_year() -> int: """ Get the current year in UTC+8 (Philippine Time). This ensures the year is always calculated based on Philippine Time, regardless of the server's local timezone. Returns: The current year as an integer. Example: >>> get_current_year() 2025 """ # Use UTC+8 timezone (Philippine Time) utc_plus_8 = timezone(timedelta(hours = 8)) current_time = datetime.now(utc_plus_8) return current_time.year