add autokanban
This commit is contained in:
parent
b05d8a8ab3
commit
745bf9a29a
9 changed files with 181 additions and 3 deletions
31
README.md
31
README.md
|
|
@ -27,6 +27,7 @@
|
||||||
- **📓 JupyterHub**: Multi-user Jupyter notebook server for drone programming (port 8001)
|
- **📓 JupyterHub**: Multi-user Jupyter notebook server for drone programming (port 8001)
|
||||||
- **🦊 Forgejo**: Self-hosted Git service for code collaboration (port 3003)
|
- **🦊 Forgejo**: Self-hosted Git service for code collaboration (port 3003)
|
||||||
- **🔄 Watchtower**: Automatic container updates every 24 hours
|
- **🔄 Watchtower**: Automatic container updates every 24 hours
|
||||||
|
- **🗂️ Autokanban**: Kollektive To‑Do‑Liste / Aufgabenboard (port 8000)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -132,6 +133,7 @@ graph TB
|
||||||
- **curl** - for testing and healthchecks (install: `brew install curl` on macOS)
|
- **curl** - for testing and healthchecks (install: `brew install curl` on macOS)
|
||||||
- **Poppler** (for pdf2image - included in Docker)
|
- **Poppler** (for pdf2image - included in Docker)
|
||||||
- **Port availability**: 80, 3003, 6875, 8001, 8008, 8080, 8082, 9000, 11434
|
- **Port availability**: 80, 3003, 6875, 8001, 8008, 8080, 8082, 9000, 11434
|
||||||
|
- **Port availability**: 80, 3003, 6875, 8000, 8001, 8008, 8080, 8082, 9000, 11434
|
||||||
|
|
||||||
**Note:** Python dependencies are containerized and don't need to be installed on the host.
|
**Note:** Python dependencies are containerized and don't need to be installed on the host.
|
||||||
|
|
||||||
|
|
@ -164,9 +166,9 @@ graph TB
|
||||||
- Portainer: <http://localhost:9000>
|
- Portainer: <http://localhost:9000>
|
||||||
- Matrix: <http://localhost:8008>
|
- Matrix: <http://localhost:8008>
|
||||||
- Element Web: <http://localhost:8082>
|
- Element Web: <http://localhost:8082>
|
||||||
|
- Autokanban: <http://localhost:8000>
|
||||||
- JupyterHub: <http://localhost:8001>
|
- JupyterHub: <http://localhost:8001>
|
||||||
- Forgejo: <http://localhost:3003>
|
- Forgejo: <http://localhost:3003>
|
||||||
- Forgejo: <http://localhost:3003>
|
|
||||||
|
|
||||||
### First-Time Setup
|
### First-Time Setup
|
||||||
|
|
||||||
|
|
@ -339,7 +341,32 @@ Creates timestamped backups of:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚢 Deployment & Portability
|
## <20> BookStack API (create pages programmatically)
|
||||||
|
|
||||||
|
You can automate content creation in BookStack using the HTTP API and a Personal Access Token (User Settings → API Tokens).
|
||||||
|
|
||||||
|
Example `curl` to list books:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: Token token=\"$BOOKSTACK_API_TOKEN\"" \
|
||||||
|
"$BOOKSTACK_APP_URL/api/books"
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a page with `curl`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Authorization: Token token=\"$BOOKSTACK_API_TOKEN\"" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"My Page","book_id":1,"html":"<h1>Hello</h1>"}' \
|
||||||
|
"$BOOKSTACK_APP_URL/api/pages"
|
||||||
|
```
|
||||||
|
|
||||||
|
There's a small helper script in the repo: `bookstack_api_create_page.py` which demonstrates listing books and creating a page interactively.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## <20>🚢 Deployment & Portability
|
||||||
|
|
||||||
This application is designed to be **fully portable**. To move to a new server:
|
This application is designed to be **fully portable**. To move to a new server:
|
||||||
|
|
||||||
|
|
|
||||||
97
bookstack_api_create_page.py
Normal file
97
bookstack_api_create_page.py
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Small helper to demonstrate creating a BookStack page via the BookStack HTTP API.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
- Create a Personal Access Token in BookStack (User Settings → API Tokens).
|
||||||
|
- Add the token and app URL to your `.env` or export env vars:
|
||||||
|
BOOKSTACK_APP_URL=http://124.local:6875
|
||||||
|
BOOKSTACK_API_TOKEN=your_token_here
|
||||||
|
- Run: python bookstack_api_create_page.py
|
||||||
|
|
||||||
|
This script will list available books and create a page in the chosen book.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
try:
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
BOOKSTACK_APP_URL = os.environ.get("BOOKSTACK_APP_URL")
|
||||||
|
BOOKSTACK_API_TOKEN = os.environ.get("BOOKSTACK_API_TOKEN")
|
||||||
|
|
||||||
|
if not BOOKSTACK_APP_URL or not BOOKSTACK_API_TOKEN:
|
||||||
|
print("Please set BOOKSTACK_APP_URL and BOOKSTACK_API_TOKEN in the environment or .env file.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def auth_headers():
|
||||||
|
# BookStack expects: Authorization: Token token="<token>"
|
||||||
|
return {
|
||||||
|
"Authorization": f'Token token="{BOOKSTACK_API_TOKEN}"',
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def list_books():
|
||||||
|
url = urljoin(BOOKSTACK_APP_URL, "/api/books")
|
||||||
|
r = requests.get(url, headers=auth_headers(), timeout=10)
|
||||||
|
r.raise_for_status()
|
||||||
|
data = r.json()
|
||||||
|
return data.get("data", [])
|
||||||
|
|
||||||
|
|
||||||
|
def create_page(book_id: int, name: str, html: str):
|
||||||
|
url = urljoin(BOOKSTACK_APP_URL, "/api/pages")
|
||||||
|
payload = {
|
||||||
|
"name": name,
|
||||||
|
"book_id": book_id,
|
||||||
|
"html": html,
|
||||||
|
"markdown": None,
|
||||||
|
"draft": False,
|
||||||
|
}
|
||||||
|
r = requests.post(url, headers=auth_headers(), data=json.dumps(payload), timeout=10)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Using BookStack: {BOOKSTACK_APP_URL}")
|
||||||
|
books = list_books()
|
||||||
|
if not books:
|
||||||
|
print("No books found. Create a book in BookStack first or verify token permissions.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Available books:")
|
||||||
|
for i, b in enumerate(books):
|
||||||
|
print(f" [{i}] {b.get('name')} (id={b.get('id')})")
|
||||||
|
|
||||||
|
choice = input("Choose a book index to create the page in (default 0): ") or "0"
|
||||||
|
try:
|
||||||
|
idx = int(choice)
|
||||||
|
except ValueError:
|
||||||
|
idx = 0
|
||||||
|
|
||||||
|
book = books[idx]
|
||||||
|
book_id = book.get("id")
|
||||||
|
|
||||||
|
title = input("Page title: ") or "Automated Page"
|
||||||
|
content = input("Simple HTML content (or leave empty for a sample): ")
|
||||||
|
if not content:
|
||||||
|
content = f"<h2>{title}</h2><p>Created automatically via API.</p>"
|
||||||
|
|
||||||
|
resp = create_page(book_id, title, content)
|
||||||
|
print("Created page:")
|
||||||
|
print(json.dumps(resp, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Binary file not shown.
|
|
@ -1 +1 @@
|
||||||
MANIFEST-000004
|
MANIFEST-000014
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,48 @@
|
||||||
14:41:11.539093 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
14:41:11.539093 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
14:41:11.543912 db@janitor F·3 G·0
|
14:41:11.543912 db@janitor F·3 G·0
|
||||||
14:41:11.543982 db@open done T·6.225416ms
|
14:41:11.543982 db@open done T·6.225416ms
|
||||||
|
=============== Nov 12, 2025 (CET) ===============
|
||||||
|
09:57:26.179138 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||||
|
09:57:26.186435 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:57:26.191524 db@open opening
|
||||||
|
09:57:26.194711 journal@recovery F·1
|
||||||
|
09:57:26.195667 journal@recovery recovering @3
|
||||||
|
09:57:26.197988 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:57:26.216087 db@janitor F·3 G·0
|
||||||
|
09:57:26.217023 db@open done T·24.267292ms
|
||||||
|
=============== Nov 22, 2025 (CET) ===============
|
||||||
|
10:01:25.477377 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||||
|
10:01:25.477990 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
10:01:25.478025 db@open opening
|
||||||
|
10:01:25.478154 journal@recovery F·1
|
||||||
|
10:01:25.478214 journal@recovery recovering @5
|
||||||
|
10:01:25.478556 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
10:01:25.480013 db@janitor F·3 G·0
|
||||||
|
10:01:25.480040 db@open done T·1.995458ms
|
||||||
|
=============== Nov 27, 2025 (CET) ===============
|
||||||
|
09:57:27.459640 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||||
|
09:57:27.463226 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:57:27.463855 db@open opening
|
||||||
|
09:57:27.464798 journal@recovery F·1
|
||||||
|
09:57:27.465256 journal@recovery recovering @7
|
||||||
|
09:57:27.472782 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:57:27.511286 db@janitor F·3 G·0
|
||||||
|
09:57:27.511538 db@open done T·47.508458ms
|
||||||
|
=============== Nov 27, 2025 (CET) ===============
|
||||||
|
09:58:40.940724 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||||
|
09:58:40.944445 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:58:40.945532 db@open opening
|
||||||
|
09:58:40.946059 journal@recovery F·1
|
||||||
|
09:58:40.946299 journal@recovery recovering @9
|
||||||
|
09:58:40.951856 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
09:58:40.957677 db@janitor F·3 G·0
|
||||||
|
09:58:40.958035 db@open done T·12.392458ms
|
||||||
|
=============== Nov 27, 2025 (CET) ===============
|
||||||
|
10:01:13.275972 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
|
||||||
|
10:01:13.278440 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
10:01:13.278524 db@open opening
|
||||||
|
10:01:13.278925 journal@recovery F·1
|
||||||
|
10:01:13.279002 journal@recovery recovering @11
|
||||||
|
10:01:13.279809 version@stat F·[1] S·542B[542B] Sc·[0.25]
|
||||||
|
10:01:13.283533 db@janitor F·3 G·0
|
||||||
|
10:01:13.283640 db@open done T·4.933416ms
|
||||||
|
|
|
||||||
Binary file not shown.
BIN
forgejo/data/gitea/queues/common/MANIFEST-000014
Normal file
BIN
forgejo/data/gitea/queues/common/MANIFEST-000014
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -102,6 +102,15 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<a class="link-card" href="http://autokanban.local:8000" target="_blank">
|
||||||
|
<i class="fas fa-tasks card-icon"></i>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="title">Autokanban</div>
|
||||||
|
<div class="tagline">Kollektive To‑Do‑Liste: Jede*r kann Aufgaben posten und lösen. Für das Lösen
|
||||||
|
von Aufgaben gibt es Badges — sammle Anerkennung für deinen Beitrag!</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a class="link-card" href="mailto:einszwovier@gvb-gymnasium.de" target="_blank">
|
<a class="link-card" href="mailto:einszwovier@gvb-gymnasium.de" target="_blank">
|
||||||
<i class="fas fa-envelope card-icon"></i>
|
<i class="fas fa-envelope card-icon"></i>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue