06/18 Phase 7

This commit is contained in:
2026-06-18 09:29:33 -04:00
parent d1383a9835
commit d54e5e2127
16 changed files with 563 additions and 8 deletions
+91 -2
View File
@@ -1,5 +1,6 @@
"""Main blueprint: landing page and health check."""
from flask import Blueprint, render_template, jsonify
"""Main blueprint: landing page, health check, SEO files."""
from datetime import datetime
from flask import Blueprint, render_template, jsonify, Response, request
main_bp = Blueprint("main", __name__)
@@ -12,3 +13,91 @@ def index():
@main_bp.route("/healthz")
def healthz():
return jsonify(status="ok")
@main_bp.route("/robots.txt")
def robots():
lines = [
"User-agent: *",
"Disallow: /admin",
"Disallow: /auth/",
"Disallow: /my/",
"Disallow: /messages",
"Disallow: /billing/",
f"Sitemap: {request.host_url}sitemap.xml",
]
return Response("\n".join(lines), mimetype="text/plain")
@main_bp.route("/sitemap.xml")
def sitemap():
from app.extensions import db
from app.models.listing import Listing
from app.models.category import Category
from app.models.enums import ListingStatus
base = request.host_url.rstrip("/")
urls = []
# static pages
for path in ("", "/listings", "/pricing", "/sponsors"):
urls.append({"loc": f"{base}{path}", "changefreq": "daily", "priority": "0.8"})
# categories
for cat in Category.query.filter_by(is_active=True).all():
urls.append({
"loc": f"{base}/listings?category={cat.id}",
"changefreq": "daily",
"priority": "0.7",
})
# active listings (last 500 by bump/created for crawl budget)
listings = (Listing.query
.filter(Listing.status == ListingStatus.active,
Listing.expires_at > datetime.utcnow())
.order_by(Listing.created_at.desc())
.limit(500).all())
for l in listings:
urls.append({
"loc": f"{base}/listings/{l.id}",
"lastmod": l.updated_at.strftime("%Y-%m-%d"),
"changefreq": "weekly",
"priority": "0.6",
})
xml = render_template("sitemap.xml", urls=urls)
return Response(xml, mimetype="application/xml")
# ---------------------------------------------------------------------------
# SEO landing pages
# ---------------------------------------------------------------------------
@main_bp.route("/classifieds/category/<slug>")
def category_landing(slug):
from app.extensions import db
from app.models.category import Category
from app.models.listing import Listing
from app.models.enums import ListingStatus
cat = Category.query.filter_by(slug=slug, is_active=True).first_or_404()
listings = (Listing.query
.filter(Listing.category_id == cat.id,
Listing.status == ListingStatus.active,
Listing.expires_at > datetime.utcnow())
.order_by(Listing.created_at.desc())
.limit(20).all())
return render_template("main/category_landing.html", cat=cat, listings=listings)
@main_bp.route("/classifieds/state/<state>")
def state_landing(state):
from app.extensions import db
from app.models.listing import Listing
from app.models.enums import ListingStatus
state = state.upper()
listings = (Listing.query
.filter(Listing.state == state,
Listing.status == ListingStatus.active,
Listing.expires_at > datetime.utcnow())
.order_by(Listing.created_at.desc())
.limit(20).all())
return render_template("main/state_landing.html", state=state, listings=listings)