mirror of
https://github.com/mskatoni/ni-mail.git
synced 2026-09-06 07:56:43 +08:00
fix: resolve 18-point audit items including http payload error helpers, python-dotenv auto-load, and exception wrapping
This commit is contained in:
+14
-4
@@ -1,16 +1,22 @@
|
|||||||
__version__ = "1.1.0"
|
|
||||||
import os
|
import os
|
||||||
from flask import Flask, render_template, jsonify
|
from flask import Flask, render_template, jsonify
|
||||||
|
from dotenv import load_dotenv
|
||||||
from app.db import db
|
from app.db import db
|
||||||
from app.api import accounts, emails
|
from app.api import accounts, emails
|
||||||
|
|
||||||
|
__version__ = "1.1.0"
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
|
load_dotenv()
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
db_path = os.getenv("DATABASE_URL", f"sqlite:///{os.path.join(os.getcwd(), 'ni_mail.db')}")
|
data_dir = os.getenv("DATA_DIR", os.getcwd())
|
||||||
|
default_db = f"sqlite:///{os.path.join(data_dir, 'ni_mail.db')}"
|
||||||
|
db_path = os.getenv("DATABASE_URL", default_db)
|
||||||
|
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = db_path
|
app.config["SQLALCHEMY_DATABASE_URI"] = db_path
|
||||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||||
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "ni-mail-secret-key")
|
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "ni-mail-secret-key-v1.1.0")
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
|
||||||
@@ -23,7 +29,11 @@ def create_app():
|
|||||||
|
|
||||||
@app.route("/health")
|
@app.route("/health")
|
||||||
def health():
|
def health():
|
||||||
return jsonify({"status": "ok", "app": "ni-mail"})
|
return jsonify({
|
||||||
|
"status": "ok",
|
||||||
|
"app": "ni-mail",
|
||||||
|
"version": __version__
|
||||||
|
})
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|||||||
+40
-36
@@ -18,22 +18,27 @@ def get_emails():
|
|||||||
proxy_url = os.getenv("PROXY_URL")
|
proxy_url = os.getenv("PROXY_URL")
|
||||||
messages = []
|
messages = []
|
||||||
|
|
||||||
if acct.method == "graph":
|
try:
|
||||||
token_res = graph.get_access_token_graph_result(
|
if acct.method == "graph":
|
||||||
client_id=acct.client_id,
|
token_res = graph.get_access_token_graph_result(
|
||||||
refresh_token=acct.refresh_token,
|
client_id=acct.client_id,
|
||||||
proxy_url=proxy_url
|
refresh_token=acct.refresh_token,
|
||||||
)
|
proxy_url=proxy_url
|
||||||
if isinstance(token_res, dict) and "access_token" in token_res:
|
)
|
||||||
token = token_res["access_token"]
|
if isinstance(token_res, dict) and "access_token" in token_res:
|
||||||
messages = graph.fetch_messages(token, top=15, proxy_url=proxy_url)
|
token = token_res["access_token"]
|
||||||
else:
|
messages = graph.fetch_messages(token, top=15, proxy_url=proxy_url)
|
||||||
messages = imap.fetch_inbox_messages(
|
elif isinstance(token_res, dict) and "error" in token_res:
|
||||||
email=acct.email,
|
return jsonify({"error": token_res["error"]}), 400
|
||||||
password=acct.password or acct.refresh_token,
|
else:
|
||||||
limit=15,
|
messages = imap.fetch_inbox_messages(
|
||||||
proxy_url=proxy_url
|
email=acct.email,
|
||||||
)
|
password=acct.password or acct.refresh_token,
|
||||||
|
limit=15,
|
||||||
|
proxy_url=proxy_url
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": f"Failed to fetch emails: {str(e)}"}), 500
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
@@ -42,7 +47,7 @@ def get_emails():
|
|||||||
results.append({
|
results.append({
|
||||||
"id": msg.get("id"),
|
"id": msg.get("id"),
|
||||||
"subject": msg.get("subject"),
|
"subject": msg.get("subject"),
|
||||||
"from": msg.get("from", {}).get("emailAddress", {}).get("address", ""),
|
"from": msg.get("from", {}).get("emailAddress", {}).get("address", "") if isinstance(msg.get("from"), dict) else str(msg.get("from", "")),
|
||||||
"received_at": msg.get("receivedDateTime"),
|
"received_at": msg.get("receivedDateTime"),
|
||||||
"otp_code": code,
|
"otp_code": code,
|
||||||
"link": link,
|
"link": link,
|
||||||
@@ -68,21 +73,21 @@ def send_email():
|
|||||||
|
|
||||||
proxy_url = os.getenv("PROXY_URL")
|
proxy_url = os.getenv("PROXY_URL")
|
||||||
|
|
||||||
if acct.method == "graph":
|
try:
|
||||||
token_res = graph.get_access_token_graph_result(
|
if acct.method == "graph":
|
||||||
client_id=acct.client_id,
|
token_res = graph.get_access_token_graph_result(
|
||||||
refresh_token=acct.refresh_token,
|
client_id=acct.client_id,
|
||||||
proxy_url=proxy_url
|
refresh_token=acct.refresh_token,
|
||||||
)
|
proxy_url=proxy_url
|
||||||
if isinstance(token_res, dict) and "access_token" in token_res:
|
)
|
||||||
token = token_res["access_token"]
|
if isinstance(token_res, dict) and "access_token" in token_res:
|
||||||
success = graph.send_mail_graph(token, to_email, subject, body, proxy_url=proxy_url)
|
token = token_res["access_token"]
|
||||||
if success:
|
success = graph.send_mail_graph(token, to_email, subject, body, proxy_url=proxy_url)
|
||||||
return jsonify({"success": True, "message": "Email sent via Graph API"})
|
if success:
|
||||||
return jsonify({"error": "Graph API send mail failed"}), 500
|
return jsonify({"success": True, "message": "Email sent via Graph API"})
|
||||||
return jsonify({"error": "Token refresh failed"}), 400
|
return jsonify({"error": "Graph API send mail failed"}), 500
|
||||||
else:
|
return jsonify({"error": "Token refresh failed"}), 400
|
||||||
try:
|
else:
|
||||||
success = smtp.send_mail_smtp(
|
success = smtp.send_mail_smtp(
|
||||||
host=os.getenv("SMTP_HOST", "smtp.office365.com"),
|
host=os.getenv("SMTP_HOST", "smtp.office365.com"),
|
||||||
port=int(os.getenv("SMTP_PORT", "587")),
|
port=int(os.getenv("SMTP_PORT", "587")),
|
||||||
@@ -95,7 +100,6 @@ def send_email():
|
|||||||
)
|
)
|
||||||
if success:
|
if success:
|
||||||
return jsonify({"success": True, "message": "Email sent via SMTP"})
|
return jsonify({"success": True, "message": "Email sent via SMTP"})
|
||||||
except Exception as e:
|
return jsonify({"error": "SMTP send mail failed"}), 500
|
||||||
return jsonify({"error": f"SMTP send mail failed: {str(e)}"}), 500
|
except Exception as e:
|
||||||
|
return jsonify({"error": f"Send mail failed: {str(e)}"}), 500
|
||||||
return jsonify({"error": "Send mail failed"}), 500
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
from app.services.http import build_error_payload, get_response_details
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
|||||||
+13
-9
@@ -1,12 +1,16 @@
|
|||||||
from __future__ import annotations
|
from typing import Any, Dict
|
||||||
|
|
||||||
from typing import Any
|
def get_response_details(res) -> str:
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def get_response_details(response: requests.Response) -> Any:
|
|
||||||
try:
|
try:
|
||||||
return response.json()
|
return res.text[:500]
|
||||||
except Exception:
|
except Exception:
|
||||||
return response.text or response.reason
|
return "No response details"
|
||||||
|
|
||||||
|
def build_error_payload(code: str, message: str, error_type: str = "APIError", status_code: int = 500, details: Any = None) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"code": code,
|
||||||
|
"message": message,
|
||||||
|
"type": error_type,
|
||||||
|
"status": status_code,
|
||||||
|
"details": details
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
from app.services.http import build_error_payload, get_response_details
|
||||||
|
|
||||||
import email
|
import email
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|||||||
Reference in New Issue
Block a user