diff --git a/run-reports.sh b/run-reports.sh index 6a666be..ade36c6 100755 --- a/run-reports.sh +++ b/run-reports.sh @@ -32,6 +32,9 @@ python scripts/generate_reports.py daily --all-domains python scripts/generate_reports.py weekly --all-domains python scripts/generate_reports.py monthly --all-domains +# Generate root index +python scripts/generate_reports.py index + # Deactivate to keep cron environment clean if type deactivate >/dev/null 2>&1; then deactivate diff --git a/scripts/generate_reports.py b/scripts/generate_reports.py index 2a7eb73..6118978 100644 --- a/scripts/generate_reports.py +++ b/scripts/generate_reports.py @@ -128,6 +128,26 @@ def _generate_all_domains(interval: str) -> None: _generate_interval(interval, domain) +def _generate_root_index() -> None: + """Render the top-level index listing all intervals and domains.""" + intervals = [p.name for p in OUTPUT_DIR.iterdir() if p.is_dir() and p.name != "domains"] + intervals.sort() + + domains_dir = OUTPUT_DIR / "domains" + domains: List[str] = [] + if domains_dir.is_dir(): + domains = [p.name for p in domains_dir.iterdir() if p.is_dir()] + domains.sort() + + env = Environment(loader=FileSystemLoader(TEMPLATE_DIR)) + template = env.get_template("index.html") + + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + out_path = OUTPUT_DIR / "index.html" + out_path.write_text(template.render(intervals=intervals, domains=domains)) + typer.echo(f"Generated root index at {out_path}") + + @app.command() def hourly( domain: Optional[str] = typer.Option( @@ -192,5 +212,11 @@ def monthly( _generate_interval("monthly", domain) +@app.command() +def index() -> None: + """Generate the root index page linking all reports.""" + _generate_root_index() + + if __name__ == "__main__": app() diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..5273079 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,65 @@ + + + + + ngxstat Reports + + + +
+

ngxstat Reports

+
+
+ +
+
+ +
+
+
+ + + + diff --git a/tests/test_reports.py b/tests/test_reports.py index 3b4ef35..5a1deef 100644 --- a/tests/test_reports.py +++ b/tests/test_reports.py @@ -125,3 +125,36 @@ def test_generate_interval_domain_filter(tmp_path, sample_reports, monkeypatch): (tmp_path / "output" / "domains" / "example.com" / "hourly" / "hits.json").read_text() ) assert hits[0]["value"] == 2 + + +def test_generate_root_index(tmp_path, sample_reports, monkeypatch): + db_path = tmp_path / "database" / "ngxstat.db" + setup_db(db_path) + + monkeypatch.setattr(gr, "DB_PATH", db_path) + monkeypatch.setattr(gr, "OUTPUT_DIR", tmp_path / "output") + monkeypatch.setattr(gr, "REPORT_CONFIG", sample_reports) + monkeypatch.setattr( + gr, "TEMPLATE_DIR", Path(__file__).resolve().parents[1] / "templates" + ) + + gr._generate_interval("hourly") + gr._generate_interval("daily") + + # create dummy domain directories + (tmp_path / "output" / "domains" / "foo.com").mkdir(parents=True) + (tmp_path / "output" / "domains" / "bar.com").mkdir(parents=True) + + gr._generate_root_index() + + index_file = tmp_path / "output" / "index.html" + assert index_file.exists() + content = index_file.read_text() + + # check for interval links + assert 'data-interval="hourly"' in content + assert 'data-interval="daily"' in content + + # check for domain links + assert 'data-domain="foo.com"' in content + assert 'data-domain="bar.com"' in content