homepage
This commit is contained in:
@@ -233,5 +233,10 @@ async def search(q: str, _: None = Depends(require_access)):
|
||||
return await notes.search_notes(q)
|
||||
|
||||
|
||||
@app.get("/api/homepage")
|
||||
async def homepage_stats(_: None = Depends(require_access)):
|
||||
return await notes.get_homepage_stats()
|
||||
|
||||
|
||||
# Mount static assets last so /api routes take precedence
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
@@ -346,6 +346,36 @@ async def _record_history(
|
||||
)
|
||||
|
||||
|
||||
async def get_homepage_stats() -> dict:
|
||||
from pathlib import Path
|
||||
|
||||
async with aiosqlite.connect(settings.database_path) as db:
|
||||
db.row_factory = aiosqlite.Row
|
||||
|
||||
async def count(query: str) -> int:
|
||||
row = await db.execute(query)
|
||||
row = await row.fetchone()
|
||||
return row[0]
|
||||
|
||||
total_notes = await count("SELECT COUNT(*) FROM notes WHERE deleted_at IS NULL")
|
||||
actions = await count("SELECT COUNT(*) FROM history")
|
||||
users = await count("SELECT COUNT(*) FROM users")
|
||||
|
||||
attachments = 0
|
||||
data_root = Path(settings.data_dir)
|
||||
if data_root.is_dir():
|
||||
for attach_dir in data_root.rglob("attachments"):
|
||||
if attach_dir.is_dir():
|
||||
attachments += sum(1 for f in attach_dir.iterdir() if f.is_file())
|
||||
|
||||
return {
|
||||
"total_notes": total_notes,
|
||||
"attachments": attachments,
|
||||
"actions": actions,
|
||||
"users": users,
|
||||
}
|
||||
|
||||
|
||||
async def get_history(note_id: str) -> list[dict]:
|
||||
async with aiosqlite.connect(settings.database_path) as db:
|
||||
db.row_factory = aiosqlite.Row
|
||||
|
||||
27
extras/homepage-widget.yaml
Normal file
27
extras/homepage-widget.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
# Paste this into /opt/homepage/config/services.yaml as a new entry.
|
||||
#
|
||||
# Replace {{ SNOTES_URL }} with where snotes is reachable, e.g.
|
||||
# http://192.168.1.45:8019 (host mapped port)
|
||||
|
||||
- Snotes:
|
||||
icon: snotes-main.png
|
||||
href: "{{ SNOTES_URL }}"
|
||||
description: Markdown notes
|
||||
widget:
|
||||
type: customapi
|
||||
url: "{{ SNOTES_URL }}/api/homepage"
|
||||
refreshInterval: 60000
|
||||
display: block
|
||||
mappings:
|
||||
- field: total_notes
|
||||
label: Notes
|
||||
format: number
|
||||
- field: attachments
|
||||
label: Attachments
|
||||
format: number
|
||||
- field: actions
|
||||
label: Actions
|
||||
format: number
|
||||
- field: users
|
||||
label: Users
|
||||
format: number
|
||||
@@ -153,6 +153,24 @@ async def test_history_recorded(client):
|
||||
assert history[0]["ip"] == "192.168.1.5"
|
||||
|
||||
|
||||
async def test_homepage_stats(client):
|
||||
await client.post("/api/notes", json={"body": "note one"})
|
||||
await client.post("/api/notes", json={"body": "note two"})
|
||||
await client.post(
|
||||
"/api/attachments",
|
||||
files={"file": ("a.png", b"abc", "image/png")},
|
||||
data={"username": "schmeeve"},
|
||||
)
|
||||
|
||||
r = await client.get("/api/homepage")
|
||||
assert r.status_code == 200
|
||||
stats = r.json()
|
||||
assert stats["total_notes"] == 2
|
||||
assert stats["attachments"] == 1
|
||||
assert stats["actions"] == 2
|
||||
assert stats["users"] == 3
|
||||
|
||||
|
||||
async def test_user_selection_cookie(client):
|
||||
r = await client.post("/api/users/select", json={"username": "ilya"})
|
||||
assert r.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user