diff --git a/web/app.py b/web/app.py
index 3dcdcae..0e805ea 100644
--- a/web/app.py
+++ b/web/app.py
@@ -1,5 +1,5 @@
import os
-from flask import Flask, request, jsonify, render_template, redirect, url_for, session, flash
+from flask import Flask, request, jsonify, render_template, redirect, url_for, session, flash, send_file
from flask_wtf import CSRFProtect
from typing import Dict, List
@@ -32,6 +32,7 @@ from web.utils import (
initialize_users_from_settings,
filter_jobs,
get_job_by_id,
+ get_cache_dir,
)
from web.db import get_all_regions, get_all_keywords
@@ -229,6 +230,39 @@ def job_by_id(job_id):
return jsonify({"error": "Job not found"}), 404
+@app.route('/cached/', methods=['GET'])
+def serve_cached(job_id):
+ """Serve the cached HTML file for a job if available.
+
+ Uses the job record's `file_path_abs` when present, or resolves the DB `file_path` via helper.
+ Ensures the returned file is located under the configured cache directory to avoid path-traversal.
+ """
+ try:
+ from web.db import db_get_cached_abs_path
+ j = get_job_by_id(job_id)
+ if not j:
+ return "Job not found", 404
+
+ # Prefer file_path_abs, fall back to resolving the DB-stored file_path
+ abs_fp = j.get('file_path_abs') or None
+ if not abs_fp:
+ db_fp = j.get('file_path')
+ abs_fp = db_get_cached_abs_path(db_fp) if db_fp else None
+
+ if not abs_fp or not os.path.isfile(abs_fp):
+ return "Cached file not available", 404
+
+ cache_dir = os.path.abspath(get_cache_dir())
+ abs_fp = os.path.abspath(abs_fp)
+ # Ensure the file is inside the cache directory
+ if os.path.commonpath([cache_dir, abs_fp]) != cache_dir:
+ return "Forbidden", 403
+
+ return send_file(abs_fp)
+ except Exception:
+ return "Error serving cached file", 500
+
+
@app.route('/jobs//favorite', methods=['POST'])
def set_favorite(job_id):
"""Mark or unmark a job as favorite for a given user.
diff --git a/web/templates/index.html b/web/templates/index.html
index feac3ec..fee4585 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -46,6 +46,11 @@
{{ job['posted_time'] }}
{{ job['region'] }}
{{ job['keyword'] }}
+ {% if job.get('file_path_abs') or job.get('file_path') %}
+
+ {% endif %}
{% endfor %}
diff --git a/web/templates/job.html b/web/templates/job.html
index 85948df..bf337a4 100644
--- a/web/templates/job.html
+++ b/web/templates/job.html
@@ -23,5 +23,13 @@ styles %}{% endblock %} {% block content %}
>{{ job.title }}
+ {% if job.file_path_abs or job.file_path %}
+
+ Cached copy:
+ View cached copy
+
+ {% endif %}
{% endblock %}