complete change to email instead of FTP
This commit is contained in:
186
app/main.py
186
app/main.py
@@ -1,102 +1,124 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Mailpit → Gotify bridge webhook.
|
||||
|
||||
from utils.common_utils import get_common_utils
|
||||
from utils.logging_setup import get_logger
|
||||
from utils.settings import get_settings
|
||||
from utils.cache_db import get_cache
|
||||
Receives POSTs from Mailpit (MP_WEBHOOK_URL) when new mail arrives.
|
||||
Fetches the full message from the Mailpit API, extracts useful info,
|
||||
and forwards a summary to Gotify.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
from typing import Any, Dict
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
from flask import Flask, jsonify, request
|
||||
|
||||
logger = get_logger()
|
||||
settings = get_settings()
|
||||
utils = get_common_utils()
|
||||
# ------------------------------------------------------------------ #
|
||||
# Config & logging
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
load_dotenv()
|
||||
|
||||
MAILPIT_API = os.getenv("MAILPIT_API", "http://localhost:8025")
|
||||
MAILPIT_TOKEN = os.getenv("MAILPIT_TOKEN", "")
|
||||
GOTIFY_URL = os.getenv("GOTIFY_URL","")
|
||||
GOTIFY_TOKEN = os.getenv("GOTIFY_TOKEN","")
|
||||
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
|
||||
|
||||
CACHE_DIR = Path.cwd() / "config" / "cache.db"
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, LOG_LEVEL, logging.INFO),
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
)
|
||||
log = logging.getLogger("mailpit-hook")
|
||||
|
||||
def gotify(title:str="Test", message:str="testing msg",priority:int=5):
|
||||
"""
|
||||
Send a message to a Gotify server using a Bearer token.
|
||||
app = Flask(__name__)
|
||||
|
||||
Args:
|
||||
server_url (str): Base URL of the Gotify server (e.g., http://10.10.20.8:8080).
|
||||
token (str): Gotify app token for authentication.
|
||||
title (str): Title of the message.
|
||||
message (str): Body of the message.
|
||||
priority (int, optional): Message priority (1–10). Defaults to 5.
|
||||
from utils.gotify_api import GotifyNotifier
|
||||
|
||||
Returns:
|
||||
bool: True if the message was sent successfully, False otherwise.
|
||||
"""
|
||||
server_url = os.getenv("GOTIFY_URL")
|
||||
token = os.getenv("GOTIFY_TOKEN")
|
||||
# ------------------------------------------------------------------ #
|
||||
# Helpers
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
if not server_url or not token:
|
||||
print("[!] Missing GOTIFY_URL or GOTIFY_TOKEN in environment.")
|
||||
return False
|
||||
def get_mailpit_message(message_id: str) -> Dict[str, Any]:
|
||||
"""Retrieve full message JSON from Mailpit REST API."""
|
||||
url = f"{MAILPIT_API}/api/v1/message/{message_id}"
|
||||
headers = {}
|
||||
if MAILPIT_TOKEN:
|
||||
headers["Authorization"] = f"Bearer {MAILPIT_TOKEN}"
|
||||
|
||||
url = f"{server_url.rstrip('/')}/message"
|
||||
resp = requests.get(url, headers=headers, timeout=10)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def send_gotify(title: str, message: str, priority: int = 5) -> None:
|
||||
"""Send a message to Gotify."""
|
||||
notify = GotifyNotifier(GOTIFY_URL, GOTIFY_TOKEN)
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"title": title,
|
||||
"message": message,
|
||||
"priority": priority
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=10)
|
||||
response.raise_for_status()
|
||||
return True
|
||||
except requests.RequestException as e:
|
||||
print(f"[!] Failed to send Gotify message: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def check_dir_changed():
|
||||
changed = False
|
||||
|
||||
dir_to_watch = os.getenv("DIR_TO_WATCH")
|
||||
|
||||
# create a cache db object and key for this dir (base64 of the dir)
|
||||
cache = get_cache(CACHE_DIR)
|
||||
cache_key = utils.TextUtils.encode_base64(dir_to_watch)
|
||||
|
||||
# get the old file listing from cache
|
||||
existing_contents = cache.read(cache_key)
|
||||
|
||||
try:
|
||||
# get current files
|
||||
current_files = utils.FileUtils.list_files_in_dir_w_subs(dir_to_watch)
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to check for files due to: {e}")
|
||||
return False
|
||||
|
||||
# if they are different..
|
||||
if existing_contents != current_files:
|
||||
logger.info(f"The contents of {dir_to_watch} changed")
|
||||
changed = True
|
||||
|
||||
# update the cache
|
||||
if existing_contents is None:
|
||||
cache.create(cache_key,current_files)
|
||||
result = notify.gotify(title=title,markdown=message,priority=5)
|
||||
if not result:
|
||||
log.warning("Gotify push failed")
|
||||
else:
|
||||
cache.update(cache_key,current_files)
|
||||
log.info("Gotify push OK")
|
||||
|
||||
return changed
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Webhook route
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
@app.route("/hook", methods=["POST"])
|
||||
def hook():
|
||||
"""
|
||||
Mailpit sends JSON like:
|
||||
{
|
||||
"ID": "abcdef123",
|
||||
"MessageID": "<...>",
|
||||
"From": "camera@reolink.local",
|
||||
"Subject": "Motion Detected",
|
||||
...
|
||||
}
|
||||
"""
|
||||
data = request.get_json(silent=True) or {}
|
||||
mail_msg_id = data.get("MessageID")
|
||||
msg_id = data.get("ID")
|
||||
if not msg_id:
|
||||
log.warning("Webhook received malformed payload: %s", data)
|
||||
return jsonify({"error": "missing ID"}), 400
|
||||
|
||||
log.info(f"Webhook triggered for message ID={msg_id} - Email MSG_ID={mail_msg_id}")
|
||||
|
||||
result = handle_hook(msg_id)
|
||||
if result:
|
||||
return jsonify({"status": "ok"}), 200
|
||||
else:
|
||||
return jsonify({"error":"Error sending webhook"}), 500
|
||||
|
||||
|
||||
def handle_hook(msg_id:str):
|
||||
try:
|
||||
msg = get_mailpit_message(msg_id)
|
||||
subject = msg.get("Subject", "(no subject)")
|
||||
text = msg.get("Text", "") or msg.get("HTML", "")
|
||||
preview = (text or "")
|
||||
if len(preview) > 200:
|
||||
preview = preview[:200] + "..."
|
||||
|
||||
send_gotify(subject, preview)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
log.exception("Error processing webhook: %s", e)
|
||||
return False
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Entry point
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
if __name__ == "__main__":
|
||||
title = "NEW ACTIVITY DETECTED"
|
||||
msg = "Your Camera System has uploaded videos!. We have detected activity!"
|
||||
|
||||
files_changed = check_dir_changed()
|
||||
if files_changed:
|
||||
gotify(title,msg)
|
||||
# msg_id = "ZTUUK57e7kUoaviua6TCgP@mailpit"
|
||||
# msg = get_mailpit_message(msg_id)
|
||||
app.run(host="0.0.0.0", port=8088)
|
||||
|
||||
Reference in New Issue
Block a user