105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
"""Main blueprint: landing page, health check, SEO files."""
|
|
from datetime import datetime
|
|
from app.utils.time import utcnow
|
|
from flask import Blueprint, render_template, jsonify, Response, request
|
|
|
|
main_bp = Blueprint("main", __name__)
|
|
|
|
|
|
@main_bp.route("/")
|
|
def index():
|
|
return render_template("index.html")
|
|
|
|
|
|
@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 > 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 > 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 > utcnow())
|
|
.order_by(Listing.created_at.desc())
|
|
.limit(20).all())
|
|
return render_template("main/state_landing.html", state=state, listings=listings)
|