Files
2025-11-12 08:53:59 -03:00

233 lines
7.7 KiB
Python

# -*- coding: utf-8 -*-
from flask import Flask, render_template, request, send_file, redirect, url_for, render_template_string
import oracledb, json
from datetime import datetime
import io
import oci
import urllib.parse
import extract_msg
# ============================================================
# CONFIGURATION
# ============================================================
with open("config", "r") as f:
config_data = json.load(f)
WALLET_PATH = config_data["WALLET_PATH"]
DB_ALIAS = config_data["DB_ALIAS"]
USERNAME = config_data["USERNAME"]
PASSWORD = config_data["PASSWORD"]
connection = oracledb.connect(
user=USERNAME,
password=PASSWORD,
dsn=DB_ALIAS,
config_dir=WALLET_PATH,
wallet_location=WALLET_PATH,
wallet_password=PASSWORD,
)
# OCI client configuration (same standard as process_emails_v2_en.py)
BUCKET_PROFILE = config_data["bucket-profile"]
BUCKET_NAME = config_data["bucket"]
COMPARTMENT_ID = config_data["compartment_id"]
bucket_name = BUCKET_NAME + "/processed"
# Initialize OCI client and get namespace
config = oci.config.from_file("~/.oci/config", BUCKET_PROFILE)
object_storage = oci.object_storage.ObjectStorageClient(config)
namespace = object_storage.get_namespace().data
app = Flask(__name__)
# ============================================================
# HELPER FUNCTIONS
# ============================================================
def get_distinct_status():
"""Return all distinct statuses + 'Forwarded Email' option."""
with connection.cursor() as c:
c.execute("SELECT DISTINCT STATUS FROM PROCESSED_EMAILS ORDER BY STATUS")
values = [r[0] for r in c.fetchall() if r[0] and str(r[0]).strip()]
if "Forwarded Email" not in values:
values.append("Forwarded Email")
return values
# ============================================================
# MAIN ROUTE
# ============================================================
@app.route("/", methods=["GET"])
def search_emails():
booking = request.args.get("booking", "").strip().upper()
alert_flag = request.args.get("alert", "")
status = request.args.get("status", "")
start_date = request.args.get("start", "")
end_date = request.args.get("end", "")
include_forwarded = request.args.get("include_forwarded") == "on"
sql = """
SELECT DATE_SENT, BOOKING, EMAIL_FROM, EMAIL_TO, SUBJECT,
STATUS, BRIEF_DESCRIPTION, ALERT, FILE_NAME, THREAD_INDEX
FROM PROCESSED_EMAILS_REDACTED
WHERE 1=1 \
"""
params = {}
if booking:
sql += " AND UPPER(BOOKING) LIKE :bk"
params["bk"] = f"%{booking}%"
if alert_flag in ("YES", "NO"):
sql += " AND ALERT = :alert"
params["alert"] = alert_flag
if status:
if status == "Forwarded Email":
sql += " AND (STATUS IS NULL OR TRIM(STATUS) = '')"
else:
sql += " AND STATUS = :status"
params["status"] = status
else:
# If the checkbox is NOT checked, exclude forwarded emails (STATUS is null)
if not include_forwarded:
sql += " AND (STATUS IS NOT NULL)"
if start_date:
sql += " AND DATE_SENT >= TO_TIMESTAMP(:start, 'YYYY-MM-DD')"
params["start"] = start_date
if end_date:
sql += " AND DATE_SENT <= TO_TIMESTAMP(:end, 'YYYY-MM-DD') + INTERVAL '1' DAY"
params["end"] = end_date
sql += " ORDER BY DATE_SENT ASC"
with connection.cursor() as c:
c.execute(sql, params)
rows = c.fetchall()
cols = [d[0] for d in c.description]
records = [dict(zip(cols, row)) for row in rows]
for r in records:
if isinstance(r["DATE_SENT"], datetime):
r["DATE_SENT"] = r["DATE_SENT"].strftime("%Y-%m-%d %H:%M:%S")
if not r.get("STATUS") or not str(r["STATUS"]).strip():
r["STATUS"] = "Forwarded Email"
status_options = get_distinct_status()
return render_template(
"emails_filter.html",
records=records,
filters={
"booking": booking,
"alert": alert_flag,
"status": status,
"start": start_date,
"end": end_date,
"include_forwarded": include_forwarded
},
status_options=status_options
)
# ============================================================
# ROUTE: VIEW EMAIL
# ============================================================
@app.route("/view_email/<path:file_name>")
def view_email(file_name):
try:
# Fix URL encoding
file_name = urllib.parse.unquote(file_name).strip()
# Try multiple possible paths
possible_paths = [
file_name,
f"processed/{file_name}",
f"inbox/{file_name}",
f"emails/{file_name}",
f"emails/processed/{file_name}",
]
msg_obj = None
for path in possible_paths:
try:
obj = object_storage.get_object(namespace, BUCKET_NAME, path)
msg_obj = extract_msg.Message(io.BytesIO(obj.data.content))
print(f"[INFO] File found: {path}")
break
except oci.exceptions.ServiceError as e:
if e.status == 404:
continue
raise
if not msg_obj:
return (
f"<h3>❌ Email not found in any tested path.</h3>"
f"<p><b>Bucket:</b> {BUCKET_NAME}<br><b>File:</b> {file_name}</p>",
404,
)
# Extract main fields
from_field = getattr(msg_obj, "sender", "")
to_field = getattr(msg_obj, "to", "")
subject = getattr(msg_obj, "subject", "")
date = getattr(msg_obj, "date", "")
body = getattr(msg_obj, "body", "")
# Basic HTML rendering for readability
html = f"""
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{subject or "Viewed Email"}</title>
<style>
body {{
font-family: Arial, sans-serif;
background: #f4f4f9;
padding: 30px;
color: #333;
}}
.email-container {{
background: white;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
padding: 20px;
max-width: 900px;
margin: auto;
}}
.header {{
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
padding-bottom: 10px;
}}
.header b {{
color: #004b8d;
}}
pre {{
white-space: pre-wrap;
word-wrap: break-word;
font-family: Arial, sans-serif;
font-size: 15px;
}}
</style>
</head>
<body>
<div class="email-container">
<div class="header">
<p><b>From:</b> {from_field}</p>
<p><b>To:</b> {to_field}</p>
<p><b>Date:</b> {date}</p>
<p><b>Subject:</b> {subject}</p>
</div>
<pre>{body}</pre>
</div>
</body>
</html>
"""
return render_template_string(html)
except Exception as e:
return f"<h3>Error reading the email:</h3><pre>{e}</pre>", 500
# ============================================================
# MAIN ENTRY POINT
# ============================================================
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5015)