Fix article quantity bug and session timeout
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 1m38s

- Fixed article quantity handling in packing lists (drag and drop).

- Resolved 'headers already sent' bug in backpacks.php.

- Increased PHP session timeout to 24 hours via .htaccess.

- Synced .gitea/workflows/build-push.yaml template.
This commit is contained in:
Gemini Agent
2026-05-11 14:16:26 +00:00
parent 7744168d0d
commit 02f7e2b059
5 changed files with 42 additions and 27 deletions

View File

@@ -1,58 +1,47 @@
name: Docker Build & Push
run-name: ${{ gitea.actor }} zwingt es zum Laufen 🔨
run-name: ${{ gitea.actor }} flucht, aber baut 🔨
on:
push:
branches:
- main
- master
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
# -----------------------------------------------------------
# 1. DER NETZWERK-RETTER (MUSS WIEDER REIN!)
# Ersetzt "gitea:3000" durch die IP, damit der Container es findet.
# -----------------------------------------------------------
# 1. DER FIX (Mit dem automatischen Gitea-Token)
# ${{ gitea.token }} hat IMMER Zugriff auf das Repo, in dem der Job läuft.
- name: Fix Git URL Resolution
run: git config --global url."http://172.30.1.213/".insteadOf "http://gitea:3000/"
run: git config --global url."http://${{ gitea.token }}@172.30.1.213/".insteadOf "http://gitea:3000/"
# 2. Checkout (Klappt jetzt, weil URL umgebogen wird)
# 2. Checkout
- name: Checkout Code
uses: actions/checkout@v3
# 3. Login (Mit dem globalen Token aus deinen User-Settings)
# 3. Docker Login (Hier nehmen wir weiterhin deinen Runner-Token oder den Actor)
# Wenn der Login fehlschlägt, dann hat dein User keine Schreibrechte auf Packages.
# Aber probier erst mal Checkout.
- name: Login bei Registry
run: docker login 172.30.1.213 -u ${{ gitea.actor }} -p ${{ secrets.TOKEN_RUNNER }}
# 4. Feuer frei
# 4. Bauen
- name: Build & Push
run: |
REPO_LOWER=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
IMAGE_TAG="172.30.1.213/$REPO_LOWER:latest"
echo "Baue Image: $IMAGE_TAG"
docker build -t $IMAGE_TAG .
docker push $IMAGE_TAG
# 5. Node-RED
- name: Webhook an Node-RED
if: always()
run: |
# Status setzen
if [ "${{ job.status }}" == "success" ]; then
STATUS="success"
else
STATUS="failed"
fi
# JSON Payload basteln
# Wir nutzen printf, um sauberes JSON zu bauen
JSON_DATA=$(printf '{"status": "%s", "repo": "%s", "actor": "%s"}' "$STATUS" "${{ gitea.repository }}" "${{ gitea.actor }}")
# Abfeuern an Node-RED
curl -v -H "Content-Type: application/json" \
-X POST \
-d "$JSON_DATA" \
http://172.30.80.246:1880/gitea-status
curl -v -H "Content-Type: application/json" -X POST -d "$JSON_DATA" http://172.30.80.246:1880/gitea-status

View File

@@ -206,3 +206,9 @@ Das Projekt basiert auf bewährten Web-Standards:
* `packliste.sql` aktualisiert.
* Anzeige-Probleme bei Dropdowns behoben.
* SQL-Fehler in der Statistik-Berechnung korrigiert.
### 11.05.2026
* **Fixes:**
* Fehler bei der Artikelanzahl behoben: Wenn ein Artikel mehrfach im Bestand vorhanden ist (z.B. 5 Stück), verschwindet er nicht mehr aus der Auswahlliste, nachdem das erste Stück in einen Rucksack gezogen wurde.
* Bugfix für Session-Timeouts ("Headers already sent"): Die PHP-Sitzung wird nun korrekt überprüft und verarbeitet, bevor HTML-Header gesendet werden (z.B. in `backpacks.php`).
* Session Timeout (Ausloggen) auf 24 Stunden verlängert (per `.htaccess`).

3
src/.htaccess Normal file
View File

@@ -0,0 +1,3 @@
php_value session.gc_maxlifetime 86400
php_value session.cookie_lifetime 86400
php_value session.cache_expire 86400

View File

@@ -2,13 +2,18 @@
// backpacks.php - Verwaltung der Rucksäcke
$page_title = "Rucksäcke";
require_once 'db_connect.php';
require_once 'header.php';
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit;
}
require_once 'header.php';
$user_id = $_SESSION['user_id'];
$message = '';

View File

@@ -286,11 +286,23 @@ $conn->close();
const filterCategory = document.getElementById('filter-category').value;
const filterManufacturer = document.getElementById('filter-manufacturer').value;
const availableListEl = document.getElementById('available-items-list');
const packedArticleIds = packedItems.map(item => String(item.article_id));
const packedQuantities = {};
packedItems.forEach(item => {
const aid = String(item.article_id);
packedQuantities[aid] = (packedQuantities[aid] || 0) + parseInt(item.quantity || 1, 10);
});
let html = '';
allArticles.forEach(article => {
if (article.parent_article_id) return;
if (article.consumable == 1 || !packedArticleIds.includes(String(article.id))) {
const aid = String(article.id);
const packedQty = packedQuantities[aid] || 0;
const ownedQty = parseInt(article.quantity_owned || 1, 10);
const isConsumable = article.consumable == 1;
if (isConsumable || packedQty < ownedQty) {
const matchesText = article.name.toLowerCase().includes(filterText) || (article.manufacturer_name && article.manufacturer_name.toLowerCase().includes(filterText)) || (article.product_designation && article.product_designation.toLowerCase().includes(filterText));
const matchesCategory = !filterCategory || article.category_name === filterCategory;
const matchesManufacturer = !filterManufacturer || article.manufacturer_name === filterManufacturer;