diff --git a/.dedupe/index.sqlite b/.dedupe/index.sqlite new file mode 100644 index 0000000..d2fa618 Binary files /dev/null and b/.dedupe/index.sqlite differ diff --git a/.dedupe/report.csv b/.dedupe/report.csv new file mode 100644 index 0000000..8056de2 --- /dev/null +++ b/.dedupe/report.csv @@ -0,0 +1 @@ +group_id,canonical_path,dup_path,dup_size_bytes diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fd3ded5 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# Copy to .env and fill in values + +# WordPress base URL (required) +WP_BASE_URL=https://your-site.tld + +# Authentication: prefer WP_AUTH_BASE64 OR use USERNAME+PASSWORD (Application Password) +# Example to generate: base64(username:application_password) +WP_AUTH_BASE64= + +# Alternatively provide username and application password +WP_USERNAME= +WP_PASSWORD= + +# OpenAI API key (optional, enables rewrite) +OPENAI_API_KEY= + diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5d55808..af3394f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,9 +19,16 @@ jobs: username: oliver key: ${{ secrets.HETZNER_SSH_KEY }} port: 22 + envs: APP_ADMIN_USERNAME,APP_ADMIN_PASSWORD script: | - cd rss-news + cd /opt/rss-news git pull origin main source .venv/bin/activate pip install -r requirements.txt - sudo systemctl restart rss-app + pip install -r backend/requirements.txt || true + sudo systemctl restart rss-news-api + sleep 3 + BASE_URL="https://news.vanityontour.de" APP_ADMIN_USERNAME="${APP_ADMIN_USERNAME}" APP_ADMIN_PASSWORD="${APP_ADMIN_PASSWORD}" bash scripts/smoke_backend.sh + env: + APP_ADMIN_USERNAME: ${{ secrets.NEWS_APP_ADMIN_USERNAME }} + APP_ADMIN_PASSWORD: ${{ secrets.NEWS_APP_ADMIN_PASSWORD }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..1d627db --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,39 @@ +name: Backend Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + backend-tests: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r backend/requirements.txt + pip install -r backend/requirements-test.txt + + - name: Run tests with coverage + env: + APP_DB_PATH: /tmp/rss_news_test.db + run: | + pytest backend/tests --cov=backend/app --cov-report=term-missing --cov-report=xml + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-xml + path: coverage.xml diff --git a/.gitignore b/.gitignore index d714f32..aac3a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ internal/start.sh internal/copy_files.sh internal/_line.txt internal/push_commit.txt +internal/git.sh +CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7251de6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,40 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `app.py`: Streamlit UI (entry point for the app). +- `main.py`: RSS fetching, rewrite, and WordPress upload logic. +- `utils/`: Helpers (image/article extraction, WP uploader, UI helpers). +- `pages/`: Streamlit pages (e.g., `01_feed_manager.py`, `log_viewer.py`). +- `data/`: JSON state (`articles.json`, `feeds.json`). +- `logs/`: Runtime logs (`rss_tool.log`). +- `docs/`: Project notes (e.g., roadmap). +- `__version__.py`: Version string written by `versioning.py`. + +## Build, Test, and Development Commands +- Create env: `python -m venv .venv && source .venv/bin/activate` +- Install deps: `pip install -r requirements.txt` +- Run app: `streamlit run app.py` +- Version bump: `python versioning.py --level patch --push` (updates `__version__.py`, prepares `CHANGELOG.md`, creates tag; see `--help`). + +## Coding Style & Naming Conventions +- Python 3.10+, PEP 8, 4-space indentation, type hints where practical. +- Modules and functions: `snake_case`; classes: `PascalCase`. +- Streamlit pages: numeric prefix for order, e.g., `pages/01_feature.py`. +- Keep functions small and pure in `utils/`; isolate I/O in app layers. +- Suggested tools (optional): Black (`black .`) and Ruff (`ruff check .`). + +## Testing Guidelines +- Framework: pytest (recommended). Place tests under `tests/` with `test_*.py`. +- Unit tests for `utils/*`; light integration checks for `main.py` with temporary files. +- Run: `pytest -q`. Add coverage if needed (e.g., `pytest --cov=utils`). +- Test data: avoid mutating files in `data/`; use temp dirs or fixtures. + +## Commit & Pull Request Guidelines +- Commits: imperative mood, concise; examples: `Add feed dedupe`, `Fix WP upload retry`, `Bump version to v1.7.0`. +- PRs: clear description, linked issue, screenshots/GIFs for UI changes, note env variables touched. +- Update `CHANGELOG.md` and bump version via `versioning.py` before release PRs. + +## Security & Configuration Tips +- Required env: `OPENAI_API_KEY`, `WP_BASE_URL`, `WP_USERNAME`, `WP_PASSWORD` or `WP_AUTH_BASE64` (see `.env`). +- Never commit secrets; `.env` is git-ignored. Avoid hardcoded credentials; prefer `os.getenv`. +- Logs and data may contain content; do not commit `logs/` or large `data/` snapshots. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8d5df..66b7237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +## [1.7.1] - 2025-08-24 + +### ✨ Security angepasst + - alle Credentials in die .env Datei verschoben + - beim Start der App werden die Credentials geprüft und beim fehlen entsprechende Meldungen ausgegeben + +--- + +## [1.7.0] - 2025-08-24 + +### Multi-Select & Massenoperationen: + - ✅ Checkboxes für Artikel-Auswahl im "Artikel verwalten" Bereich + - ✅ "Alle auswählen" / "Auswahl aufheben" Buttons + - ✅ Massenoperationen für ausgewählte Artikel: + - Bulk Status-Änderung für mehrere Artikel gleichzeitig + - Bulk Artikel-Umschreibung mit automatischer Status-Verwaltung + - Bulk WordPress-Upload nur für "Process"-Artikel + - Bulk Papierkorb-Funktion + +### Schnellaktionen Integration: + - ✅ Feed-Aktualisierung direkt im Artikel-Tab verfügbar + - ✅ Alle Dashboard-Schnellaktionen in Artikel-Verwaltung integriert + - ✅ Intelligente Anzeige nur relevanter Operationen (z.B. WordPress-Upload nur bei Process-Artikeln) + +### 🔧 Verbesserungen + + - UI/UX: Verbesserte Artikel-Card-Layouts mit Checkbox-Integration + - Workflow: Streamlined Artikel-Management ohne Tab-Wechsel nötig + - Feedback: Detaillierte Statusmeldungen bei Massenoperationen + - Performance: Optimierte Session-State-Verwaltung für Artikel-Auswahl + +### 🏗️ Technische Änderungen + + - Session State Erweiterung um selected_articles Set + - Neue Bulk-Operation-Funktionen in app.py:326-467 + - Überarbeitetes Artikel-Card-Layout mit 3-Spalten-Design + - Integration bestehender WordPress-Upload und Rewrite-Funktionen + +--- + +## [1.6.3] - 2025-08-18 + +### 🔧 Verbesserungen +- **SyleSheet erneut hinzugefügt + - Style wurde bei einem Release leider vergessen + - Style auf DarkMode angepasst + +--- + ## [v1.6.2] - 2025-08-16 ### 🐛 Kritische Fehlerbehebung diff --git a/README.md b/README.md index 0f3d86c..b3c2b4a 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,63 @@ -# 📰 RSS News Bot +# rss-news (Rebuild) -Ein intelligentes Tool zum Einlesen, Umschreiben und Veröffentlichen von Artikeln aus RSS-Feeds – mit automatischer Tag-Erkennung, KI-unterstütztem Rewrite via GPT-4, Bildextraktion aus Originalartikeln und optionaler DALL·E-Bildgenerierung. +`rss-news` wird als bestehendes Repository weitergefuehrt und schrittweise zu einer robusten, rechtssicheren News-Pipeline neu aufgebaut. - - - - +Aktueller Stand: +- Alte Streamlit-App wird nicht produktiv genutzt. +- `news.vanityontour.de` wird bis zum Go-Live der neuen App auf `https://vanityontour.de` umgeleitet. +- Planung, Doku und Wiki werden als Grundlage fuer den Neuaufbau gepflegt. ---- +## Ziele +- RSS-gestuetzte Artikelverarbeitung mit klaren Quellregeln +- Rechtssichere Nutzung (Quellen, Attribution, Lizenzinformationen) +- Zuverlaessige Automatisierung auf Hetzner +- Publikation nach WordPress (IONOS aktuell, spaeter offen) +- Zugriff nur nach Login (zunaechst User/Password) -## 🚀 Features +## Architektur-Richtung (MVP) +- Backend: `Python + FastAPI` +- Jobs: Queue-Worker (z. B. Redis + RQ/Celery) +- Daten: SQLite fuer MVP, spaeter optional PostgreSQL +- Auth: Session-Login mit einem Admin-User +- Publishing: WordPress REST API (Status zunaechst `pending`) -- 📡 **RSS-Feeds verwalten** (hinzufügen, aktualisieren) -- ✍️ **Artikel automatisch umschreiben** mit GPT-4 -- 🏷️ **Tags automatisch generieren** -- 🖼️ **Bilder aus Originalartikeln extrahieren** -- 🪄 **Optionales DALL·E-Bild generieren** -- 🔧 **Bearbeiten von Bildmetadaten** -- 🗂️ **Statusverwaltung der Artikel (New, Rewrite, Process, etc.)** -- 📜 **Log-Viewer-Seite integriert** -- 📥 **Export zur Veröffentlichung auf WordPress vorbereitet** -- 📋 Artikeltabelle mit Status-Filter -- 🔍 Artikel-Expander mit Rewrite, Tags & Bildern -- 🪄 Button für KI-Bildgenerierung +Details: `docs/PROJECT_PLAN.md` +## Projektsteuerung +- GitHub Project: `https://github.com/users/OliverGiertz/projects/3/views/1` +- Dieses Board ist die zentrale Steuerung fuer ToDos, Bugs, Verbesserungen. +- Wiki-Struktur liegt unter `docs/wiki/`. ---- +## Dokumentation +- Projektplan: `docs/PROJECT_PLAN.md` +- ToDo-Liste: `docs/TODO.md` +- Quell- und Lizenzpolicy: `docs/SOURCE_POLICY.md` +- Wiki Home: `docs/wiki/Home.md` -## 🧱 Projektstruktur - -ss-news/ -├── app.py # Haupt-UI mit Streamlit -├── main.py # Logik für Feed-Import und Verarbeitung -├── utils/ -│ └── image_extractor.py # Bilder aus Originalartikeln extrahieren -│ └── dalle_generator.py # DALL·E-Integration (KI-Bild) -├── pages/ -│ └── log_viewer.py # UI zur Anzeige der Logs -├── data/ -│ └── articles.json # Gespeicherte Artikel -│ └── feeds.json # Gespeicherte Feed-URLs -├── logs/ -│ └── rss_tool.log # Logging der Verarbeitung -├── versioning.py # CLI-Tool zur Versionierung & Release -├── TEST-CHECKLIST.md # Manuelle Prüfliste für Releases -├── version.py # Aktuelle Version -└── CHANGELOG.md # Änderungsprotokoll - - ---- - -## ⚙️ Installation +## Lokale Entwicklung (Legacy-Code) +Der vorhandene Legacy-Stand kann weiterhin lokal gestartet werden: ```bash -git clone https://github.com/OliverGiertz/rss-news.git -cd rss-news python -m venv .venv source .venv/bin/activate pip install -r requirements.txt -``` - ---- - -## Update -Ein Update Script findest du hier: https://gist.github.com/OliverGiertz/ad33ae3de9aa1c1163dad5fe8affb6ca - -```bash -bash update.sh -``` - - -## ▶️ Starten der App - streamlit run app.py +``` + +Hinweis: Diese App ist funktional historisch und wird durch die neue Architektur ersetzt. + +## Deployment-Zielbild +- Betrieb auf Hetzner +- Reverse Proxy via CloudPanel/Nginx +- Produktive Domain: `news.vanityontour.de` +- Bis zur Fertigstellung: Redirect auf `https://vanityontour.de` + +## Sicherheit +- Keine Secrets im Repository +- `.env` lokal/auf Server, nie committen +- Auth-Pflicht fuer die neue WebApp +- spaeter optional: Passkeys/WebAuthn + +## Rechtlicher Hinweis +Dieses Projekt verarbeitet nur Quellen mit dokumentierter Nutzungsgrundlage. Vor produktiver Nutzung ist eine finale rechtliche Pruefung der ausgewaehlten Feeds notwendig. diff --git a/__version__.py b/__version__.py index c8a19b1..6a6d0f8 100644 --- a/__version__.py +++ b/__version__.py @@ -1 +1 @@ -VERSION = "1.6.2" +VERSION = "1.7.1" diff --git a/app.py b/app.py index 0296f0b..f161a65 100644 --- a/app.py +++ b/app.py @@ -13,6 +13,8 @@ from main import ( ) from utils.dalle_generator import generate_dalle_image from utils.wordpress_uploader import WordPressUploader +from utils.css_loader import load_css, apply_dark_theme +from utils.config import validate_env import os from collections import Counter import time @@ -24,103 +26,22 @@ st.set_page_config( initial_sidebar_state="collapsed" ) -# === Custom CSS für modernes Design === -st.markdown(""" - -""", unsafe_allow_html=True) +# === CSS & Theme laden === +load_css() +apply_dark_theme() + +# === Environment-Validierung (.env) === +env_check = validate_env() +if not env_check.get("ok"): + st.error("🔒 Sicherheits-/Konfigurationshinweis: Bitte .env korrekt konfigurieren.") + for msg in env_check.get("errors", []): + st.markdown(f"- ❌ {msg}") + for msg in env_check.get("warnings", []): + st.markdown(f"- ⚠️ {msg}") +elif env_check.get("warnings"): + st.info("ℹ️ Hinweise zur Konfiguration:") + for msg in env_check.get("warnings", []): + st.markdown(f"- ⚠️ {msg}") # === Initialize Session State === if 'selected_articles' not in st.session_state: @@ -340,9 +261,8 @@ with tab1:
Basic-Auth mit Base64-kodierten Zugangsdaten:Authorization: Basic <base64(username:password)>WP_AUTH_BASE64 setzen (aus username:application_password erzeugt).WP_USERNAME und WP_PASSWORD gesetzt werden; dann wird Base64 zur Laufzeit generiert.
+ edit_posts - Beiträge erstellen und bearbeitenpublish_posts - Beiträge veröffentlichen (für Status-Änderungen)upload_files - Dateien hochladen (für spätere Bild-Uploads)edit_categories - Kategorien verwaltenedit_tags - Tags verwalten
+ ,