Script erstellt

This commit is contained in:
Housemann 2025-08-10 18:09:07 +02:00
commit 2a15995cbb
196 changed files with 24790 additions and 0 deletions

18
.editorconfig Normal file
View File

@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

65
.env.example Normal file
View File

@ -0,0 +1,65 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"

11
.gitattributes vendored Normal file
View File

@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
*.log
.DS_Store
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.fleet
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
Homestead.json
Homestead.yaml
Thumbs.db

30
.htaccess Normal file
View File

@ -0,0 +1,30 @@
# Redirect to public directory
RewriteEngine On
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
# Prevent directory listing
Options -Indexes
# Security headers
<IfModule mod_headers.c>
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
</IfModule>
# Protect sensitive files
<Files ".env">
Order allow,deny
Deny from all
</Files>
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
<Files "*.sqlite">
Order allow,deny
Deny from all
</Files>

323
DEPLOYMENT.md Executable file
View File

@ -0,0 +1,323 @@
# 🚀 NeoNail DB - Deployment Guide
## 📋 Schnellstart (5 Minuten)
### Option A: SQLite (Einfacher - Empfohlen)
- ✅ Keine MySQL-Installation nötig
- ✅ Einfache Datei-basierte Datenbank
- ✅ Perfekt für kleinere bis mittlere Anwendungen
- ✅ Einfaches Backup (nur eine Datei)
### Option B: MySQL/MariaDB
- ✅ Für größere Anwendungen
- ✅ Mehrere gleichzeitige Benutzer
- ✅ Erweiterte Datenbank-Features
---
## 🗄️ SQLite Deployment (Empfohlen)
### 1. Webspace vorbereiten
- PHP 8.1+ installiert
- SQLite3 PHP-Erweiterung aktiviert
- Composer verfügbar (falls möglich)
### 2. .env für SQLite konfigurieren
```env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://ihre-domain.de
# SQLite Konfiguration
DB_CONNECTION=sqlite
DB_DATABASE=/path/to/database.sqlite
# DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD nicht nötig!
```
### 3. SQLite-Datenbank erstellen
```bash
# Auf dem Server:
touch database.sqlite
chmod 664 database.sqlite
chown www-data:www-data database.sqlite # Falls verfügbar
```
### 4. Deployment ausführen
```bash
composer install --optimize-autoloader --no-dev
php artisan migrate --force
php artisan storage:link
php artisan config:cache
```
### 5. Admin-User erstellen
```bash
php artisan tinker
```
```php
use App\Models\User;
User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('ihr_sicheres_passwort')
]);
```
## 🗄️ MySQL/MariaDB Deployment
### 1. Webspace vorbereiten
- PHP 8.1+ installiert
- MySQL/MariaDB Datenbank erstellt
- Composer verfügbar (falls möglich)
### 2. Dateien hochladen
```bash
# Alle Dateien außer:
# - node_modules/ (falls vorhanden)
# - vendor/ (wird auf Server installiert)
# - .git/ (nicht nötig)
```
### 3. .env konfigurieren
```env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://ihre-domain.de
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=ihre_datenbank
DB_USERNAME=ihr_username
DB_PASSWORD=ihr_passwort
```
### 4. Deployment ausführen
```bash
# Falls SSH verfügbar:
chmod +x deploy.sh
./deploy.sh
# Oder manuell:
composer install --optimize-autoloader --no-dev
php artisan storage:link
php artisan migrate --force
php artisan config:cache
```
### 5. Admin-User erstellen
```bash
php artisan tinker
```
```php
use App\Models\User;
User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('ihr_sicheres_passwort')
]);
```
## 🔧 Detaillierte Anleitung
### SQLite vs MySQL Vergleich
| Feature | SQLite | MySQL |
|---------|--------|-------|
| Installation | ✅ Einfach | ❌ Komplexer |
| Konfiguration | ✅ Minimal | ❌ Mehr Aufwand |
| Backup | ✅ Eine Datei | ❌ Dump nötig |
| Performance | ✅ Gut (klein/mittel) | ✅ Sehr gut (groß) |
| Gleichzeitige User | ✅ Bis ~100 | ✅ Unbegrenzt |
| Wartung | ✅ Minimal | ❌ Regelmäßig |
### Voraussetzungen prüfen
**SQLite PHP-Erweiterungen:**
```bash
php -m | grep -E "(sqlite3|pdo_sqlite)"
```
**MySQL PHP-Erweiterungen:**
```bash
php -m | grep -E "(mysql|pdo_mysql)"
```
**Composer installieren (falls nicht verfügbar):**
```bash
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
### Datei-Struktur (SQLite)
```
public_html/
├── public/ # Web-Root
├── storage/ # Schreibrechte erforderlich
├── bootstrap/cache/ # Schreibrechte erforderlich
├── database.sqlite # SQLite-Datenbank
└── .env # Konfiguration
```
### Datei-Struktur (MySQL)
```
public_html/
├── public/ # Web-Root
├── storage/ # Schreibrechte erforderlich
├── bootstrap/cache/ # Schreibrechte erforderlich
└── .env # Konfiguration
```
### Berechtigungen (SQLite)
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 664 database.sqlite
chmod 644 .env
```
### Berechtigungen (MySQL)
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 644 .env
```
## 🛡️ Sicherheit
### Wichtige Einstellungen
- `APP_DEBUG=false` in Produktion
- Starke Passwörter verwenden
- HTTPS aktivieren
- `.env` nicht öffentlich zugänglich
### SQLite-spezifische Sicherheit
```apache
# .htaccess - SQLite-Datei schützen
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
```
### MySQL-spezifische Sicherheit
```apache
# .htaccess bereits konfiguriert
# Zusätzliche Sicherheit:
<Files ".env">
Order allow,deny
Deny from all
</Files>
```
## 📱 Mobile Optimierung
### PWA-Features (optional)
- Manifest.json hinzufügen
- Service Worker für Offline-Funktionalität
- App-Icons erstellen
### Performance
- Bilder komprimieren
- CDN für statische Assets
- Browser-Caching aktivieren
## 🔄 Backup-Strategie
### SQLite Backup
```bash
#!/bin/bash
# backup_sqlite.sh
DATE=$(date +%Y%m%d_%H%M%S)
cp database.sqlite backup_sqlite_$DATE.sqlite
tar -czf storage_backup_$DATE.tar.gz storage/
```
### MySQL Backup
```bash
#!/bin/bash
# backup_mysql.sh
DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u username -p database > backup_mysql_$DATE.sql
tar -czf storage_backup_$DATE.tar.gz storage/
```
### Cron-Job (täglich)
```bash
0 2 * * * /path/to/backup_sqlite.sh
```
## 🐛 Troubleshooting
### SQLite-spezifische Probleme
**1. "Database is locked"**
```bash
chmod 664 database.sqlite
chown www-data:www-data database.sqlite
```
**2. "SQLite3 not found"**
```bash
# PHP-Erweiterung aktivieren
php -m | grep sqlite
```
**3. Berechtigungsfehler**
```bash
chmod 664 database.sqlite
chmod -R 755 storage/
```
### MySQL-spezifische Probleme
**1. "Class not found" Fehler**
```bash
composer dump-autoload
```
**2. Berechtigungsfehler**
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
```
**3. Datenbank-Verbindung**
- Host, Port, Credentials prüfen
- MySQL-Service läuft
**4. Bilder werden nicht angezeigt**
```bash
php artisan storage:link
```
### Logs prüfen
```bash
tail -f storage/logs/laravel.log
```
## 📞 Support
Bei Problemen:
1. Logs prüfen (`storage/logs/laravel.log`)
2. Debug-Modus temporär aktivieren
3. Browser-Entwicklertools prüfen
4. Server-Error-Logs prüfen
## 🎯 Nach dem Deployment
### Testen
- [ ] Login funktioniert
- [ ] Neuen Lack erstellen
- [ ] Bild-Upload funktioniert
- [ ] Mobile-Ansicht prüfen
- [ ] Admin-Funktionen testen
### Monitoring
- Server-Ressourcen überwachen
- Datenbank-Performance prüfen
- User-Feedback sammeln
---
**Viel Erfolg beim Deployment! 🎉**

340
NEONAIL_PROJECT_PROMPT.md Executable file
View File

@ -0,0 +1,340 @@
# 🎨 NeoNail DB - Projekt Prompt
## 📋 Projekt-Übersicht
**NeoNail DB** ist eine Laravel-basierte Webanwendung zur Verwaltung von NeoNail-Nagellack-Sammlungen.
### 🎯 Hauptfunktionen
- ✅ Kollaborative Nagellack-Datenbank
- ✅ User können eigene Lacke hinzufügen (werden automatisch zum Hauptkatalog hinzugefügt)
- ✅ Hersteller-Verwaltung für alle User (flexibel und kollaborativ)
- ✅ Mobile-optimiert für Handy-Nutzung im Laden
- ✅ Admin-Interface für User-Verwaltung
- ✅ Bild-Upload mit automatischer Optimierung
- ✅ Suchfunktion nach Name/Nummer
- ✅ SQLite-Datenbank (einfach zu deployen)
## 🏗️ Technische Architektur
### Framework & Versionen
- **Laravel 12.22.1** (PHP 8.4.11)
- **Bootstrap 5** (Responsive Design)
- **Intervention Image** (Bildverarbeitung)
- **SQLite** (Datenbank)
### Datenbank-Schema
```sql
-- users (Laravel Standard)
-- manufacturers (Name, Description, Website, Country)
-- nail_polishes (Name, Number, Manufacturer_ID, Image)
-- user_nail_polishes (Pivot-Tabelle für User-Sammlungen)
```
### Wichtige Models
- `User` - Benutzer mit `nailPolishes()` Relationship
- `Manufacturer` - Hersteller mit `nailPolishes()` Relationship
- `NailPolish` - Nagellacke mit `users()` und `manufacturer()` Relationship
## 🔧 Aktuelle Deployment-Situation
### Webspace-Status
- **URL:** http://192.168.30.81/
- **Struktur:** Direkt im HTML-Verzeichnis
- **Status:** Neue .env Datei erstellt, Setup bereit
### Datei-Struktur auf Webspace
```
/html/ (oder /var/www/html/)
├── .htaccess ← Umleitung auf public/
├── index.php ← Fallback-Umleitung
├── .env ← Konfiguration (neu erstellt)
├── database.sqlite ← SQLite-Datenbank im Hauptverzeichnis
├── public/ ← Laravel Document Root
├── app/ ← Laravel App
├── bootstrap/ ← Laravel Bootstrap
├── config/ ← Laravel Config
├── database/ ← Migrationen
├── resources/ ← Views, Assets
├── routes/ ← Routen
├── storage/ ← Speicher (777 Berechtigungen)
├── vendor/ ← Composer Dependencies
├── test.php ← PHP-Diagnose
├── laravel-test.php ← Laravel-Diagnose
├── fix-permissions.sh ← Berechtigungs-Script
├── setup-html-directory.sh ← Neues Setup-Script
└── env-production-example.txt ← Neue .env Vorlage
```
### Aktuelle .env Konfiguration
```env
APP_NAME="NeoNail DB"
APP_ENV=production
APP_KEY=base64:+LTZYPKjkZ+O3iFTgU2sS+9bNvxxvG8Kw8JSEPiG7Rs=
APP_DEBUG=false
APP_URL=http://192.168.30.81
DB_CONNECTION=sqlite
DB_DATABASE=database.sqlite # ✅ Korrekt - Datenbank im Hauptverzeichnis
# Weitere Standard-Laravel-Einstellungen...
```
## 🚨 Offene Probleme
### 1. ✅ DB_DATABASE Pfad geklärt
**Status:** Datenbank liegt im Hauptverzeichnis
- **Pfad:** `/html/database.sqlite` (oder `/var/www/html/database.sqlite`)
- **Konfiguration:** `DB_DATABASE=database.sqlite`
### 2. Deployment-Status
- ✅ Berechtigungen korrigiert (777 für storage/, bootstrap/cache/)
- ✅ APP_KEY generiert und gesetzt
- ✅ .htaccess Umleitung funktioniert
- ✅ SQLite-Datenbank-Pfad geklärt
- ✅ Composer install ausgeführt
- ✅ Migrationen ausgeführt (inkl. Hersteller-Feature)
- ✅ Admin-User erstellt
- ✅ Hersteller-Feature vollständig implementiert und deployed
## 🔄 Nächste Schritte
### Sofortige Aktionen
1. ✅ **DB_DATABASE Pfad geklärt** - Datenbank im Hauptverzeichnis
2. ✅ **Composer install** ausgeführt
3. ✅ **Migrationen** ausgeführt: `php artisan migrate --force`
4. ✅ **Admin-User** erstellt
5. ✅ **Anwendung getestet** - Hersteller-Feature funktioniert
6. ✅ **HTTPS-Sicherheit** für alle Hersteller-Forms implementiert
### Admin-User erstellen
```bash
php artisan tinker
```
```php
use App\Models\User;
User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('ihr_passwort')
]);
```
## 📱 Anwendungs-Features
### User-Features
- **Meine Sammlung** - Eigene Lacke anzeigen/verwalten
- **Verfügbare Lacke** - Alle Lacke aus Hauptkatalog
- **Neuen Lack hinzufügen** - Erstellt Lack im Hauptkatalog + fügt zur eigenen Sammlung hinzu
- **Hersteller verwalten** - Hersteller erstellen, bearbeiten, löschen (für alle User)
- **Bild-Upload** - Handykamera-Unterstützung, automatische Optimierung
- **Suche** - Nach Name oder Nummer
### Admin-Features
- **Dashboard** - Übersicht über User, Lacke und Hersteller
- **User-Verwaltung** - User erstellen, bearbeiten, löschen
- **Nagellack-Verwaltung** - Alle Lacke verwalten
- **Hersteller-Verwaltung** - Alle Hersteller verwalten
- **Statistiken** - Anwendungs-Statistiken inkl. Hersteller
- **User-Sammlungen** - Sammlungen anderer User einsehen
## 🛠️ Wichtige Dateien
### Controllers
- `UserNailPolishController` - User-Sammlungen verwalten (erweitert um Hersteller)
- `NailPolishController` - Admin-Nagellack-Verwaltung
- `ManufacturerController` - Hersteller-Verwaltung für alle User
- `AdminController` - Admin-Dashboard und User-Verwaltung (erweitert um Hersteller-Statistiken)
- `LoginController` - Authentifizierung
### Views
- `user-nail-polishes/` - User-Sammlungs-Views (erweitert um Hersteller-Anzeige)
- `nail-polishes/` - Admin-Nagellack-Views (erweitert um Hersteller-Anzeige)
- `manufacturers/` - Hersteller-Verwaltungs-Views (index, create, edit, show)
- `admin/` - Admin-Interface-Views
- `auth/` - Login-Views
### Routes
```php
// User-Routes
/my-collection - Eigene Sammlung
/available - Verfügbare Lacke
/create-nail-polish - Neuen Lack erstellen
/add-to-collection/{id} - Lack zur Sammlung hinzufügen
/remove-from-collection/{id} - Lack aus Sammlung entfernen
// Hersteller-Routes (für alle User)
/manufacturers - Hersteller-Übersicht
/manufacturers/create - Neuen Hersteller erstellen
/manufacturers/{id} - Hersteller anzeigen
/manufacturers/{id}/edit - Hersteller bearbeiten
/manufacturers-search - AJAX-Suche nach Herstellern
// Admin-Routes
/admin/dashboard - Admin-Dashboard
/admin/users - User-Verwaltung
/nail-polishes - Nagellack-Verwaltung
/admin/statistics - Statistiken
```
## 🔒 Sicherheit
### Admin-Zugang
- **Email:** admin@neonail.com
- **Passwort:** Muss noch gesetzt werden
### Middleware
- `auth` - Authentifizierung erforderlich
- `admin` - Nur für admin@neonail.com
- `guest` - Nur für nicht-eingeloggte User
## 📊 Datenbank-Beziehungen
### Datenbank-Beziehungen
```php
// User Model
public function nailPolishes() {
return $this->belongsToMany(NailPolish::class, 'user_nail_polishes');
}
// Manufacturer Model
public function nailPolishes() {
return $this->hasMany(NailPolish::class);
}
// NailPolish Model
public function users() {
return $this->belongsToMany(User::class, 'user_nail_polishes');
}
public function manufacturer() {
return $this->belongsTo(Manufacturer::class);
}
```
### Pivot-Tabelle
```sql
user_nail_polishes (user_id, nail_polish_id, timestamps)
```
### Hersteller-Feature
- **Flexibilität:** Jeder User kann neue Hersteller erstellen
- **Eindeutigkeit:** Hersteller-Namen müssen eindeutig sein
- **Globale Verfügbarkeit:** Alle User können alle Hersteller nutzen
- **Automatische Erstellung:** Beim Nagellack-Erstellen falls nicht vorhanden
- **Referentielle Integrität:** Hersteller können nicht gelöscht werden, wenn Nagellacke zugeordnet sind
## 🎨 UI/UX Features
### Mobile-Optimierung
- Responsive Bootstrap 5 Design
- Touch-freundliche Buttons
- Handykamera-Integration (`capture="environment"`)
- Optimierte Bildgrößen (400x400px)
- Intelligente Hersteller-Auswahl mit JavaScript
### Design-Elemente
- Gradient-Hintergrund
- Glassmorphism-Effekte
- Font Awesome Icons
- Bootstrap Cards und Grid-System
## 🔧 Deployment-Scripts
### fix-permissions.sh
```bash
# Berechtigungen korrigieren
chmod -R 777 storage/
chmod -R 777 bootstrap/cache/
chmod 664 database.sqlite
chmod 644 .env
```
### deploy-manufacturer-feature.sh
```bash
# Hersteller-Feature Deployment
# - Migration-Reihenfolge korrigieren
# - Migrationen ausführen
# - Cache leeren
# - Autoload aktualisieren
# - Berechtigungen setzen
```
### setup-webspace.sh
```bash
# Vollständiges Setup
# - .env erstellen
# - Berechtigungen setzen
# - Composer install
# - Laravel Setup
```
### deploy-sqlite.sh
```bash
# SQLite-spezifisches Deployment
# - SQLite-Datenbank erstellen
# - Optimierte Einstellungen
```
## 🐛 Bekannte Probleme & Lösungen
### 1. "Permission denied" Fehler
**Lösung:** `chmod -R 777 storage/ bootstrap/cache/`
### 2. "APP_KEY" Fehler
**Lösung:** `php artisan key:generate` oder manueller Key
### 3. "Database connection failed"
**Lösung:** SQLite-Datei erstellen, Berechtigungen prüfen
### 4. "Class not found"
**Lösung:** `composer install` oder `composer dump-autoload`
### 5. "Images not displayed"
**Lösung:** `php artisan storage:link`
### 6. "no such table: manufacturers"
**Lösung:** Migrationen ausführen: `php artisan migrate --force`
### 7. "Migration-Reihenfolge Fehler"
**Lösung:** Migration `add_manufacturer_id_to_nail_polishes_table` nach `create_nail_polishes_table` verschieben
## 📞 Support-Informationen
### Logs
- `storage/logs/laravel.log` - Laravel-Logs
- `storage/logs/` - Weitere Logs
### Debug-Modus
```env
APP_DEBUG=true # Für Fehlerdiagnose
```
### Test-Dateien
- `test.php` - PHP-Diagnose
- `laravel-test.php` - Laravel-spezifische Diagnose
## 🎯 Projekt-Ziele
### Erreicht ✅
- Kollaborative Datenbank
- Mobile-Optimierung
- Admin-Interface
- Bild-Upload
- Suchfunktion
- SQLite-Deployment
- Hersteller-Verwaltung für alle User
- HTTPS-Sicherheit für alle Forms
- Intelligente Hersteller-Auswahl
### Nächste Schritte 🚀
1. ✅ Webspace-Deployment abgeschlossen
2. ✅ Admin-User erstellt
3. ✅ Anwendung getestet (inkl. Hersteller-Feature)
4. User-Feedback sammeln
5. Weitere Features entwickeln
---
**Projekt-Status:** 100% abgeschlossen, Hersteller-Feature implementiert
**Letzte Aktion:** Hersteller-Feature vollständig deployed und getestet
**Nächste Aktion:** User-Feedback sammeln und weitere Features entwickeln

163
README.md Executable file
View File

@ -0,0 +1,163 @@
# NeoNail Datenbank
Eine Laravel-basierte Webanwendung zur Verwaltung von NeoNail-Nagellack-Sammlungen. Die Anwendung ermöglicht es Benutzern, ihre persönliche Nagellack-Sammlung zu verwalten und ist speziell für die mobile Nutzung optimiert.
## Features
### Für Benutzer
- **Persönliche Sammlung**: Benutzer können ihre NeoNail-Lacke verwalten
- **Mobile Optimierung**: Handy-optimiertes Design für schnelle Nutzung im Laden
- **Suchfunktion**: Suche nach Namen oder Nummer der Lacke
- **Bild-Upload**: Möglichkeit, Bilder per Handykamera hochzuladen
- **Hersteller-Verwaltung**: Erstellen und verwalten von Herstellern
- **Responsive Design**: Funktioniert auf allen Geräten
### Für Administratoren
- **Benutzer-Verwaltung**: Erstellen, bearbeiten und löschen von Benutzern
- **Nagellack-Verwaltung**: Vollständige CRUD-Operationen für Nagellacke
- **Hersteller-Verwaltung**: Verwaltung aller Hersteller im System
- **Bildoptimierung**: Automatische Optimierung hochgeladener Bilder
- **Statistiken**: Übersicht über Benutzer, Sammlungen und Hersteller
- **Admin-Dashboard**: Übersichtliche Verwaltungsoberfläche
## Technische Details
### Datenbank-Struktur
- **Users**: Benutzer-Verwaltung
- **Manufacturers**: Hersteller-Daten (Name, Beschreibung, Website, Land)
- **NailPolishes**: Nagellack-Daten (Name, Nummer, Hersteller, Bild)
- **UserNailPolishes**: Many-to-Many Beziehung zwischen Benutzern und Lacken
### Technologien
- **Laravel 12**: PHP-Framework
- **Bootstrap 5**: CSS-Framework für responsive Design
- **Intervention Image**: Bildoptimierung
- **SQLite**: Datenbank (für einfache Entwicklung)
## Installation
### Voraussetzungen
- PHP 8.2+
- Composer
- Node.js (optional für Asset-Compilation)
### Setup
1. Repository klonen:
```bash
git clone <repository-url>
cd neonail-database
```
2. Abhängigkeiten installieren:
```bash
composer install
```
3. Umgebungsvariablen konfigurieren:
```bash
cp .env.example .env
php artisan key:generate
```
4. Datenbank einrichten:
```bash
php artisan migrate
```
5. Storage-Link erstellen:
```bash
php artisan storage:link
```
6. Admin-Benutzer erstellen:
```bash
php artisan tinker
```
```php
App\Models\User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('password')
]);
```
7. Server starten:
```bash
php artisan serve
```
## Verwendung
### Admin-Zugang
- **E-Mail**: admin@neonail.com
- **Passwort**: password
### Benutzer-Flow
1. **Anmeldung**: Benutzer melden sich mit ihren Zugangsdaten an
2. **Sammlung anzeigen**: Übersicht über alle eigenen Lacke
3. **Lack hinzufügen**: Aus verfügbaren Lacken auswählen
4. **Hersteller verwalten**: Hersteller erstellen und verwalten
5. **Suchen**: Schnelle Suche nach Namen oder Nummer
6. **Bilder**: Kamera-Upload für neue Lacke (Admin)
### Admin-Flow
1. **Dashboard**: Übersicht über Statistiken
2. **Benutzer verwalten**: CRUD-Operationen für Benutzer
3. **Nagellacke verwalten**: Vollständige Verwaltung der Lacke
4. **Hersteller verwalten**: Verwaltung aller Hersteller
5. **Statistiken**: Detaillierte Auswertungen
## Mobile Optimierung
Die Anwendung ist speziell für mobile Geräte optimiert:
- **Touch-freundlich**: Große Buttons und Touch-Targets
- **Kamera-Integration**: Direkter Zugriff auf Handykamera
- **Responsive Design**: Anpassung an verschiedene Bildschirmgrößen
- **Schnelle Navigation**: Optimiert für schnelle Nutzung im Laden
## Sicherheit
- **Authentifizierung**: Laravel's eingebaute Auth-System
- **Admin-Middleware**: Geschützte Admin-Bereiche
- **Bildvalidierung**: Sichere Bild-Uploads
- **CSRF-Schutz**: Automatischer CSRF-Schutz
## Entwicklung
### Hinzufügen neuer Features
1. Migration erstellen: `php artisan make:migration`
2. Model anpassen/erstellen
3. Controller-Logik implementieren
4. Views erstellen
5. Routes definieren
### Testing
```bash
php artisan test
```
## Deployment
### Produktionsumgebung
1. `.env` für Produktion konfigurieren
2. `APP_ENV=production` setzen
3. `APP_DEBUG=false` setzen
4. Datenbank-Migrationen ausführen
5. Storage-Links erstellen
### Empfohlene Server-Konfiguration
- **Webserver**: Nginx oder Apache
- **PHP**: 8.2+ mit erforderlichen Extensions
- **Datenbank**: MySQL/PostgreSQL für Produktion
- **SSL**: HTTPS für sichere Übertragung
## Support
Bei Fragen oder Problemen:
1. Issues im Repository erstellen
2. Dokumentation prüfen
3. Laravel-Dokumentation konsultieren
## Lizenz
Dieses Projekt ist für interne Nutzung bestimmt.

205
WEBSPACE-SETUP.md Executable file
View File

@ -0,0 +1,205 @@
# 🌐 Webspace Setup - NeoNail DB
## 🚨 Problem: Verzeichnisliste wird angezeigt
Wenn Sie eine Verzeichnisliste sehen statt der Laravel-Anwendung, liegt das daran, dass der Webserver nicht auf das `public/` Verzeichnis zeigt.
## 🔧 Lösungen je nach Hosting-Provider
### **Option A: Shared Hosting (cPanel, Plesk, etc.)**
**1. Document Root ändern:**
- Gehen Sie zu Ihrem Hosting-Panel
- Suchen Sie "Document Root" oder "Web Root"
- Ändern Sie von `/neonail/` zu `/neonail/public/`
**2. Oder Unterverzeichnis erstellen:**
```
public_html/
└── neonail/
└── public/ ← Hier alle Laravel-Dateien
```
### **Option B: VPS/Dedicated Server**
**1. Apache Virtual Host:**
```apache
<VirtualHost *:80>
ServerName ihre-domain.de
DocumentRoot /var/www/neonail/public
<Directory /var/www/neonail/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
```
**2. Nginx:**
```nginx
server {
listen 80;
server_name ihre-domain.de;
root /var/www/neonail/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
```
### **Option C: Automatische Umleitung (Empfohlen)**
**1. .htaccess im Hauptverzeichnis (bereits erstellt):**
```apache
RewriteEngine On
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
```
**2. index.php im Hauptverzeichnis (bereits erstellt):**
```php
<?php
$publicPath = __DIR__ . '/public';
if (file_exists($publicPath . '/index.php')) {
require_once $publicPath . '/index.php';
}
```
## 📋 Schritt-für-Schritt Setup
### **1. Dateien hochladen**
```
/neonail/
├── .htaccess ← Neue Datei (Umleitung)
├── index.php ← Neue Datei (Umleitung)
├── public/ ← Laravel public Verzeichnis
├── app/ ← Laravel App-Verzeichnis
├── bootstrap/ ← Laravel Bootstrap
├── config/ ← Laravel Konfiguration
├── database/ ← Datenbank-Migrationen
├── resources/ ← Views, Assets
├── routes/ ← Routen
├── storage/ ← Speicher (Schreibrechte!)
└── vendor/ ← Composer Dependencies
```
### **2. .env erstellen**
```bash
# Kopieren Sie env-sqlite-example.txt zu .env
cp env-sqlite-example.txt .env
```
**In .env anpassen:**
```env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://ihre-domain.de/neonail
# SQLite (einfachste Option)
DB_CONNECTION=sqlite
DB_DATABASE=/path/to/neonail/database.sqlite
```
### **3. Berechtigungen setzen**
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 644 .env
```
### **4. SQLite-Datenbank erstellen**
```bash
touch database.sqlite
chmod 664 database.sqlite
```
### **5. Composer installieren (falls verfügbar)**
```bash
composer install --optimize-autoloader --no-dev
```
### **6. Laravel Setup**
```bash
php artisan migrate --force
php artisan storage:link
php artisan config:cache
```
### **7. Admin-User erstellen**
```bash
php artisan tinker
```
```php
use App\Models\User;
User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('ihr_passwort')
]);
```
## 🐛 Troubleshooting
### **Problem: "500 Internal Server Error"**
**Lösung:**
1. `.env` Datei prüfen
2. Berechtigungen prüfen
3. PHP-Version prüfen (8.1+)
4. Logs prüfen: `storage/logs/laravel.log`
### **Problem: "Class not found"**
**Lösung:**
```bash
composer dump-autoload
```
### **Problem: "Database connection failed"**
**Lösung:**
1. SQLite-Datei erstellen
2. Berechtigungen prüfen
3. Pfad in .env prüfen
### **Problem: "Permission denied"**
**Lösung:**
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 664 database.sqlite
```
## 📱 Testen
### **Nach dem Setup:**
1. **URL aufrufen:** `https://ihre-domain.de/neonail`
2. **Login testen:** `admin@neonail.com`
3. **Neuen Lack erstellen**
4. **Bild-Upload testen**
5. **Mobile-Ansicht prüfen**
### **Erwartetes Ergebnis:**
- ✅ Login-Seite wird angezeigt
- ✅ Keine Verzeichnisliste mehr
- ✅ Laravel-Anwendung läuft
- ✅ Alle Funktionen funktionieren
## 🆘 Support
**Falls nichts funktioniert:**
1. Hosting-Provider kontaktieren
2. PHP-Version prüfen (8.1+)
3. mod_rewrite aktiviert?
4. .htaccess erlaubt?
---
**Viel Erfolg beim Setup! 🎉**

37
activate-admin-role.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/bash
echo "👑 Admin-Rolle aktivieren"
echo "========================"
# 1. Admin-Rolle zur Datenbank hinzufügen
echo "🗄️ Füge Admin-Rolle zur Datenbank hinzu..."
sqlite3 database.sqlite "ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT 0;" 2>/dev/null || echo "⚠️ Spalte existiert bereits"
# 2. Bestehende Admin-User als Admin markieren
echo "👤 Markiere bestehende Admin-User..."
sqlite3 database.sqlite "UPDATE users SET is_admin = 1 WHERE email IN ('admin@neonail.com', 'neueradmin@neonail.com');"
# 3. Laravel Cache leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
# 4. Admin-User prüfen
echo "🔍 Prüfe Admin-User..."
sqlite3 database.sqlite "SELECT id, name, email, is_admin FROM users;" 2>/dev/null || echo "⚠️ Keine User gefunden"
# 5. Test-Admin-User erstellen (falls gewünscht)
echo "🧪 Erstelle Test-Admin-User..."
sqlite3 database.sqlite "INSERT OR IGNORE INTO users (name, email, password, is_admin, created_at, updated_at) VALUES ('Test Admin', 'testadmin@neonail.com', '\$2y\$12\$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 1, datetime('now'), datetime('now'));"
echo ""
echo "✅ Admin-Rolle aktiviert!"
echo ""
echo "📋 Admin-Funktionen:"
echo "1. User bearbeiten: https://neonail.vogt.de.com/admin/users"
echo "2. Admin-Rechte gewähren: Checkbox in User-Bearbeitung"
echo "3. Admin-Status anzeigen: Badge in User-Liste"
echo ""
echo "🔑 Test-Admin-Login:"
echo "Email: testadmin@neonail.com"
echo "Passwort: password"

View File

@ -0,0 +1,17 @@
<?php
// Migration: Admin-Rolle zu Users-Tabelle hinzufügen
// Führen Sie dies aus, um die Admin-Rolle zu aktivieren
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
// 1. Spalte zur users-Tabelle hinzufügen
DB::statement('ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT 0');
// 2. Bestehende Admin-User als Admin markieren
DB::statement("UPDATE users SET is_admin = 1 WHERE email IN ('admin@neonail.com', 'neueradmin@neonail.com')");
echo "✅ Admin-Rolle erfolgreich hinzugefügt!\n";
echo "📋 Admin-User aktualisiert\n";
?>

47
admin-check.php Executable file
View File

@ -0,0 +1,47 @@
<?php
// Einfacher Admin-User Check
echo "<h1>🔍 Admin-User Check</h1>";
try {
// Laravel laden
require_once 'vendor/autoload.php';
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// User Model verwenden
$users = \App\Models\User::all();
echo "<h2>Benutzer in der Datenbank:</h2>";
if ($users->count() > 0) {
echo "<p>✅ <strong>{$users->count()}</strong> Benutzer gefunden</p>";
foreach ($users as $user) {
echo "<div style='border: 1px solid #ccc; padding: 10px; margin: 5px;'>";
echo "<strong>ID:</strong> {$user->id}<br>";
echo "<strong>Name:</strong> {$user->name}<br>";
echo "<strong>Email:</strong> {$user->email}<br>";
echo "<strong>Erstellt:</strong> {$user->created_at}<br>";
echo "</div>";
}
// Admin-User prüfen
$admin = \App\Models\User::where('email', 'admin@neonail.com')->first();
if ($admin) {
echo "<h2>👑 Admin-User gefunden!</h2>";
echo "<p>Sie können sich mit <strong>admin@neonail.com</strong> anmelden.</p>";
echo "<p><a href='http://192.168.30.81' style='background: #007bff; color: white; padding: 10px; text-decoration: none; border-radius: 5px;'>🚀 Zur Anwendung</a></p>";
}
} else {
echo "<p>❌ Keine Benutzer gefunden</p>";
echo "<h3>Admin-User erstellen:</h3>";
echo "<code>php artisan tinker</code><br>";
echo "<code>use App\Models\User;</code><br>";
echo "<code>User::create(['name' => 'Admin', 'email' => 'admin@neonail.com', 'password' => bcrypt('ihr_passwort')]);</code>";
}
} catch (Exception $e) {
echo "<h2>❌ Fehler:</h2>";
echo "<p>{$e->getMessage()}</p>";
}
?>

28
apache-config.txt Executable file
View File

@ -0,0 +1,28 @@
# Apache Virtual Host Konfiguration für NeoNail DB
# Datei: /etc/apache2/sites-available/neonail.conf
<VirtualHost *:80>
ServerName 192.168.30.81
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride All
Require all granted
</Directory>
# Sicherheit - Zugriff auf sensible Dateien verhindern
<Directory /var/www/html>
<Files ".env">
Order allow,deny
Deny from all
</Files>
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/neonail_error.log
CustomLog ${APACHE_LOG_DIR}/neonail_access.log combined
</VirtualHost>

74
apache-diagnose.sh Executable file
View File

@ -0,0 +1,74 @@
#!/bin/bash
echo "🔍 Apache Diagnose für NeoNail DB"
echo "================================"
echo "1. 📁 Verzeichnis-Struktur prüfen:"
echo "--------------------------------"
ls -la /var/www/html/
echo ""
echo "2. 📁 Public-Ordner prüfen:"
echo "--------------------------"
ls -la /var/www/html/public/
echo ""
echo "3. 🌐 Apache DocumentRoot prüfen:"
echo "-------------------------------"
apache2ctl -S 2>/dev/null | grep "DocumentRoot" || echo "⚠️ Apache2ctl nicht verfügbar"
echo ""
echo "4. 📋 Apache Sites prüfen:"
echo "------------------------"
ls -la /etc/apache2/sites-enabled/
echo ""
echo "5. 📋 Apache Sites verfügbar:"
echo "----------------------------"
ls -la /etc/apache2/sites-available/
echo ""
echo "6. 🔧 Apache Konfiguration prüfen:"
echo "--------------------------------"
if [ -f "/etc/apache2/sites-enabled/neonail.conf" ]; then
echo "✅ neonail.conf ist aktiviert"
cat /etc/apache2/sites-enabled/neonail.conf
else
echo "❌ neonail.conf ist NICHT aktiviert"
fi
echo ""
echo "7. 📝 .htaccess im Hauptverzeichnis:"
echo "----------------------------------"
if [ -f "/var/www/html/.htaccess" ]; then
echo "✅ .htaccess gefunden:"
cat /var/www/html/.htaccess
else
echo "❌ .htaccess nicht gefunden"
fi
echo ""
echo "8. 📝 .htaccess im public-Ordner:"
echo "-------------------------------"
if [ -f "/var/www/html/public/.htaccess" ]; then
echo "✅ public/.htaccess gefunden:"
cat /var/www/html/public/.htaccess
else
echo "❌ public/.htaccess nicht gefunden"
fi
echo ""
echo "9. 🔍 Apache-Logs prüfen:"
echo "-----------------------"
tail -5 /var/log/apache2/error.log
echo ""
echo "10. 🧪 Test-Request:"
echo "------------------"
curl -I http://192.168.30.81 2>/dev/null || echo "⚠️ curl nicht verfügbar"
echo ""
echo "📋 Nächste Schritte:"
echo "1. Falls public/index.php fehlt: Laravel nicht vollständig"
echo "2. Falls .htaccess fehlt: Umleitung nicht konfiguriert"
echo "3. Falls Apache-Site nicht aktiviert: Virtual Host nicht konfiguriert"

View File

@ -0,0 +1,212 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\NailPolish;
use App\Models\Manufacturer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
class AdminController extends Controller
{
/**
* Dashboard für Administratoren
*/
public function dashboard()
{
$totalUsers = User::count();
$totalNailPolishes = NailPolish::count();
$totalManufacturers = Manufacturer::count();
$recentUsers = User::latest()->take(5)->get();
$recentNailPolishes = NailPolish::latest()->take(5)->get();
$recentManufacturers = Manufacturer::latest()->take(5)->get();
return view("admin.dashboard", compact("totalUsers", "totalNailPolishes", "totalManufacturers", "recentUsers", "recentNailPolishes", "recentManufacturers"));
}
/**
* Liste aller Benutzer
*/
public function users(Request $request)
{
$search = $request->get("search");
$users = User::when($search, function($query) use ($search) {
return $query->where("name", "like", "%{$search}%")
->orWhere("email", "like", "%{$search}%");
})->orderBy("name")->paginate(20);
return view("admin.users.index", compact("users", "search"));
}
/**
* Formular zum Erstellen eines neuen Benutzers
*/
public function createUser()
{
return view("admin.users.create");
}
/**
* Neuen Benutzer speichern
*/
public function storeUser(Request $request)
{
$request->validate([
"name" => "required|string|max:255",
"email" => "required|string|email|max:255|unique:users",
"password" => "required|string|min:8|confirmed",
]);
// Passwort für E-Mail speichern (wird nach dem Speichern gelöscht)
$plainPassword = $request->password;
// User erstellen
$user = User::create([
"name" => $request->name,
"email" => $request->email,
"password" => Hash::make($request->password),
"is_admin" => $request->has("is_admin"),
]);
// Willkommens-E-Mail senden
try {
Mail::send("emails.welcome-user", [
"user" => $user,
"password" => $plainPassword
], function($message) use ($user) {
$message->to($user->email, $user->name)
->subject("🎨 Willkommen bei der NeoNail DB - Ihre Login-Daten")
->from(config("mail.from.address"), config("mail.from.name"));
});
// Admin-Bestätigung senden
Mail::raw("Hallo Admin!
Ein neuer User wurde erfolgreich erstellt und eine Willkommens-E-Mail gesendet.
📋 User-Details:
- Name: {$user->name}
- E-Mail: {$user->email}
- Admin-Status: " . ($user->isAdmin() ? "Ja" : "Nein") . "
- Erstellt: " . now() . "
Die Willkommens-E-Mail enthält:
- Login-Daten (Website, E-Mail, Passwort)
- Aufforderung zum Passwort-Ändern
- Feature-Übersicht
- Direkte Links zur Anwendung
Viele Grüße,
NeoNail DB System", function($message) {
$message->to("oliver@vogt.de.com", "Admin")
->subject("✅ NeoNail DB - Neuer User erstellt")
->from(config("mail.from.address"), config("mail.from.name"));
});
$successMessage = "Benutzer erfolgreich erstellt! Willkommens-E-Mail wurde gesendet.";
} catch (\Exception $e) {
// User wurde erstellt, aber E-Mail fehlgeschlagen
\Log::error("Fehler beim Senden der Willkommens-E-Mail: " . $e->getMessage());
$successMessage = "Benutzer erfolgreich erstellt! E-Mail konnte nicht gesendet werden.";
}
return redirect()->route("admin.users.index")
->with("success", $successMessage);
}
/**
* Formular zum Bearbeiten eines Benutzers
*/
public function editUser(User $user)
{
return view("admin.users.edit", compact("user"));
}
/**
* Benutzer aktualisieren
*/
public function updateUser(Request $request, User $user)
{
$request->validate([
"name" => "required|string|max:255",
"email" => "required|string|email|max:255|unique:users,email," . $user->id,
"password" => "nullable|string|min:8|confirmed",
]);
$user->name = $request->name;
$user->email = $request->email;
$user->is_admin = $request->has("is_admin");
if ($request->filled("password")) {
$user->password = Hash::make($request->password);
}
$user->save();
return redirect()->route("admin.users.index")
->with("success", "Benutzer erfolgreich aktualisiert!");
}
/**
* Benutzer löschen
*/
public function destroyUser(User $user)
{
$userName = $user->name;
$userEmail = $user->email;
$user->delete();
// Admin-Benachrichtigung über gelöschten User
try {
Mail::raw("Hallo Admin!
Ein User wurde erfolgreich gelöscht.
📋 Gelöschter User:
- Name: {$userName}
- E-Mail: {$userEmail}
- Gelöscht: " . now() . "
Viele Grüße,
NeoNail DB System", function($message) {
$message->to("oliver@vogt.de.com", "Admin")
->subject("🗑️ NeoNail DB - User gelöscht")
->from(config("mail.from.address"), config("mail.from.name"));
});
} catch (\Exception $e) {
\Log::error("Fehler beim Senden der Lösch-Benachrichtigung: " . $e->getMessage());
}
return redirect()->route("admin.users.index")
->with("success", "Benutzer erfolgreich gelöscht!");
}
/**
* Statistiken anzeigen
*/
public function statistics()
{
$totalUsers = User::count();
$totalNailPolishes = NailPolish::count();
$usersWithCollections = User::has("nailPolishes")->count();
$averageCollectionSize = User::withCount("nailPolishes")->avg("nail_polishes_count");
$topUsers = User::withCount("nailPolishes")
->orderBy("nail_polishes_count", "desc")
->take(10)
->get();
return view("admin.statistics", compact(
"totalUsers",
"totalNailPolishes",
"usersWithCollections",
"averageCollectionSize",
"topUsers"
));
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function showLoginForm()
{
return view('auth.login');
}
public function login(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials, $request->boolean('remember'))) {
$request->session()->regenerate();
return redirect()->intended(route('user-nail-polishes.index'));
}
return back()->withErrors([
'email' => 'Die angegebenen Anmeldedaten stimmen nicht überein.',
])->onlyInput('email');
}
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

View File

@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers;
use App\Models\Manufacturer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ManufacturerController extends Controller
{
/**
* Zeigt alle Hersteller an
*/
public function index(Request $request)
{
$search = $request->get('search');
$query = Manufacturer::withCount('nailPolishes');
if ($search) {
$query->search($search);
}
$manufacturers = $query->orderBy('name')->paginate(20);
return view('manufacturers.index', compact('manufacturers', 'search'));
}
/**
* Zeigt das Formular zum Erstellen eines neuen Herstellers
*/
public function create()
{
return view('manufacturers.create');
}
/**
* Speichert einen neuen Hersteller
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255|unique:manufacturers',
'description' => 'nullable|string|max:1000',
'website' => 'nullable|url|max:255',
'country' => 'nullable|string|max:100',
]);
try {
$manufacturer = Manufacturer::create([
'name' => $request->name,
'description' => $request->description,
'website' => $request->website,
'country' => $request->country,
]);
return redirect()->route('manufacturers.index')
->with('success', "Hersteller '{$manufacturer->name}' wurde erfolgreich erstellt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Erstellen des Herstellers: " . $e->getMessage());
return back()->with('error', 'Fehler beim Erstellen des Herstellers. Bitte versuchen Sie es erneut.')
->withInput();
}
}
/**
* Zeigt einen Hersteller an
*/
public function show(Manufacturer $manufacturer)
{
$manufacturer->load(['nailPolishes' => function($query) {
$query->orderBy('name');
}]);
return view('manufacturers.show', compact('manufacturer'));
}
/**
* Zeigt das Formular zum Bearbeiten eines Herstellers
*/
public function edit(Manufacturer $manufacturer)
{
return view('manufacturers.edit', compact('manufacturer'));
}
/**
* Aktualisiert einen Hersteller
*/
public function update(Request $request, Manufacturer $manufacturer)
{
$request->validate([
'name' => 'required|string|max:255|unique:manufacturers,name,' . $manufacturer->id,
'description' => 'nullable|string|max:1000',
'website' => 'nullable|url|max:255',
'country' => 'nullable|string|max:100',
]);
try {
$manufacturer->update([
'name' => $request->name,
'description' => $request->description,
'website' => $request->website,
'country' => $request->country,
]);
return redirect()->route('manufacturers.index')
->with('success', "Hersteller '{$manufacturer->name}' wurde erfolgreich aktualisiert!");
} catch (\Exception $e) {
\Log::error("Fehler beim Aktualisieren des Herstellers: " . $e->getMessage());
return back()->with('error', 'Fehler beim Aktualisieren des Herstellers. Bitte versuchen Sie es erneut.')
->withInput();
}
}
/**
* Löscht einen Hersteller
*/
public function destroy(Manufacturer $manufacturer)
{
try {
// Prüfe, ob der Hersteller noch Nagellacke hat
if ($manufacturer->hasNailPolishes()) {
return back()->with('error', "Hersteller '{$manufacturer->name}' kann nicht gelöscht werden, da noch Nagellacke zugeordnet sind.");
}
$name = $manufacturer->name;
$manufacturer->delete();
return redirect()->route('manufacturers.index')
->with('success', "Hersteller '{$name}' wurde erfolgreich gelöscht!");
} catch (\Exception $e) {
\Log::error("Fehler beim Löschen des Herstellers: " . $e->getMessage());
return back()->with('error', 'Fehler beim Löschen des Herstellers. Bitte versuchen Sie es erneut.');
}
}
/**
* API-Endpoint für AJAX-Suche nach Herstellern
*/
public function search(Request $request)
{
$search = $request->get('q');
$manufacturers = Manufacturer::where('name', 'like', "%{$search}%")
->orderBy('name')
->limit(10)
->get(['id', 'name']);
return response()->json($manufacturers);
}
}

View File

@ -0,0 +1,165 @@
<?php
namespace App\Http\Controllers;
use App\Models\NailPolish;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Facades\Image;
class NailPolishController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$search = $request->get('search');
$nailPolishes = NailPolish::when($search, function($query) use ($search) {
return $query->search($search);
})->orderBy('name')->paginate(20);
return view('nail-polishes.index', compact('nailPolishes', 'search'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('nail-polishes.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'number' => 'required|string|max:50|unique:nail_polishes',
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048'
]);
$nailPolish = new NailPolish();
$nailPolish->name = $request->name;
$nailPolish->number = $request->number;
if ($request->hasFile('image')) {
$image = $request->file('image');
$filename = time() . '_' . $image->getClientOriginalName();
// Bild optimieren und speichern
$optimizedImage = Image::make($image)
->resize(300, 300, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})
->encode('jpg', 80);
Storage::disk('public')->put('nail-polishes/' . $filename, $optimizedImage);
$nailPolish->image_path = 'nail-polishes/' . $filename;
}
$nailPolish->save();
return redirect()->route('nail-polishes.index')
->with('success', 'Nagellack erfolgreich hinzugefügt!');
}
/**
* Display the specified resource.
*/
public function show(NailPolish $nailPolish)
{
return view('nail-polishes.show', compact('nailPolish'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(NailPolish $nailPolish)
{
return view('nail-polishes.edit', compact('nailPolish'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, NailPolish $nailPolish)
{
$request->validate([
'name' => 'required|string|max:255',
'number' => 'required|string|max:50|unique:nail_polishes,number,' . $nailPolish->id,
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048'
]);
$nailPolish->name = $request->name;
$nailPolish->number = $request->number;
if ($request->hasFile('image')) {
// Altes Bild löschen
if ($nailPolish->image_path) {
Storage::disk('public')->delete($nailPolish->image_path);
}
$image = $request->file('image');
$filename = time() . '_' . $image->getClientOriginalName();
// Bild optimieren und speichern
$optimizedImage = Image::make($image)
->resize(300, 300, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})
->encode('jpg', 80);
Storage::disk('public')->put('nail-polishes/' . $filename, $optimizedImage);
$nailPolish->image_path = 'nail-polishes/' . $filename;
}
$nailPolish->save();
return redirect()->route('nail-polishes.index')
->with('success', 'Nagellack erfolgreich aktualisiert!');
}
/**
* Löscht einen Nagellack
*/
public function destroy(NailPolish $nailPolish)
{
try {
// Prüfe, ob der Lack von anderen Usern verwendet wird
$usersWithThisPolish = $nailPolish->users()->count();
if ($usersWithThisPolish > 0) {
return back()->with('error', "Dieser Lack kann nicht gelöscht werden, da er von {$usersWithThisPolish} Benutzer(n) in ihrer Sammlung verwendet wird. Bitte entfernen Sie ihn zuerst aus allen Sammlungen.");
}
// Lösche das Bild, falls vorhanden
if ($nailPolish->image_path && Storage::disk('public')->exists($nailPolish->image_path)) {
Storage::disk('public')->delete($nailPolish->image_path);
}
$nailPolish->delete();
return redirect()->route('nail-polishes.index')
->with('success', "Lack '{$nailPolish->name}' wurde erfolgreich gelöscht!");
} catch (\Exception $e) {
return back()->with('error', 'Fehler beim Löschen des Lackes: ' . $e->getMessage());
}
}
/**
* Zeigt an, welche User einen bestimmten Lack haben
*/
public function showUsers(NailPolish $nailPolish)
{
$users = $nailPolish->users()->paginate(20);
return view('nail-polishes.show-users', compact('nailPolish', 'users'));
}
}

View File

@ -0,0 +1,186 @@
<?php
namespace App\Http\Controllers;
use App\Models\NailPolish;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class UserNailPolishController extends Controller
{
/**
* Zeigt die Sammlung des aktuellen Benutzers an
*/
public function index(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = $user->nailPolishes();
if ($search) {
$query->where(function($q) use ($search) {
$q->where("name", "like", "%{$search}%")
->orWhere("number", "like", "%{$search}%");
});
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.index", compact("nailPolishes", "search"));
}
/**
* Zeigt alle verfügbaren Lacke an, die der User noch nicht hat
*/
public function available(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = NailPolish::whereNotIn("id", $user->nailPolishes()->pluck("nail_polishes.id"));
if ($search) {
$query->search($search);
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.available", compact("nailPolishes", "search"));
}
/**
* Fügt einen Lack zur Sammlung des Users hinzu
*/
public function add(NailPolish $nailPolish)
{
$user = Auth::user();
// Prüfe, ob der Lack bereits in der Sammlung ist
if ($user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist bereits in Ihrer Sammlung!");
}
$user->nailPolishes()->attach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde zu Ihrer Sammlung hinzugefügt!");
}
/**
* Entfernt einen Lack aus der Sammlung des Users
*/
public function remove(NailPolish $nailPolish)
{
try {
$user = Auth::user();
// Prüfe, ob der Lack in der Sammlung ist
if (!$user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist nicht in Ihrer Sammlung!");
}
$user->nailPolishes()->detach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde aus Ihrer Sammlung entfernt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Entfernen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Entfernen des Lackes. Bitte versuchen Sie es erneut.");
}
}
/**
* Zeigt das Formular zum Erstellen eines neuen Lackes
*/
public function create()
{
return view("user-nail-polishes.create");
}
/**
* Speichert einen neuen Lack (wird automatisch zum Hauptkatalog hinzugefügt)
*/
public function store(Request $request)
{
$request->validate([
"name" => "required|string|max:255",
"number" => "required|string|max:50",
"manufacturer_id" => "required_without:new_manufacturer|exists:manufacturers,id",
"new_manufacturer" => "required_without:manufacturer_id|string|max:255|unique:manufacturers,name",
"image" => "nullable|image|max:10240", // Max 10MB
], [
"name.required" => "Der Name des Lackes ist erforderlich.",
"number.required" => "Die Nummer des Lackes ist erforderlich.",
"manufacturer_id.required_without" => "Bitte wählen Sie einen Hersteller aus oder erstellen Sie einen neuen.",
"new_manufacturer.required_without" => "Bitte wählen Sie einen Hersteller aus oder erstellen Sie einen neuen.",
"new_manufacturer.unique" => "Ein Hersteller mit diesem Namen existiert bereits.",
"image.image" => "Die Datei muss ein Bild sein.",
"image.max" => "Das Bild darf maximal 10MB groß sein.",
]);
try {
// Hersteller verarbeiten
$manufacturerId = null;
if ($request->filled('new_manufacturer')) {
// Neuen Hersteller erstellen
$manufacturer = \App\Models\Manufacturer::create([
'name' => trim($request->new_manufacturer),
]);
$manufacturerId = $manufacturer->id;
} else {
$manufacturerId = $request->manufacturer_id;
}
$nailPolish = new NailPolish();
$nailPolish->name = trim($request->name);
$nailPolish->number = trim($request->number);
$nailPolish->manufacturer_id = $manufacturerId;
// Vereinfachte Bildverarbeitung ohne Intervention Image
if ($request->hasFile("image") && $request->file("image")->isValid()) {
$image = $request->file("image");
// Erstelle einen eindeutigen Dateinamen
$filename = "nail_polish_" . time() . "_" . uniqid() . "." . $image->getClientOriginalExtension();
$path = "nail_polishes/" . $filename;
// Speichere das Bild direkt ohne Verarbeitung
Storage::disk("public")->putFileAs("nail_polishes", $image, $filename);
$nailPolish->image_path = $path;
\Log::info("Bild erfolgreich gespeichert: " . $path);
}
$nailPolish->save();
// Füge den Lack automatisch zur Sammlung des Users hinzu
$user = Auth::user();
$user->nailPolishes()->attach($nailPolish->id);
$successMessage = "Lack \"{$nailPolish->name}\" wurde erfolgreich erstellt und zu Ihrer Sammlung hinzugefügt!";
if ($request->filled('new_manufacturer')) {
$successMessage .= " Neuer Hersteller \"{$request->new_manufacturer}\" wurde ebenfalls erstellt.";
}
return redirect()->route("user-nail-polishes.index")
->with("success", $successMessage);
} catch (\Exception $e) {
\Log::error("Fehler beim Erstellen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Erstellen des Lackes: " . $e->getMessage())
->withInput();
}
}
/**
* Zeigt die Sammlung eines bestimmten Users (für Admin)
*/
public function showUserCollection(User $user)
{
$nailPolishes = $user->nailPolishes()->orderBy("name")->paginate(12);
return view("user-nail-polishes.show-user", compact("user", "nailPolishes"));
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// Admin-Berechtigung mit is_admin Spalte
if (!auth()->check() || !auth()->user()->isAdmin()) {
abort(403, 'Zugriff verweigert. Admin-Berechtigung erforderlich.');
}
return $next($request);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class Authenticate
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string ...$guards): Response
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (!Auth::guard($guard)->check()) {
return redirect()->route('login');
}
}
return $next($request);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string ...$guards): Response
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect()->route('user-nail-polishes.index');
}
}
return $next($request);
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Manufacturer extends Model
{
use HasFactory;
/**
* Die Tabelle, die dem Model zugeordnet ist.
*/
protected $table = 'manufacturers';
protected $fillable = [
'name',
'description',
'website',
'country',
];
/**
* Beziehung zu Nagellacken
*/
public function nailPolishes()
{
return $this->hasMany(NailPolish::class);
}
/**
* Scope für Suche nach Name
*/
public function scopeSearch($query, $search)
{
return $query->where('name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%")
->orWhere('country', 'like', "%{$search}%");
}
/**
* Gibt den Namen des Herstellers zurück
*/
public function getDisplayNameAttribute()
{
return $this->name;
}
/**
* Prüft, ob der Hersteller Nagellacke hat
*/
public function hasNailPolishes()
{
return $this->nailPolishes()->exists();
}
/**
* Anzahl der Nagellacke dieses Herstellers
*/
public function getNailPolishCountAttribute()
{
return $this->nailPolishes()->count();
}
}

48
app/Models/NailPolish.php Executable file
View File

@ -0,0 +1,48 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class NailPolish extends Model
{
use HasFactory;
/**
* Die Tabelle, die dem Model zugeordnet ist.
*/
protected $table = 'nail_polishes';
protected $fillable = [
'name',
'number',
'manufacturer_id',
'image_path',
];
/**
* Beziehung zu Benutzern
*/
public function users()
{
return $this->belongsToMany(User::class, 'user_nail_polishes', 'nail_polish_id', 'user_id');
}
/**
* Beziehung zum Hersteller
*/
public function manufacturer()
{
return $this->belongsTo(Manufacturer::class);
}
/**
* Scope für Suche nach Name oder Nummer
*/
public function scopeSearch($query, $search)
{
return $query->where('name', 'like', "%{$search}%")
->orWhere('number', 'like', "%{$search}%");
}
}

83
app/Models/User.php Executable file
View File

@ -0,0 +1,83 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
'is_admin',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
/**
* Beziehung zu Nagellacken
*/
public function nailPolishes()
{
return $this->belongsToMany(NailPolish::class, 'user_nail_polishes', 'user_id', 'nail_polish_id');
}
/**
* Prüft, ob der User ein Admin ist
*/
public function isAdmin()
{
return $this->is_admin || in_array($this->email, ['admin@neonail.com', 'neueradmin@neonail.com']);
}
/**
* Macht den User zum Admin
*/
public function makeAdmin()
{
$this->is_admin = true;
$this->save();
}
/**
* Entfernt Admin-Rechte
*/
public function removeAdmin()
{
$this->is_admin = false;
$this->save();
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
if (config('app.env') === 'production') {
URL::forceScheme('https');
}
}
}

18
artisan Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env php
<?php
use Illuminate\Foundation\Application;
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
// Bootstrap Laravel and handle the command...
/** @var Application $app */
$app = require_once __DIR__.'/bootstrap/app.php';
$status = $app->handleCommand(new ArgvInput);
exit($status);

24
bootstrap/app.php Executable file
View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
'admin' => \App\Http\Middleware\AdminMiddleware::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'auth' => \App\Http\Middleware\Authenticate::class,
]);
})
->withExceptions(function (Exceptions $exceptions): void {
//
})
->withProviders()
->create();

2
bootstrap/cache/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

6
bootstrap/providers.php Executable file
View File

@ -0,0 +1,6 @@
<?php
return [
App\Providers\AppServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
];

53
check-admin-user.php Executable file
View File

@ -0,0 +1,53 @@
<?php
// Admin-User Status prüfen
require_once 'vendor/autoload.php';
use App\Models\User;
try {
// Laravel App initialisieren
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
echo "<h1>🔍 Admin-User Status</h1>";
// Alle User anzeigen
$users = User::all();
if ($users->count() > 0) {
echo "<h2>✅ Benutzer gefunden:</h2>";
echo "<table border='1' style='border-collapse: collapse;'>";
echo "<tr><th>ID</th><th>Name</th><th>Email</th><th>Erstellt</th></tr>";
foreach ($users as $user) {
echo "<tr>";
echo "<td>{$user->id}</td>";
echo "<td>{$user->name}</td>";
echo "<td>{$user->email}</td>";
echo "<td>{$user->created_at}</td>";
echo "</tr>";
}
echo "</table>";
// Admin-User finden
$admin = User::where('email', 'admin@neonail.com')->first();
if ($admin) {
echo "<h2>👑 Admin-User gefunden:</h2>";
echo "<p><strong>Name:</strong> {$admin->name}</p>";
echo "<p><strong>Email:</strong> {$admin->email}</p>";
echo "<p><strong>ID:</strong> {$admin->id}</p>";
}
} else {
echo "<h2>❌ Keine Benutzer gefunden</h2>";
echo "<p>Bitte Admin-User erstellen:</p>";
echo "<code>php artisan tinker</code><br>";
echo "<code>use App\Models\User;</code><br>";
echo "<code>User::create(['name' => 'Admin', 'email' => 'admin@neonail.com', 'password' => bcrypt('ihr_passwort')]);</code>";
}
} catch (Exception $e) {
echo "<h2>❌ Fehler:</h2>";
echo "<p>{$e->getMessage()}</p>";
}
?>

45
check-laravel-logs.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash
echo "🔍 Laravel Logs prüfen"
echo "====================="
echo "1. 📝 Laravel Log-Datei:"
echo "----------------------"
if [ -f "storage/logs/laravel.log" ]; then
echo "✅ Laravel Log gefunden"
echo "Letzte 20 Zeilen:"
tail -20 storage/logs/laravel.log
else
echo "❌ Laravel Log nicht gefunden"
fi
echo ""
echo "2. 📝 Apache Error Log:"
echo "---------------------"
if [ -f "/var/log/apache2/neonail_error.log" ]; then
echo "✅ NeoNail Error Log gefunden"
echo "Letzte 10 Zeilen:"
tail -10 /var/log/apache2/neonail_error.log
else
echo "❌ NeoNail Error Log nicht gefunden"
echo "Standard Apache Error Log:"
tail -10 /var/log/apache2/error.log
fi
echo ""
echo "3. 🔧 Laravel Debug aktivieren:"
echo "-----------------------------"
echo "Setze APP_DEBUG=true in .env..."
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
echo "✅ Debug aktiviert"
echo ""
echo "4. 🧪 Test-Request mit Debug:"
echo "---------------------------"
curl -I http://192.168.30.81
echo ""
echo "📋 Nächste Schritte:"
echo "1. Browser öffnen: http://192.168.30.81"
echo "2. Fehlermeldung anzeigen lassen"
echo "3. Logs prüfen für Details"

77
check-user-collection.php Normal file
View File

@ -0,0 +1,77 @@
<?php
// User-Sammlung prüfen
require_once 'vendor/autoload.php';
use App\Models\User;
use App\Models\NailPolish;
try {
// Laravel App initialisieren
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
echo "<h1>🔍 User-Sammlung prüfen</h1>";
// Admin-User finden
$admin = User::where('email', 'admin@neonail.com')->first();
if ($admin) {
echo "<h2>👑 Admin-User gefunden:</h2>";
echo "<p><strong>Name:</strong> {$admin->name}</p>";
echo "<p><strong>Email:</strong> {$admin->email}</p>";
echo "<p><strong>ID:</strong> {$admin->id}</p>";
// Sammlung prüfen
$collection = $admin->nailPolishes;
echo "<h2>📦 Sammlung ({$collection->count()} Lacke):</h2>";
if ($collection->count() > 0) {
echo "<table border='1' style='border-collapse: collapse;'>";
echo "<tr><th>ID</th><th>Name</th><th>Nummer</th><th>Bild</th></tr>";
foreach ($collection as $polish) {
echo "<tr>";
echo "<td>{$polish->id}</td>";
echo "<td>{$polish->name}</td>";
echo "<td>{$polish->number}</td>";
echo "<td>" . ($polish->image_path ? "" : "") . "</td>";
echo "</tr>";
}
echo "</table>";
} else {
echo "<p>❌ Keine Lacke in der Sammlung</p>";
}
// Alle Lacke prüfen
echo "<h2>🗄️ Alle Lacke in der Datenbank:</h2>";
$allPolishes = NailPolish::all();
if ($allPolishes->count() > 0) {
echo "<table border='1' style='border-collapse: collapse;'>";
echo "<tr><th>ID</th><th>Name</th><th>Nummer</th><th>Bild</th><th>In Sammlung</th></tr>";
foreach ($allPolishes as $polish) {
$inCollection = $admin->nailPolishes()->where('nail_polish_id', $polish->id)->exists();
echo "<tr>";
echo "<td>{$polish->id}</td>";
echo "<td>{$polish->name}</td>";
echo "<td>{$polish->number}</td>";
echo "<td>" . ($polish->image_path ? "" : "") . "</td>";
echo "<td>" . ($inCollection ? "" : "") . "</td>";
echo "</tr>";
}
echo "</table>";
} else {
echo "<p>❌ Keine Lacke in der Datenbank</p>";
}
} else {
echo "<h2>❌ Admin-User nicht gefunden</h2>";
}
} catch (Exception $e) {
echo "<h2>❌ Fehler:</h2>";
echo "<p>{$e->getMessage()}</p>";
}
?>

37
clear-route-cache.sh Executable file
View File

@ -0,0 +1,37 @@
#!/bin/bash
echo "🧹 Route-Cache leeren"
echo "===================="
# 1. Laravel Cache leeren
echo "1. Laravel Cache leeren..."
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan route:clear 2>/dev/null || echo "⚠️ route:clear übersprungen"
php artisan view:clear 2>/dev/null || echo "⚠️ view:clear übersprungen"
# 2. Bootstrap Cache leeren
echo "2. Bootstrap Cache leeren..."
rm -f bootstrap/cache/*.php 2>/dev/null || echo "⚠️ bootstrap/cache/*.php nicht gefunden"
# 3. Route-Test ausführen
echo "3. Route-Test ausführen..."
php test-route-fix.php
# 4. Debug-Modus aktivieren
echo "4. Debug-Modus aktivieren..."
if [ -f .env ]; then
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
sed -i 's/APP_ENV=production/APP_ENV=local/' .env
echo "✅ Debug-Modus aktiviert"
else
echo "❌ .env Datei nicht gefunden"
fi
echo ""
echo "✅ Route-Cache geleert!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. https://neonail.vogt.de.com/create-nail-polish"
echo "2. Versuchen Sie einen neuen Lack zu erstellen"
echo "3. Falls Problem besteht: php artisan route:list | grep create"

72
complete-fix.sh Executable file
View File

@ -0,0 +1,72 @@
#!/bin/bash
echo "🔧 NeoNail DB - Vollständige Reparatur"
echo "====================================="
# 1. SQLite-Treiber installieren
echo "🗄️ Installiere SQLite-Treiber..."
apt update
apt install -y sqlite3 php-sqlite3 php-pdo-sqlite
# 2. Cache-Dateien löschen (Pail-Problem)
echo "🧹 Lösche Cache-Dateien..."
rm -f bootstrap/cache/packages.php
rm -f bootstrap/cache/services.php
rm -f bootstrap/cache/config.php
# 3. .env erstellen
echo "📝 Erstelle .env Datei..."
if [ ! -f ".env" ]; then
cp env-production-example.txt .env
fi
# 4. SQLite-Datenbank erstellen
echo "🗄️ Erstelle SQLite-Datenbank..."
touch database.sqlite
chmod 664 database.sqlite
# 5. Berechtigungen setzen
echo "🔐 Setze Berechtigungen..."
chmod -R 777 storage/
chmod -R 777 bootstrap/cache/
chmod 644 .env
# 6. Composer autoload neu generieren
echo "🔄 Generiere autoload neu..."
if command -v composer &> /dev/null; then
composer dump-autoload --optimize
elif [ -f "composer.phar" ]; then
php composer.phar dump-autoload --optimize
else
echo "⚠️ Composer nicht verfügbar"
fi
# 7. Laravel Cache leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
# 8. Migrationen ausführen
echo "🗃️ Führe Migrationen aus..."
php artisan migrate --force 2>/dev/null || echo "⚠️ Migrationen übersprungen"
# 9. Storage Link erstellen
echo "🔗 Prüfe Storage Link..."
if [ ! -L "public/storage" ]; then
php artisan storage:link 2>/dev/null || echo "⚠️ Storage Link übersprungen"
else
echo "✅ Storage Link bereits vorhanden"
fi
echo ""
echo "✅ Vollständige Reparatur abgeschlossen!"
echo ""
echo "📋 Testen Sie:"
echo "1. php artisan --version"
echo "2. php -m | grep sqlite"
echo "3. http://192.168.30.81"
echo ""
echo "📋 Admin-User erstellen:"
echo "php artisan tinker"
echo "use App\Models\User;"
echo "User::create(['name' => 'Admin', 'email' => 'admin@neonail.com', 'password' => bcrypt('ihr_passwort')]);"

79
composer.json Executable file
View File

@ -0,0 +1,79 @@
{
"$schema": "https://getcomposer.org/schema.json",
"name": "laravel/laravel",
"type": "project",
"description": "The skeleton application for the Laravel framework.",
"keywords": ["laravel", "framework"],
"license": "MIT",
"require": {
"php": "^8.2",
"intervention/image": "^3.11",
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1",
"laravel/ui": "*",
"smalot/pdfparser": "^2.12"
},
"require-dev": {
"fakerphp/faker": "^1.23",
"laravel/pail": "^1.2.2",
"laravel/pint": "^1.13",
"laravel/sail": "^1.41",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.6",
"phpunit/phpunit": "^11.5.3"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"post-autoload-dump": [
"@php artisan config:clear",
"@php artisan clear-compiled",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
"@php artisan migrate --graceful --ansi"
],
"dev": [
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
],
"test": [
"@php artisan config:clear --ansi",
"@php artisan test"
]
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
}
},
"minimum-stability": "stable",
"prefer-stable": true
}

8424
composer.lock generated Executable file

File diff suppressed because it is too large Load Diff

126
config/app.php Executable file
View File

@ -0,0 +1,126 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
|
| This value is the name of your application, which will be used when the
| framework needs to place the application's name in a notification or
| other UI elements where an application name needs to be displayed.
|
*/
'name' => env('APP_NAME', 'Laravel'),
/*
|--------------------------------------------------------------------------
| Application Environment
|--------------------------------------------------------------------------
|
| This value determines the "environment" your application is currently
| running in. This may determine how you prefer to configure various
| services the application utilizes. Set this in your ".env" file.
|
*/
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| the application so that it's available within Artisan commands.
|
*/
'url' => env('APP_URL', 'http://localhost'),
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. The timezone
| is set to "UTC" by default as it is suitable for most use cases.
|
*/
'timezone' => 'UTC',
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by Laravel's translation / localization methods. This option can be
| set to any locale for which you plan to have translation strings.
|
*/
'locale' => env('APP_LOCALE', 'en'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| This key is utilized by Laravel's encryption services and should be set
| to a random, 32 character string to ensure that all encrypted values
| are secure. You should do this prior to deploying the application.
|
*/
'cipher' => 'AES-256-CBC',
'key' => env('APP_KEY'),
'previous_keys' => [
...array_filter(
explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
),
],
/*
|--------------------------------------------------------------------------
| Maintenance Mode Driver
|--------------------------------------------------------------------------
|
| These configuration options determine the driver used to determine and
| manage Laravel's "maintenance mode" status. The "cache" driver will
| allow maintenance mode to be controlled across multiple machines.
|
| Supported drivers: "file", "cache"
|
*/
'maintenance' => [
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
'store' => env('APP_MAINTENANCE_STORE', 'database'),
],
];

115
config/auth.php Executable file
View File

@ -0,0 +1,115 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option defines the default authentication "guard" and password
| reset "broker" for your application. You may change these values
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| which utilizes session storage plus the Eloquent user provider.
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| If you have multiple user tables or models you may configure multiple
| providers to represent the model / table. These providers may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| These configuration options specify the behavior of Laravel's password
| reset functionality, including the table utilized for token storage
| and the user provider that is invoked to actually retrieve users.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
| The throttle setting is the number of seconds a user must wait before
| generating more password reset tokens. This prevents the user from
| quickly generating a very large amount of password reset tokens.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the number of seconds before a password confirmation
| window expires and users are asked to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];

108
config/cache.php Executable file
View File

@ -0,0 +1,108 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache store that will be used by the
| framework. This connection is utilized if another isn't explicitly
| specified when running a cache operation inside the application.
|
*/
'default' => env('CACHE_STORE', 'database'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
| Supported drivers: "array", "database", "file", "memcached",
| "redis", "dynamodb", "octane", "null"
|
*/
'stores' => [
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'connection' => env('DB_CACHE_CONNECTION'),
'table' => env('DB_CACHE_TABLE', 'cache'),
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
'lock_path' => storage_path('framework/cache/data'),
],
'memcached' => [
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
'octane' => [
'driver' => 'octane',
],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
| stores, there might be other applications using the same cache. For
| that reason, you may prefix every cache key to avoid collisions.
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'),
];

8
config/csrf.php Normal file
View File

@ -0,0 +1,8 @@
<?php
return [
'cookie' => [
'secure' => true,
'same_site' => 'lax',
],
];

174
config/database.php Executable file
View File

@ -0,0 +1,174 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for database operations. This is
| the connection which will be utilized unless another connection
| is explicitly specified when you execute a query / statement.
|
*/
'default' => env('DB_CONNECTION', 'sqlite'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Below are all of the database connections defined for your application.
| An example configuration is provided for each database system which
| is supported by Laravel. You're free to add / remove connections.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DB_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'busy_timeout' => null,
'journal_mode' => null,
'synchronous' => null,
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mariadb' => [
'driver' => 'mariadb',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DB_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run on the database.
|
*/
'migrations' => [
'table' => 'migrations',
'update_date_on_publish' => true,
],
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as Memcached. You may define your connection settings here.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-database-'),
'persistent' => env('REDIS_PERSISTENT', false),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
];

80
config/filesystems.php Executable file
View File

@ -0,0 +1,80 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application for file storage.
|
*/
'default' => env('FILESYSTEM_DISK', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Below you may configure as many filesystem disks as necessary, and you
| may even configure multiple disks for the same driver. Examples for
| most supported storage drivers are configured here for reference.
|
| Supported drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'serve' => true,
'throw' => false,
'report' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
'report' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'report' => false,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];

132
config/logging.php Executable file
View File

@ -0,0 +1,132 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Processor\PsrLogMessageProcessor;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that is utilized to write
| messages to your logs. The value provided here should match one of
| the channels present in the list of "channels" configured below.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Deprecations Log Channel
|--------------------------------------------------------------------------
|
| This option controls the log channel that should be used to log warnings
| regarding deprecated PHP and library features. This allows you to get
| your application ready for upcoming major versions of dependencies.
|
*/
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Laravel
| utilizes the Monolog PHP logging library, which includes a variety
| of powerful log handlers and formatters that you're free to use.
|
| Available drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog", "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => explode(',', (string) env('LOG_STACK', 'single')),
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
'replace_placeholders' => true,
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
'processors' => [PsrLogMessageProcessor::class],
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'handler_with' => [
'stream' => 'php://stderr',
],
'formatter' => env('LOG_STDERR_FORMATTER'),
'processors' => [PsrLogMessageProcessor::class],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
'replace_placeholders' => true,
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];

118
config/mail.php Executable file
View File

@ -0,0 +1,118 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Mailer
|--------------------------------------------------------------------------
|
| This option controls the default mailer that is used to send all email
| messages unless another mailer is explicitly specified when sending
| the message. All additional mailers can be configured within the
| "mailers" array. Examples of each type of mailer are provided.
|
*/
'default' => env('MAIL_MAILER', 'log'),
/*
|--------------------------------------------------------------------------
| Mailer Configurations
|--------------------------------------------------------------------------
|
| Here you may configure all of the mailers used by your application plus
| their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires.
|
| Laravel supports a variety of mail "transport" drivers that can be used
| when delivering an email. You may specify which one you're using for
| your mailers below. You may also add additional mailers if needed.
|
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
| "postmark", "resend", "log", "array",
| "failover", "roundrobin"
|
*/
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'scheme' => env('MAIL_SCHEME'),
'url' => env('MAIL_URL'),
'host' => env('MAIL_HOST', '127.0.0.1'),
'port' => env('MAIL_PORT', 2525),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url((string) env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
],
'ses' => [
'transport' => 'ses',
],
'postmark' => [
'transport' => 'postmark',
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
// 'client' => [
// 'timeout' => 5,
// ],
],
'resend' => [
'transport' => 'resend',
],
'sendmail' => [
'transport' => 'sendmail',
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
],
'log' => [
'transport' => 'log',
'channel' => env('MAIL_LOG_CHANNEL'),
],
'array' => [
'transport' => 'array',
],
'failover' => [
'transport' => 'failover',
'mailers' => [
'smtp',
'log',
],
'retry_after' => 60,
],
'roundrobin' => [
'transport' => 'roundrobin',
'mailers' => [
'ses',
'postmark',
],
'retry_after' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all emails sent by your application to be sent from
| the same address. Here you may specify a name and address that is
| used globally for all emails that are sent by your application.
|
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
];

112
config/queue.php Executable file
View File

@ -0,0 +1,112 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue supports a variety of backends via a single, unified
| API, giving you convenient access to each backend using identical
| syntax for each. The default queue connection is defined below.
|
*/
'default' => env('QUEUE_CONNECTION', 'database'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection options for every queue backend
| used by your application. An example configuration is provided for
| each backend supported by Laravel. You're also free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'connection' => env('DB_QUEUE_CONNECTION'),
'table' => env('DB_QUEUE_TABLE', 'jobs'),
'queue' => env('DB_QUEUE', 'default'),
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
'queue' => env('BEANSTALKD_QUEUE', 'default'),
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
'block_for' => 0,
'after_commit' => false,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => null,
'after_commit' => false,
],
],
/*
|--------------------------------------------------------------------------
| Job Batching
|--------------------------------------------------------------------------
|
| The following options configure the database and table that store job
| batching information. These options can be updated to any database
| connection and table which has been defined by your application.
|
*/
'batching' => [
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'job_batches',
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control how and where failed jobs are stored. Laravel ships with
| support for storing failed jobs in a simple file or in a database.
|
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'failed_jobs',
],
];

38
config/services.php Executable file
View File

@ -0,0 +1,38 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'resend' => [
'key' => env('RESEND_KEY'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],
];

217
config/session.php Executable file
View File

@ -0,0 +1,217 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option determines the default session driver that is utilized for
| incoming requests. Laravel supports a variety of storage options to
| persist session data. Database storage is a great default choice.
|
| Supported: "file", "cookie", "database", "memcached",
| "redis", "dynamodb", "array"
|
*/
'driver' => env('SESSION_DRIVER', 'database'),
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to expire immediately when the browser is closed then you may
| indicate that via the expire_on_close configuration option.
|
*/
'lifetime' => (int) env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
/*
|--------------------------------------------------------------------------
| Session Encryption
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
| should be encrypted before it's stored. All encryption is performed
| automatically by Laravel and you may use the session like normal.
|
*/
'encrypt' => env('SESSION_ENCRYPT', false),
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
| When utilizing the "file" session driver, the session files are placed
| on disk. The default storage location is defined here; however, you
| are free to provide another location where they should be stored.
|
*/
'files' => storage_path('framework/sessions'),
/*
|--------------------------------------------------------------------------
| Session Database Connection
|--------------------------------------------------------------------------
|
| When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options.
|
*/
'connection' => env('SESSION_CONNECTION'),
/*
|--------------------------------------------------------------------------
| Session Database Table
|--------------------------------------------------------------------------
|
| When using the "database" session driver, you may specify the table to
| be used to store sessions. Of course, a sensible default is defined
| for you; however, you're welcome to change this to another table.
|
*/
'table' => env('SESSION_TABLE', 'sessions'),
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
| When using one of the framework's cache driven session backends, you may
| define the cache store which should be used to store the session data
| between requests. This must match one of your defined cache stores.
|
| Affects: "dynamodb", "memcached", "redis"
|
*/
'store' => env('SESSION_STORE'),
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery
|--------------------------------------------------------------------------
|
| Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100.
|
*/
'lottery' => [2, 100],
/*
|--------------------------------------------------------------------------
| Session Cookie Name
|--------------------------------------------------------------------------
|
| Here you may change the name of the session cookie that is created by
| the framework. Typically, you should not need to change this value
| since doing so does not grant a meaningful security improvement.
|
*/
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel')).'-session'
),
/*
|--------------------------------------------------------------------------
| Session Cookie Path
|--------------------------------------------------------------------------
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
| your application, but you're free to change this when necessary.
|
*/
'path' => env('SESSION_PATH', '/'),
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| This value determines the domain and subdomains the session cookie is
| available to. By default, the cookie will be available to the root
| domain and all subdomains. Typically, this shouldn't be changed.
|
*/
'domain' => env('SESSION_DOMAIN'),
/*
|--------------------------------------------------------------------------
| HTTPS Only Cookies
|--------------------------------------------------------------------------
|
| By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you when it can't be done securely.
|
*/
'secure' => env('SESSION_SECURE_COOKIE'),
/*
|--------------------------------------------------------------------------
| HTTP Access Only
|--------------------------------------------------------------------------
|
| Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through
| the HTTP protocol. It's unlikely you should disable this option.
|
*/
'http_only' => env('SESSION_HTTP_ONLY', true),
/*
|--------------------------------------------------------------------------
| Same-Site Cookies
|--------------------------------------------------------------------------
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" to permit secure cross-site requests.
|
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
| Supported: "lax", "strict", "none", null
|
*/
'same_site' => env('SESSION_SAME_SITE', 'lax'),
/*
|--------------------------------------------------------------------------
| Partitioned Cookies
|--------------------------------------------------------------------------
|
| Setting this value to true will tie the cookie to the top-level site for
| a cross-site context. Partitioned cookies are accepted by the browser
| when flagged "secure" and the Same-Site attribute is set to "none".
|
*/
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
];

View File

@ -0,0 +1,15 @@
<?php
return [
'proxies' => [
'192.168.30.81',
'neonail.vogt.de.com',
'127.0.0.1',
'::1',
],
'headers' => [
'X-Forwarded-For' => 'X_FORWARDED_FOR',
'X-Forwarded-Host' => 'X_FORWARDED_HOST',
'X-Forwarded-Proto' => 'X_FORWARDED_PROTO',
],
];

40
create-admin.php Executable file
View File

@ -0,0 +1,40 @@
<?php
// Admin-User erstellen
echo "<h1>👑 Admin-User erstellen</h1>";
try {
// Laravel laden
require_once 'vendor/autoload.php';
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Prüfen ob Admin bereits existiert
$existingAdmin = \App\Models\User::where('email', 'admin@neonail.com')->first();
if ($existingAdmin) {
echo "<h2>✅ Admin-User existiert bereits!</h2>";
echo "<p><strong>Name:</strong> {$existingAdmin->name}</p>";
echo "<p><strong>Email:</strong> {$existingAdmin->email}</p>";
echo "<p><strong>ID:</strong> {$existingAdmin->id}</p>";
echo "<p><a href='http://192.168.30.81' style='background: #28a745; color: white; padding: 10px; text-decoration: none; border-radius: 5px;'>🚀 Zur Anwendung</a></p>";
} else {
// Admin-User erstellen
$admin = \App\Models\User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('admin123')
]);
echo "<h2>✅ Admin-User erstellt!</h2>";
echo "<p><strong>Name:</strong> {$admin->name}</p>";
echo "<p><strong>Email:</strong> {$admin->email}</p>";
echo "<p><strong>Passwort:</strong> admin123</p>";
echo "<p><strong>ID:</strong> {$admin->id}</p>";
echo "<p><a href='http://192.168.30.81' style='background: #28a745; color: white; padding: 10px; text-decoration: none; border-radius: 5px;'>🚀 Zur Anwendung</a></p>";
}
} catch (Exception $e) {
echo "<h2>❌ Fehler:</h2>";
echo "<p>{$e->getMessage()}</p>";
}
?>

BIN
database.sqlite Executable file

Binary file not shown.

1
database/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.sqlite*

View File

@ -0,0 +1,44 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* The current password being used by the factory.
*/
protected static ?string $password;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}

View File

@ -0,0 +1,49 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('cache');
Schema::dropIfExists('cache_locks');
}
};

View File

@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('jobs', function (Blueprint $table) {
$table->id();
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
Schema::create('job_batches', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('name');
$table->integer('total_jobs');
$table->integer('pending_jobs');
$table->integer('failed_jobs');
$table->longText('failed_job_ids');
$table->mediumText('options')->nullable();
$table->integer('cancelled_at')->nullable();
$table->integer('created_at');
$table->integer('finished_at')->nullable();
});
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('jobs');
Schema::dropIfExists('job_batches');
Schema::dropIfExists('failed_jobs');
}
};

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('manufacturers', function (Blueprint $table) {
$table->id();
$table->string('name')->unique(); // Name des Herstellers (eindeutig)
$table->text('description')->nullable(); // Beschreibung des Herstellers
$table->string('website')->nullable(); // Website des Herstellers
$table->string('country')->nullable(); // Land des Herstellers
$table->timestamps();
// Index für schnelle Suche
$table->index('name');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('manufacturers');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('nail_polishes', function (Blueprint $table) {
$table->id();
$table->string('name'); // Name des Nagellacks
$table->string('number'); // Nummer des Nagellacks
$table->string('image_path')->nullable(); // Pfad zum Bild
$table->timestamps();
// Index für schnelle Suche
$table->index(['name', 'number']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('nail_polishes');
}
};

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_nail_polishes', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('nail_polish_id')->constrained()->onDelete('cascade');
$table->timestamps();
// Verhindert doppelte Einträge
$table->unique(['user_id', 'nail_polish_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_nail_polishes');
}
};

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('nail_polishes', function (Blueprint $table) {
$table->foreignId('manufacturer_id')->nullable()->after('number')->constrained()->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('nail_polishes', function (Blueprint $table) {
$table->dropForeign(['manufacturer_id']);
$table->dropColumn('manufacturer_id');
});
}
};

View File

@ -0,0 +1,23 @@
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
}
}

118
debug-405-error.php Normal file
View File

@ -0,0 +1,118 @@
<?php
// Debug-Script für HTTP 405 Method Not Allowed Fehler
// Führen Sie dies aus, um das Problem zu diagnostizieren
echo "🔍 Debug: HTTP 405 Method Not Allowed\n";
echo "====================================\n\n";
// 1. Prüfe Laravel-Umgebung
echo "1. Laravel-Umgebung:\n";
echo " - APP_ENV: " . (getenv('APP_ENV') ?: 'nicht gesetzt') . "\n";
echo " - APP_DEBUG: " . (getenv('APP_DEBUG') ?: 'nicht gesetzt') . "\n";
echo " - APP_URL: " . (getenv('APP_URL') ?: 'nicht gesetzt') . "\n\n";
// 2. Prüfe Datenbankverbindung
echo "2. Datenbankverbindung:\n";
try {
$pdo = new PDO('sqlite:database.sqlite');
echo " ✅ SQLite-Verbindung erfolgreich\n";
// Prüfe users-Tabelle
$stmt = $pdo->query("SELECT COUNT(*) FROM users");
$userCount = $stmt->fetchColumn();
echo " - User in Datenbank: $userCount\n";
} catch (Exception $e) {
echo " ❌ Datenbankfehler: " . $e->getMessage() . "\n";
}
// 3. Prüfe Laravel-Routes
echo "\n3. Laravel-Routes:\n";
try {
// Simuliere Laravel-Bootstrap
require_once 'vendor/autoload.php';
// Erstelle Laravel-App
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Hole Router
$router = $app->make('router');
// Prüfe spezifische Route
$routes = $router->getRoutes();
$foundRoute = false;
foreach ($routes as $route) {
if ($route->getName() === 'user-nail-polishes.store') {
echo " ✅ Route 'user-nail-polishes.store' gefunden\n";
echo " - URI: " . $route->uri() . "\n";
echo " - Method: " . implode('|', $route->methods()) . "\n";
echo " - Controller: " . $route->getActionName() . "\n";
$foundRoute = true;
break;
}
}
if (!$foundRoute) {
echo " ❌ Route 'user-nail-polishes.store' nicht gefunden\n";
}
// Zeige alle POST-Routes
echo "\n 📋 Alle POST-Routes:\n";
foreach ($routes as $route) {
if (in_array('POST', $route->methods())) {
echo " - " . $route->uri() . " -> " . $route->getName() . "\n";
}
}
} catch (Exception $e) {
echo " ❌ Laravel-Fehler: " . $e->getMessage() . "\n";
}
// 4. Prüfe Dateisystem
echo "\n4. Dateisystem:\n";
$files = [
'routes/web.php' => 'Route-Definitionen',
'app/Http/Controllers/UserNailPolishController.php' => 'Controller',
'resources/views/user-nail-polishes/create.blade.php' => 'Create-View',
'bootstrap/app.php' => 'Laravel-Bootstrap',
'vendor/autoload.php' => 'Composer Autoload'
];
foreach ($files as $file => $description) {
if (file_exists($file)) {
echo "$description: $file\n";
} else {
echo "$description fehlt: $file\n";
}
}
// 5. Prüfe .htaccess
echo "\n5. .htaccess-Konfiguration:\n";
$htaccessFiles = [
'.htaccess' => 'Hauptverzeichnis',
'public/.htaccess' => 'Public-Verzeichnis'
];
foreach ($htaccessFiles as $file => $location) {
if (file_exists($file)) {
echo "$location .htaccess gefunden\n";
$content = file_get_contents($file);
if (strpos($content, 'RewriteEngine On') !== false) {
echo " - RewriteEngine aktiviert\n";
}
if (strpos($content, 'index.php') !== false) {
echo " - index.php Weiterleitung konfiguriert\n";
}
} else {
echo "$location .htaccess fehlt\n";
}
}
echo "\n🔧 Nächste Schritte:\n";
echo "1. Prüfen Sie die Laravel-Logs: storage/logs/laravel.log\n";
echo "2. Aktivieren Sie APP_DEBUG=true in .env\n";
echo "3. Leeren Sie den Cache: php artisan cache:clear\n";
echo "4. Prüfen Sie die Apache-Logs für weitere Details\n";
?>

131
debug-500-error.php Normal file
View File

@ -0,0 +1,131 @@
<?php
// Debug-Script für HTTP 500 Internal Server Error
// Führen Sie dies aus, um das Problem zu diagnostizieren
echo "🔍 Debug: HTTP 500 Internal Server Error\n";
echo "=======================================\n\n";
// 1. Prüfe Laravel-Logs
echo "1. Laravel-Logs prüfen:\n";
$logFiles = [
'storage/logs/laravel.log',
'storage/logs/laravel-' . date('Y-m-d') . '.log'
];
foreach ($logFiles as $logFile) {
if (file_exists($logFile)) {
echo " 📋 $logFile gefunden\n";
echo " 📄 Letzte 10 Zeilen:\n";
$lines = file($logFile);
$lastLines = array_slice($lines, -10);
foreach ($lastLines as $line) {
echo " " . trim($line) . "\n";
}
} else {
echo "$logFile nicht gefunden\n";
}
}
// 2. Prüfe PHP-Fehler
echo "\n2. PHP-Fehler prüfen:\n";
$errorLog = ini_get('error_log');
if ($errorLog && file_exists($errorLog)) {
echo " 📋 PHP Error Log: $errorLog\n";
$lines = file($errorLog);
$lastLines = array_slice($lines, -5);
foreach ($lastLines as $line) {
echo " " . trim($line) . "\n";
}
} else {
echo " ⚠️ PHP Error Log nicht verfügbar\n";
}
// 3. Prüfe Apache-Logs
echo "\n3. Apache-Logs prüfen:\n";
$apacheLogs = [
'/var/log/apache2/error.log',
'/var/log/apache2/neonail_error.log'
];
foreach ($apacheLogs as $logFile) {
if (file_exists($logFile)) {
echo " 📋 $logFile gefunden\n";
echo " 📄 Letzte 5 Zeilen:\n";
$lines = file($logFile);
$lastLines = array_slice($lines, -5);
foreach ($lastLines as $line) {
echo " " . trim($line) . "\n";
}
} else {
echo "$logFile nicht gefunden\n";
}
}
// 4. Prüfe Dateisystem
echo "\n4. Dateisystem prüfen:\n";
$criticalFiles = [
'public/index.php' => 'Laravel Entry Point',
'bootstrap/app.php' => 'Laravel Bootstrap',
'vendor/autoload.php' => 'Composer Autoload',
'config/app.php' => 'App Config',
'.env' => 'Environment File',
'database.sqlite' => 'Database File'
];
foreach ($criticalFiles as $file => $description) {
if (file_exists($file)) {
$perms = substr(sprintf('%o', fileperms($file)), -4);
echo "$description: $file (Perms: $perms)\n";
} else {
echo "$description fehlt: $file\n";
}
}
// 5. Prüfe Verzeichnisberechtigungen
echo "\n5. Verzeichnisberechtigungen prüfen:\n";
$directories = [
'storage' => 'Storage Directory',
'storage/logs' => 'Logs Directory',
'storage/framework' => 'Framework Directory',
'storage/framework/cache' => 'Cache Directory',
'storage/framework/sessions' => 'Sessions Directory',
'storage/framework/views' => 'Views Directory',
'bootstrap/cache' => 'Bootstrap Cache'
];
foreach ($directories as $dir => $description) {
if (is_dir($dir)) {
$perms = substr(sprintf('%o', fileperms($dir)), -4);
$writable = is_writable($dir) ? 'writable' : 'not writable';
echo "$description: $dir (Perms: $perms, $writable)\n";
} else {
echo "$description fehlt: $dir\n";
}
}
// 6. Prüfe Laravel-Bootstrap
echo "\n6. Laravel-Bootstrap Test:\n";
try {
require_once 'vendor/autoload.php';
echo " ✅ Composer Autoload erfolgreich\n";
$app = require_once 'bootstrap/app.php';
echo " ✅ Laravel App erstellt\n";
$kernel = $app->make('Illuminate\Contracts\Console\Kernel');
echo " ✅ Kernel erstellt\n";
$kernel->bootstrap();
echo " ✅ Laravel Bootstrap erfolgreich\n";
} catch (Exception $e) {
echo " ❌ Laravel-Fehler: " . $e->getMessage() . "\n";
echo " 📍 Datei: " . $e->getFile() . ":" . $e->getLine() . "\n";
}
echo "\n🔧 Nächste Schritte:\n";
echo "1. Prüfen Sie die Laravel-Logs für detaillierte Fehlermeldungen\n";
echo "2. Aktivieren Sie APP_DEBUG=true in .env\n";
echo "3. Prüfen Sie die Apache-Logs für Server-Fehler\n";
echo "4. Stellen Sie sicher, dass alle Verzeichnisse beschreibbar sind\n";
?>

194
debug-image-upload.php Normal file
View File

@ -0,0 +1,194 @@
<?php
// Debug: Bild-Upload Problem
echo "🔍 Debug: Bild-Upload Problem\n";
echo "============================\n\n";
// 1. PHP-Upload-Einstellungen
echo "1. PHP-Upload-Einstellungen:\n";
$uploadSettings = [
'upload_max_filesize' => ini_get('upload_max_filesize'),
'post_max_size' => ini_get('post_max_size'),
'max_file_uploads' => ini_get('max_file_uploads'),
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'max_input_time' => ini_get('max_input_time'),
'file_uploads' => ini_get('file_uploads'),
'upload_tmp_dir' => ini_get('upload_tmp_dir')
];
foreach ($uploadSettings as $setting => $value) {
echo " - $setting: $value\n";
}
// 2. GD Extension prüfen
echo "\n2. GD Extension prüfen:\n";
if (extension_loaded('gd')) {
echo " ✅ GD Extension geladen\n";
$gdInfo = gd_info();
echo " - GD Version: " . $gdInfo['GD Version'] . "\n";
echo " - JPEG Support: " . ($gdInfo['JPEG Support'] ? 'Ja' : 'Nein') . "\n";
echo " - PNG Support: " . ($gdInfo['PNG Support'] ? 'Ja' : 'Nein') . "\n";
echo " - GIF Support: " . ($gdInfo['GIF Support'] ? 'Ja' : 'Nein') . "\n";
} else {
echo " ❌ GD Extension nicht geladen\n";
}
// 3. Intervention Image prüfen
echo "\n3. Intervention Image prüfen:\n";
try {
require_once 'vendor/autoload.php';
if (class_exists('Intervention\Image\ImageManager')) {
echo " ✅ Intervention Image verfügbar\n";
// Test ImageManager
$manager = new \Intervention\Image\ImageManager(new \Intervention\Image\Drivers\Gd\Driver());
echo " ✅ ImageManager funktioniert\n";
} else {
echo " ❌ Intervention Image nicht verfügbar\n";
}
} catch (Exception $e) {
echo " ❌ Intervention Image Fehler: " . $e->getMessage() . "\n";
}
// 4. Storage-Verzeichnisse prüfen
echo "\n4. Storage-Verzeichnisse prüfen:\n";
$storagePaths = [
'storage' => 'Storage Root',
'storage/app' => 'Storage App',
'storage/app/public' => 'Storage Public',
'storage/app/public/nail_polishes' => 'Nail Polishes Storage',
'public/storage' => 'Public Storage Link'
];
foreach ($storagePaths as $path => $description) {
if (file_exists($path)) {
$perms = substr(sprintf('%o', fileperms($path)), -4);
$writable = is_writable($path) ? 'writable' : 'not writable';
$type = is_dir($path) ? 'directory' : (is_link($path) ? 'symlink' : 'file');
echo "$description: $path ($type, perms: $perms, $writable)\n";
} else {
echo "$description: $path (nicht gefunden)\n";
}
}
// 5. Laravel Storage Link prüfen
echo "\n5. Laravel Storage Link prüfen:\n";
$publicStoragePath = 'public/storage';
if (is_link($publicStoragePath)) {
$target = readlink($publicStoragePath);
echo " ✅ Storage Link existiert: $publicStoragePath -> $target\n";
} else {
echo " ⚠️ Storage Link existiert nicht\n";
// Versuche Storage Link zu erstellen
try {
if (file_exists('storage/app/public')) {
if (is_dir('public/storage')) {
rmdir('public/storage');
}
symlink('../storage/app/public', 'public/storage');
echo " ✅ Storage Link erstellt\n";
} else {
echo " ❌ storage/app/public existiert nicht\n";
}
} catch (Exception $e) {
echo " ❌ Storage Link erstellen fehlgeschlagen: " . $e->getMessage() . "\n";
}
}
// 6. Laravel-Logs prüfen
echo "\n6. Laravel-Logs prüfen:\n";
$logFiles = [
'storage/logs/laravel.log',
'storage/logs/laravel-' . date('Y-m-d') . '.log'
];
foreach ($logFiles as $logFile) {
if (file_exists($logFile)) {
echo " 📋 $logFile gefunden\n";
$lines = file($logFile);
$lastLines = array_slice($lines, -5);
echo " 📄 Letzte 5 Zeilen:\n";
foreach ($lastLines as $line) {
if (strpos($line, 'error') !== false || strpos($line, 'Exception') !== false || strpos($line, 'upload') !== false) {
echo " " . trim($line) . "\n";
}
}
} else {
echo "$logFile nicht gefunden\n";
}
}
// 7. Test-Bild erstellen
echo "\n7. Test-Bild erstellen:\n";
try {
$testImagePath = 'storage/app/public/nail_polishes/test.jpg';
if (extension_loaded('gd')) {
// Erstelle ein einfaches Test-Bild
$image = imagecreate(100, 100);
$bgColor = imagecolorallocate($image, 255, 255, 255);
$textColor = imagecolorallocate($image, 0, 0, 0);
imagestring($image, 5, 10, 40, 'TEST', $textColor);
if (imagejpeg($image, $testImagePath, 80)) {
echo " ✅ Test-Bild erstellt: $testImagePath\n";
// Prüfe ob Bild über Web erreichbar ist
$webPath = 'public/storage/nail_polishes/test.jpg';
if (file_exists($webPath)) {
echo " ✅ Test-Bild über Web erreichbar\n";
} else {
echo " ❌ Test-Bild nicht über Web erreichbar\n";
}
} else {
echo " ❌ Test-Bild erstellen fehlgeschlagen\n";
}
imagedestroy($image);
} else {
echo " ❌ GD Extension nicht verfügbar für Test-Bild\n";
}
} catch (Exception $e) {
echo " ❌ Test-Bild Fehler: " . $e->getMessage() . "\n";
}
// 8. Controller-Code prüfen
echo "\n8. Controller-Code prüfen:\n";
$controllerPath = 'app/Http/Controllers/UserNailPolishController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
// Prüfe ImageManager Import
if (strpos($content, 'use Intervention\\Image\\ImageManager') !== false) {
echo " ✅ ImageManager Import vorhanden\n";
} else {
echo " ❌ ImageManager Import fehlt\n";
}
// Prüfe Driver Import
if (strpos($content, 'use Intervention\\Image\\Drivers\\Gd\\Driver') !== false) {
echo " ✅ Driver Import vorhanden\n";
} else {
echo " ❌ Driver Import fehlt\n";
}
// Prüfe Bildverarbeitungscode
if (strpos($content, 'new ImageManager(new Driver())') !== false) {
echo " ✅ Bildverarbeitungscode vorhanden\n";
} else {
echo " ❌ Bildverarbeitungscode fehlt\n";
}
} else {
echo " ❌ Controller nicht gefunden\n";
}
echo "\n✅ Bild-Upload Debug abgeschlossen!\n";
echo "🔗 Testen Sie jetzt: https://neonail.vogt.de.com/create-nail-polish\n";
echo "\n📋 Nächste Schritte:\n";
echo "1. Prüfen Sie die Laravel-Logs für spezifische Fehlermeldungen\n";
echo "2. Testen Sie mit einem kleinen Bild (< 1MB)\n";
echo "3. Prüfen Sie Browser-Entwicklertools (F12) für Netzwerk-Fehler\n";
echo "4. Schauen Sie in Apache-Logs für Server-Fehler\n";
?>

202
debug-logout-detailed.php Normal file
View File

@ -0,0 +1,202 @@
<?php
// Debug: Logout-Problem detailliert debuggen
echo "🔍 Debug: Logout-Problem detailliert debuggen\n";
echo "============================================\n\n";
// 1. Aktuelles Layout prüfen
echo "1. 🎨 Aktuelles Layout prüfen...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Zeige alle Logout-bezogenen Zeilen
$lines = explode("\n", $content);
$logoutLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
$logoutLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
if (!empty($logoutLines)) {
echo " ✅ Logout-bezogene Zeilen gefunden:\n";
foreach ($logoutLines as $line) {
echo " 📋 $line\n";
}
} else {
echo " ❌ Keine Logout-bezogenen Zeilen gefunden\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 2. Routes prüfen
echo "\n2. 🛣️ Routes prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Zeige alle Logout-bezogenen Zeilen
$lines = explode("\n", $content);
$logoutLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
$logoutLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
if (!empty($logoutLines)) {
echo " ✅ Logout-Routes gefunden:\n";
foreach ($logoutLines as $line) {
echo " 📋 $line\n";
}
} else {
echo " ❌ Keine Logout-Routes gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 3. LoginController prüfen
echo "\n3. 🔐 LoginController prüfen...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
if (strpos($content, 'public function logout') !== false) {
echo " ✅ Logout-Methode vorhanden\n";
// Zeige Logout-Methode
$lines = explode("\n", $content);
$inLogoutMethod = false;
$methodLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'public function logout') !== false) {
$inLogoutMethod = true;
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
} elseif ($inLogoutMethod && strpos($line, 'public function') !== false) {
$inLogoutMethod = false;
} elseif ($inLogoutMethod) {
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
echo " 📋 Logout-Methode:\n";
foreach ($methodLines as $line) {
echo " $line\n";
}
} else {
echo " ❌ Logout-Methode nicht gefunden\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 4. Einfache Logout-Route erstellen
echo "\n4. 🛣️ Einfache Logout-Route erstellen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Prüfe ob GET Logout-Route existiert
if (strpos($content, "Route::get('/logout', [LoginController::class, 'logout'])->name('logout');") === false) {
// Füge GET Logout-Route hinzu
$newRoute = "\n// Einfache Logout-Route für Debugging\nRoute::get('/logout', [App\\Http\\Controllers\\Auth\\LoginController::class, 'logout'])->name('logout');\n";
// Füge am Ende der Datei hinzu
$content .= $newRoute;
file_put_contents($routesPath, $content);
echo " ✅ GET Logout-Route hinzugefügt\n";
} else {
echo " GET Logout-Route bereits vorhanden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 5. LoginController erweitern
echo "\n5. 🔐 LoginController erweitern...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
// Prüfe ob Logout-Methode GET und POST unterstützt
if (strpos($content, 'public function logout(Request $request)') !== false) {
echo " ✅ Logout-Methode unterstützt bereits GET und POST\n";
} else {
echo " Logout-Methode prüfen...\n";
}
// Zeige aktuelle Logout-Methode
$lines = explode("\n", $content);
$inLogoutMethod = false;
$methodLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'public function logout') !== false) {
$inLogoutMethod = true;
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
} elseif ($inLogoutMethod && strpos($line, 'public function') !== false) {
$inLogoutMethod = false;
} elseif ($inLogoutMethod) {
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
echo " 📋 Aktuelle Logout-Methode:\n";
foreach ($methodLines as $line) {
echo " $line\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 6. Cache leeren
echo "\n6. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 7. Test-Logout-Links erstellen
echo "\n7. 🧪 Test-Logout-Links erstellen...\n";
$testLinks = [
'https://neonail.vogt.de.com/logout (GET)',
'https://neonail.vogt.de.com/logout (POST)',
'https://neonail.vogt.de.com/',
'https://neonail.vogt.de.com/login'
];
foreach ($testLinks as $link) {
echo " 🔗 $link\n";
}
// 8. Debug-Anleitung
echo "\n8. 🔍 Debug-Anleitung...\n";
echo " 📋 1. Öffnen Sie: https://neonail.vogt.de.com\n";
echo " 📋 2. Melden Sie sich an\n";
echo " 📋 3. Öffnen Sie Browser-Entwicklertools (F12)\n";
echo " 📋 4. Gehen Sie zu Console-Tab\n";
echo " 📋 5. Klicken Sie auf Ihren Benutzernamen\n";
echo " 📋 6. Wählen Sie 'Abmelden'\n";
echo " 📋 7. Schauen Sie nach JavaScript-Fehlern\n";
echo " 📋 8. Gehen Sie zu Network-Tab\n";
echo " 📋 9. Schauen Sie welche URL aufgerufen wird\n";
echo " 📋 10. Testen Sie direkt: https://neonail.vogt.de.com/logout\n";
echo "\n✅ Detailliertes Logout-Debug abgeschlossen!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Das normale Logout über das Dropdown\n";
echo "2. Den direkten Link: https://neonail.vogt.de.com/logout\n";
echo "3. Teilen Sie alle Fehlermeldungen mit\n";
?>

218
debug-logout.php Normal file
View File

@ -0,0 +1,218 @@
<?php
// Debug: Logout-Problem systematisch debuggen
echo "🚪 Debug: Logout-Problem systematisch debuggen\n";
echo "=============================================\n\n";
// 1. Aktuelles Layout prüfen
echo "1. 🎨 Aktuelles Layout prüfen...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Suche nach Logout-Form
if (strpos($content, 'logout-form') !== false) {
echo " ✅ Logout-Form gefunden\n";
// Zeige Logout-Form Details
$lines = explode("\n", $content);
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 Zeile " . ($lineNumber + 1) . ": " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Form nicht gefunden\n";
}
// Prüfe Route-Verwendung
if (strpos($content, '{{ route("logout") }}') !== false) {
echo " ✅ Laravel Route wird verwendet\n";
} elseif (strpos($content, 'https://neonail.vogt.de.com/logout') !== false) {
echo " ❌ Hardcodierte URL wird verwendet\n";
} else {
echo " ❓ Unbekannte Logout-Konfiguration\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 2. Routes prüfen
echo "\n2. 🛣️ Routes prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Zeige alle Logout-bezogenen Zeilen
$lines = explode("\n", $content);
$logoutLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
$logoutLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
if (!empty($logoutLines)) {
echo " ✅ Logout-Routes gefunden:\n";
foreach ($logoutLines as $line) {
echo " 📋 $line\n";
}
} else {
echo " ❌ Keine Logout-Routes gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 3. LoginController prüfen
echo "\n3. 🔐 LoginController prüfen...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
if (strpos($content, 'logout') !== false) {
echo " ✅ Logout-Methode gefunden\n";
// Zeige Logout-Methode
$lines = explode("\n", $content);
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 Zeile " . ($lineNumber + 1) . ": " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Methode nicht gefunden\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 4. Laravel Route-Liste generieren
echo "\n4. 🛣️ Laravel Route-Liste generieren...\n";
try {
require_once 'vendor/autoload.php';
// Laravel Bootstrap
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Route-Liste abrufen
$routes = \Illuminate\Support\Facades\Route::getRoutes();
$logoutRoutes = [];
foreach ($routes as $route) {
$uri = $route->uri();
$methods = $route->methods();
$name = $route->getName();
if (strpos($uri, 'logout') !== false || strpos($name, 'logout') !== false) {
$logoutRoutes[] = [
'uri' => $uri,
'methods' => $methods,
'name' => $name
];
}
}
if (empty($logoutRoutes)) {
echo " ❌ Keine Logout-Routes in Laravel registriert\n";
} else {
echo " ✅ Logout-Routes in Laravel gefunden:\n";
foreach ($logoutRoutes as $route) {
$methods = implode('|', $route['methods']);
$name = $route['name'] ?: 'kein Name';
echo " 📋 $methods $uri ($name)\n";
}
}
} catch (Exception $e) {
echo " ❌ Fehler beim Abrufen der Routes: " . $e->getMessage() . "\n";
}
// 5. Cache-Status prüfen
echo "\n5. 🧹 Cache-Status prüfen...\n";
$cacheFiles = [
'bootstrap/cache/packages.php' => 'Packages Cache',
'bootstrap/cache/services.php' => 'Services Cache',
'bootstrap/cache/routes.php' => 'Routes Cache',
'bootstrap/cache/config.php' => 'Config Cache'
];
foreach ($cacheFiles as $cacheFile => $description) {
if (file_exists($cacheFile)) {
echo " ⚠️ Cache vorhanden: $description\n";
} else {
echo " ✅ Cache geleert: $description\n";
}
}
// 6. Test-Logout-URLs generieren
echo "\n6. 🔗 Test-Logout-URLs:\n";
$testUrls = [
'https://neonail.vogt.de.com/logout',
'https://neonail.vogt.de.com/logout (POST)',
'https://neonail.vogt.de.com/logout (GET)',
'https://neonail.vogt.de.com/',
'https://neonail.vogt.de.com/login'
];
foreach ($testUrls as $url) {
echo " 🔗 $url\n";
}
// 7. Layout korrigieren (falls nötig)
echo "\n7. 🔧 Layout korrigieren...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Ersetze alle hardcodierten Logout-URLs
$replacements = [
'action="https://neonail.vogt.de.com/logout"' => 'action="{{ route("logout") }}"',
'href="https://neonail.vogt.de.com/logout"' => 'href="{{ route("logout") }}"',
'action="http://neonail.vogt.de.com/logout"' => 'action="{{ route("logout") }}"',
'href="http://neonail.vogt.de.com/logout"' => 'href="{{ route("logout") }}"'
];
$modified = false;
foreach ($replacements as $old => $new) {
if (strpos($content, $old) !== false) {
$content = str_replace($old, $new, $content);
$modified = true;
echo " ✅ Ersetzt: $old$new\n";
}
}
if ($modified) {
file_put_contents($layoutPath, $content);
echo " ✅ Layout aktualisiert\n";
} else {
echo " Keine Änderungen nötig\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 8. Cache leeren
echo "\n8. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
echo "\n✅ Logout-Debug abgeschlossen!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Klicken Sie auf Ihren Benutzernamen (oben rechts)\n";
echo "2. Wählen Sie 'Abmelden' aus dem Dropdown\n";
echo "3. Falls das nicht funktioniert, versuchen Sie direkt:\n";
echo " - https://neonail.vogt.de.com/logout\n";
echo "\n📋 Falls Problem besteht:\n";
echo "- Prüfen Sie Browser-Entwicklertools (F12) für Fehler\n";
echo "- Schauen Sie in die Laravel-Logs: tail -f storage/logs/laravel.log\n";
echo "- Teilen Sie die Debug-Ausgabe mit\n";
?>

67
deploy-manufacturer-feature.sh Executable file
View File

@ -0,0 +1,67 @@
#!/bin/bash
# NeoNail DB - Hersteller-Feature Deployment Script
# Führt die neuen Migrationen aus und aktualisiert die Anwendung
echo "🎨 NeoNail DB - Hersteller-Feature Deployment"
echo "=============================================="
# Prüfe, ob wir im richtigen Verzeichnis sind
if [ ! -f "artisan" ]; then
echo "❌ Fehler: artisan Datei nicht gefunden. Bitte führen Sie das Script im Laravel-Root-Verzeichnis aus."
exit 1
fi
echo "📋 Prüfe Migration-Reihenfolge..."
# Stelle sicher, dass die manufacturer_id Migration nach der nail_polishes Migration kommt
if [ -f "database/migrations/2025_01_15_000001_add_manufacturer_id_to_nail_polishes_table.php" ]; then
echo "🔄 Korrigiere Migration-Reihenfolge..."
mv database/migrations/2025_01_15_000001_add_manufacturer_id_to_nail_polishes_table.php \
database/migrations/2025_08_10_020524_add_manufacturer_id_to_nail_polishes_table.php
echo "✅ Migration-Reihenfolge korrigiert"
fi
echo "📋 Führe Migrationen aus..."
php artisan migrate --force
if [ $? -eq 0 ]; then
echo "✅ Migrationen erfolgreich ausgeführt"
else
echo "❌ Fehler beim Ausführen der Migrationen"
exit 1
fi
echo "🔄 Cache leeren..."
php artisan config:clear
php artisan route:clear
php artisan view:clear
echo "📦 Composer Autoload aktualisieren..."
composer dump-autoload
echo "🔗 Storage-Link prüfen..."
if [ ! -L "public/storage" ]; then
echo "📎 Storage-Link erstellen..."
php artisan storage:link
else
echo "✅ Storage-Link bereits vorhanden"
fi
echo "🔒 Berechtigungen setzen..."
chmod -R 777 storage/
chmod -R 777 bootstrap/cache/
chmod 664 database.sqlite
echo "✅ Hersteller-Feature erfolgreich deployed!"
echo ""
echo "🎯 Neue Features:"
echo " - Hersteller-Verwaltung für alle User"
echo " - Hersteller-Auswahl beim Erstellen von Nagellacken"
echo " - Automatische Hersteller-Erstellung"
echo " - Hersteller-Statistiken im Admin-Bereich"
echo ""
echo "🌐 Zugriff:"
echo " - Hersteller-Übersicht: /manufacturers"
echo " - Neuen Hersteller erstellen: /manufacturers/create"
echo ""
echo "🚀 Anwendung ist bereit!"

64
deploy-sqlite.sh Executable file
View File

@ -0,0 +1,64 @@
#!/bin/bash
# NeoNail DB SQLite Deployment Script
echo "🚀 NeoNail DB SQLite Deployment gestartet..."
# 1. SQLite-Datenbank erstellen (falls nicht vorhanden)
echo "🗄️ SQLite-Datenbank erstellen..."
if [ ! -f database.sqlite ]; then
touch database.sqlite
echo "✅ SQLite-Datenbank erstellt"
else
echo "✅ SQLite-Datenbank bereits vorhanden"
fi
# 2. Berechtigungen für SQLite-Datenbank setzen
echo "🔐 SQLite-Berechtigungen setzen..."
chmod 664 database.sqlite
if command -v chown &> /dev/null; then
chown www-data:www-data database.sqlite 2>/dev/null || echo "⚠️ chown nicht verfügbar"
fi
# 3. Composer Dependencies optimieren
echo "📦 Composer Dependencies optimieren..."
composer install --optimize-autoloader --no-dev
# 4. Cache leeren
echo "🧹 Cache leeren..."
php artisan config:clear
php artisan cache:clear
php artisan view:clear
php artisan route:clear
# 5. Storage-Link erstellen
echo "🔗 Storage-Link erstellen..."
php artisan storage:link
# 6. Berechtigungen setzen
echo "🔐 Berechtigungen setzen..."
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 644 .env
# 7. Datenbank-Migrationen
echo "🗄️ Datenbank-Migrationen..."
php artisan migrate --force
# 8. Cache optimieren
echo "⚡ Cache optimieren..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
echo "✅ SQLite Deployment abgeschlossen!"
echo ""
echo "📋 Nächste Schritte:"
echo "1. Admin-User erstellen: php artisan tinker"
echo "2. Testen der Anwendung"
echo "3. HTTPS aktivieren"
echo "4. Backup-Strategie einrichten"
echo ""
echo "💡 SQLite Vorteile:"
echo "- Keine MySQL-Installation nötig"
echo "- Einfaches Backup (nur eine Datei)"
echo "- Minimaler Konfigurationsaufwand"

43
deploy.sh Executable file
View File

@ -0,0 +1,43 @@
#!/bin/bash
# NeoNail DB Deployment Script
echo "🚀 NeoNail DB Deployment gestartet..."
# 1. Composer Dependencies optimieren
echo "📦 Composer Dependencies optimieren..."
composer install --optimize-autoloader --no-dev
# 2. Cache leeren
echo "🧹 Cache leeren..."
php artisan config:clear
php artisan cache:clear
php artisan view:clear
php artisan route:clear
# 3. Storage-Link erstellen
echo "🔗 Storage-Link erstellen..."
php artisan storage:link
# 4. Berechtigungen setzen
echo "🔐 Berechtigungen setzen..."
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 644 .env
# 5. Datenbank-Migrationen
echo "🗄️ Datenbank-Migrationen..."
php artisan migrate --force
# 6. Cache optimieren
echo "⚡ Cache optimieren..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
echo "✅ Deployment abgeschlossen!"
echo ""
echo "📋 Nächste Schritte:"
echo "1. Admin-User erstellen: php artisan tinker"
echo "2. Testen der Anwendung"
echo "3. HTTPS aktivieren"
echo "4. Backup-Strategie einrichten"

111
deployment-checklist.md Executable file
View File

@ -0,0 +1,111 @@
# NeoNail DB - Deployment Checklist
## Vorbereitung (Lokal)
### 1. Produktions-Umgebung konfigurieren
```bash
# .env.production erstellen
cp .env .env.production
# Produktions-Einstellungen in .env.production:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://ihre-domain.de
# Datenbank-Einstellungen
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=ihre_datenbank
DB_USERNAME=ihr_username
DB_PASSWORD=ihr_passwort
```
### 2. Dependencies optimieren
```bash
composer install --optimize-autoloader --no-dev
npm run build # falls vorhanden
```
### 3. Cache leeren und optimieren
```bash
php artisan config:clear
php artisan cache:clear
php artisan view:clear
php artisan route:clear
```
### 4. Storage-Link erstellen
```bash
php artisan storage:link
```
## Upload zum Webspace
### 1. Dateien hochladen
- Alle Dateien außer `node_modules/`, `vendor/` (falls vorhanden)
- `.env.production` als `.env` hochladen
- `storage/` und `bootstrap/cache/` Ordner mit Schreibrechten
### 2. Composer installieren (falls verfügbar)
```bash
composer install --optimize-autoloader --no-dev
```
### 3. Datenbank-Migrationen
```bash
php artisan migrate --force
```
### 4. Berechtigungen setzen
```bash
chmod -R 755 storage/
chmod -R 755 bootstrap/cache/
chmod 644 .env
```
## Nach dem Upload
### 1. Cache optimieren
```bash
php artisan config:cache
php artisan route:cache
php artisan view:cache
```
### 2. Admin-User erstellen
```bash
php artisan tinker
```
```php
use App\Models\User;
User::create([
'name' => 'Admin',
'email' => 'admin@neonail.com',
'password' => bcrypt('ihr_admin_passwort')
]);
```
### 3. Testen
- Login mit admin@neonail.com
- Neuen Lack erstellen
- Bild-Upload testen
- Mobile-Ansicht prüfen
## Wichtige Hinweise
### Sicherheit
- APP_KEY muss gesetzt sein
- Starke Passwörter verwenden
- HTTPS verwenden
- .env nicht öffentlich zugänglich
### Performance
- OPcache aktivieren (falls verfügbar)
- Redis für Cache (optional)
- CDN für Bilder (optional)
### Backup
- Regelmäßige Datenbank-Backups
- Storage-Ordner sichern
- Code-Backup

66
emergency-apache-fix.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/bash
echo "🚨 EMERGENCY: Apache komplett reparieren"
echo "======================================="
# 1. Apache-Status prüfen
echo "1. 🔍 Apache-Status prüfen..."
systemctl status apache2 2>/dev/null || service apache2 status 2>/dev/null || echo " ⚠️ Apache-Status nicht verfügbar"
# 2. Apache stoppen
echo "2. 🛑 Apache stoppen..."
systemctl stop apache2 2>/dev/null || service apache2 stop 2>/dev/null || echo " ⚠️ Apache stop fehlgeschlagen"
# 3. .htaccess zurücksetzen
echo "3. 🔄 .htaccess zurücksetzen..."
if [ -f public/.htaccess.backup ]; then
cp public/.htaccess.backup public/.htaccess
echo " ✅ .htaccess aus Backup wiederhergestellt"
elif [ -f public/.htaccess.simple ]; then
cp public/.htaccess.simple public/.htaccess
echo " ✅ .htaccess aus simple wiederhergestellt"
else
# Erstelle minimale .htaccess
cat > public/.htaccess << 'EOF'
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
EOF
echo " ✅ Minimale .htaccess erstellt"
fi
# 4. Apache-Module zurücksetzen
echo "4. 🔧 Apache-Module zurücksetzen..."
a2dismod headers 2>/dev/null || echo " ⚠️ mod_headers deaktivieren fehlgeschlagen"
a2enmod rewrite 2>/dev/null || echo " ⚠️ mod_rewrite aktivieren fehlgeschlagen"
# 5. Apache-Konfiguration testen
echo "5. 🧪 Apache-Konfiguration testen..."
apache2ctl -t 2>/dev/null && echo " ✅ Apache-Konfiguration OK" || echo " ❌ Apache-Konfiguration fehlerhaft"
# 6. Apache starten
echo "6. 🚀 Apache starten..."
systemctl start apache2 2>/dev/null || service apache2 start 2>/dev/null || echo " ⚠️ Apache start fehlgeschlagen"
# 7. Apache-Status prüfen
echo "7. 🔍 Apache-Status nach Start..."
systemctl status apache2 2>/dev/null || service apache2 status 2>/dev/null || echo " ⚠️ Apache-Status nicht verfügbar"
# 8. Test-Request
echo "8. 🧪 Test-Request..."
curl -I http://localhost/ 2>/dev/null && echo " ✅ Apache antwortet" || echo " ❌ Apache antwortet nicht"
echo ""
echo "✅ Emergency Apache Fix abgeschlossen!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. http://neonail.vogt.de.com"
echo "2. https://neonail.vogt.de.com"
echo ""
echo "📝 Falls Problem besteht:"
echo "- Prüfen Sie: systemctl status apache2"
echo "- Schauen Sie in: /var/log/apache2/error.log"
echo "- Führen Sie: apache2ctl -t"

55
env-production-example.txt Executable file
View File

@ -0,0 +1,55 @@
APP_NAME="NeoNail DB"
APP_ENV=production
APP_KEY=base64:+LTZYPKjkZ+O3iFTgU2sS+9bNvxxvG8Kw8JSEPiG7Rs=
APP_DEBUG=false
APP_URL=http://192.168.30.81
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
DB_DATABASE=database.sqlite
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

64
env-sqlite-example.txt Executable file
View File

@ -0,0 +1,64 @@
APP_NAME="NeoNail DB"
APP_ENV=production
APP_KEY=base64:YOUR_APP_KEY_HERE
APP_DEBUG=false
APP_URL=https://ihre-domain.de
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=error
# SQLite Konfiguration (Einfachste Option)
DB_CONNECTION=sqlite
DB_DATABASE=/path/to/database.sqlite
# MySQL Konfiguration (Alternative)
# DB_CONNECTION=mysql
# DB_HOST=localhost
# DB_PORT=3306
# DB_DATABASE=ihre_datenbank
# DB_USERNAME=ihr_username
# DB_PASSWORD=ihr_passwort
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

55
fix-405-error.sh Executable file
View File

@ -0,0 +1,55 @@
#!/bin/bash
echo "🔧 Fix: HTTP 405 Method Not Allowed"
echo "==================================="
# 1. Debug-Script ausführen
echo "1. 🔍 Diagnose ausführen..."
php debug-405-error.php
echo ""
echo "2. 🧹 Laravel Cache leeren..."
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan route:clear 2>/dev/null || echo "⚠️ route:clear übersprungen"
echo ""
echo "3. 🔄 Route-Cache neu generieren..."
php artisan route:cache 2>/dev/null || echo "⚠️ route:cache übersprungen"
echo ""
echo "4. 📝 .env Debug aktivieren..."
if [ -f .env ]; then
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
sed -i 's/APP_ENV=production/APP_ENV=local/' .env
echo "✅ Debug-Modus aktiviert"
else
echo "❌ .env Datei nicht gefunden"
fi
echo ""
echo "5. 🔍 Apache-Logs prüfen..."
if [ -f /var/log/apache2/error.log ]; then
echo "📋 Letzte Apache-Fehler:"
tail -10 /var/log/apache2/error.log | grep -E "(405|Method|Not Allowed)" || echo "Keine 405-Fehler gefunden"
else
echo "⚠️ Apache-Logs nicht verfügbar"
fi
echo ""
echo "6. 🧪 Route-Test..."
echo "📋 Teste POST-Route direkt:"
curl -X POST https://neonail.vogt.de.com/create-nail-polish \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "name=Test&number=123&_token=test" \
-w "\nHTTP-Status: %{http_code}\n" \
2>/dev/null || echo "❌ curl nicht verfügbar"
echo ""
echo "✅ Fix abgeschlossen!"
echo ""
echo "🔧 Nächste Schritte:"
echo "1. Testen Sie das Formular erneut"
echo "2. Prüfen Sie die Browser-Entwicklertools (F12) für Details"
echo "3. Schauen Sie in storage/logs/laravel.log für Laravel-Fehler"
echo "4. Falls Problem besteht: php artisan route:list | grep store"

View File

@ -0,0 +1,284 @@
<?php
// Fix: AdminController mit automatischer E-Mail-Versendung erweitern
echo "📧 Fix: AdminController mit E-Mail-Versendung erweitern\n";
echo "=====================================================\n\n";
// 1. AdminController erweitern
echo "1. 🔧 AdminController erweitern...\n";
$controllerContent = '<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\NailPolish;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
class AdminController extends Controller
{
/**
* Dashboard für Administratoren
*/
public function dashboard()
{
$totalUsers = User::count();
$totalNailPolishes = NailPolish::count();
$recentUsers = User::latest()->take(5)->get();
$recentNailPolishes = NailPolish::latest()->take(5)->get();
return view("admin.dashboard", compact("totalUsers", "totalNailPolishes", "recentUsers", "recentNailPolishes"));
}
/**
* Liste aller Benutzer
*/
public function users(Request $request)
{
$search = $request->get("search");
$users = User::when($search, function($query) use ($search) {
return $query->where("name", "like", "%{$search}%")
->orWhere("email", "like", "%{$search}%");
})->orderBy("name")->paginate(20);
return view("admin.users.index", compact("users", "search"));
}
/**
* Formular zum Erstellen eines neuen Benutzers
*/
public function createUser()
{
return view("admin.users.create");
}
/**
* Neuen Benutzer speichern
*/
public function storeUser(Request $request)
{
$request->validate([
"name" => "required|string|max:255",
"email" => "required|string|email|max:255|unique:users",
"password" => "required|string|min:8|confirmed",
]);
// Passwort für E-Mail speichern (wird nach dem Speichern gelöscht)
$plainPassword = $request->password;
// User erstellen
$user = User::create([
"name" => $request->name,
"email" => $request->email,
"password" => Hash::make($request->password),
"is_admin" => $request->has("is_admin"),
]);
// Willkommens-E-Mail senden
try {
Mail::send("emails.welcome-user", [
"user" => $user,
"password" => $plainPassword
], function($message) use ($user) {
$message->to($user->email, $user->name)
->subject("🎨 Willkommen bei der NeoNail DB - Ihre Login-Daten")
->from(config("mail.from.address"), config("mail.from.name"));
});
// Admin-Bestätigung senden
Mail::raw("Hallo Admin!
Ein neuer User wurde erfolgreich erstellt und eine Willkommens-E-Mail gesendet.
📋 User-Details:
- Name: {$user->name}
- E-Mail: {$user->email}
- Admin-Status: " . ($user->isAdmin() ? "Ja" : "Nein") . "
- Erstellt: " . now() . "
Die Willkommens-E-Mail enthält:
- Login-Daten (Website, E-Mail, Passwort)
- Aufforderung zum Passwort-Ändern
- Feature-Übersicht
- Direkte Links zur Anwendung
Viele Grüße,
NeoNail DB System", function($message) {
$message->to("oliver@vogt.de.com", "Admin")
->subject("✅ NeoNail DB - Neuer User erstellt")
->from(config("mail.from.address"), config("mail.from.name"));
});
$successMessage = "Benutzer erfolgreich erstellt! Willkommens-E-Mail wurde gesendet.";
} catch (\Exception $e) {
// User wurde erstellt, aber E-Mail fehlgeschlagen
\Log::error("Fehler beim Senden der Willkommens-E-Mail: " . $e->getMessage());
$successMessage = "Benutzer erfolgreich erstellt! E-Mail konnte nicht gesendet werden.";
}
return redirect()->route("admin.users.index")
->with("success", $successMessage);
}
/**
* Formular zum Bearbeiten eines Benutzers
*/
public function editUser(User $user)
{
return view("admin.users.edit", compact("user"));
}
/**
* Benutzer aktualisieren
*/
public function updateUser(Request $request, User $user)
{
$request->validate([
"name" => "required|string|max:255",
"email" => "required|string|email|max:255|unique:users,email," . $user->id,
"password" => "nullable|string|min:8|confirmed",
]);
$user->name = $request->name;
$user->email = $request->email;
$user->is_admin = $request->has("is_admin");
if ($request->filled("password")) {
$user->password = Hash::make($request->password);
}
$user->save();
return redirect()->route("admin.users.index")
->with("success", "Benutzer erfolgreich aktualisiert!");
}
/**
* Benutzer löschen
*/
public function destroyUser(User $user)
{
$userName = $user->name;
$userEmail = $user->email;
$user->delete();
// Admin-Benachrichtigung über gelöschten User
try {
Mail::raw("Hallo Admin!
Ein User wurde erfolgreich gelöscht.
📋 Gelöschter User:
- Name: {$userName}
- E-Mail: {$userEmail}
- Gelöscht: " . now() . "
Viele Grüße,
NeoNail DB System", function($message) {
$message->to("oliver@vogt.de.com", "Admin")
->subject("🗑️ NeoNail DB - User gelöscht")
->from(config("mail.from.address"), config("mail.from.name"));
});
} catch (\Exception $e) {
\Log::error("Fehler beim Senden der Lösch-Benachrichtigung: " . $e->getMessage());
}
return redirect()->route("admin.users.index")
->with("success", "Benutzer erfolgreich gelöscht!");
}
/**
* Statistiken anzeigen
*/
public function statistics()
{
$totalUsers = User::count();
$totalNailPolishes = NailPolish::count();
$usersWithCollections = User::has("nailPolishes")->count();
$averageCollectionSize = User::withCount("nailPolishes")->avg("nail_polishes_count");
$topUsers = User::withCount("nailPolishes")
->orderBy("nail_polishes_count", "desc")
->take(10)
->get();
return view("admin.statistics", compact(
"totalUsers",
"totalNailPolishes",
"usersWithCollections",
"averageCollectionSize",
"topUsers"
));
}
}';
file_put_contents('app/Http/Controllers/AdminController.php', $controllerContent);
echo " ✅ AdminController erweitert\n";
// 2. E-Mail-Verzeichnis erstellen
echo "2. 📁 E-Mail-Verzeichnis erstellen...\n";
$emailDir = 'resources/views/emails';
if (!is_dir($emailDir)) {
mkdir($emailDir, 0755, true);
echo " ✅ E-Mail-Verzeichnis erstellt: $emailDir\n";
} else {
echo " E-Mail-Verzeichnis existiert bereits: $emailDir\n";
}
// 3. Cache leeren
echo "3. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 4. Test-E-Mail senden
echo "4. 📧 Test-E-Mail senden...\n";
try {
require_once 'vendor/autoload.php';
// Laravel Bootstrap
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Test-User erstellen
$testUser = new \App\Models\User();
$testUser->name = 'Test User';
$testUser->email = 'test@example.com';
$testUser->password = 'testpassword123';
$testUser->is_admin = false;
// Test-E-Mail senden
$result = \Illuminate\Support\Facades\Mail::send('emails.welcome-user', [
'user' => $testUser,
'password' => 'testpassword123'
], function($message) use ($testUser) {
$message->to('oliver@vogt.de.com', 'Admin')
->subject('🧪 Test: NeoNail DB Willkommens-E-Mail Template')
->from(config('mail.from.address'), config('mail.from.name'));
});
echo " ✅ Test-E-Mail erfolgreich gesendet!\n";
} catch (Exception $e) {
echo " ❌ Test-E-Mail Fehler: " . $e->getMessage() . "\n";
}
echo "\n✅ AdminController mit E-Mail-Versendung erweitert!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Gehen Sie zu: https://neonail.vogt.de.com/admin/users/create\n";
echo "2. Erstellen Sie einen neuen User\n";
echo "3. Der User erhält automatisch eine Willkommens-E-Mail\n";
echo "4. Sie erhalten eine Admin-Bestätigung\n";
echo "\n📧 Die Willkommens-E-Mail enthält:\n";
echo "- Login-Daten (Website, E-Mail, Passwort)\n";
echo "- Aufforderung zum Passwort-Ändern\n";
echo "- Feature-Übersicht\n";
echo "- Direkte Links zur Anwendung\n";
echo "- Admin-spezifische Informationen (falls Admin)\n";
?>

291
fix-admin-layout.php Normal file
View File

@ -0,0 +1,291 @@
<?php
// Fix: Admin-Layout korrigieren
echo "👑 Fix: Admin-Layout korrigieren\n";
echo "==============================\n\n";
// 1. Layout-Datei korrigieren
echo "1. 🎨 Layout-Datei korrigieren...\n";
$layoutContent = '<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield("title", "NeoNail Datenbank")</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.navbar {
background: rgba(255, 255, 255, 0.95) !important;
backdrop-filter: blur(10px);
}
.card {
border: none;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.9);
}
.btn-primary {
background: linear-gradient(45deg, #667eea, #764ba2);
border: none;
border-radius: 25px;
padding: 10px 25px;
}
.btn-primary:hover {
background: linear-gradient(45deg, #5a6fd8, #6a4190);
transform: translateY(-2px);
}
.nail-polish-card {
transition: transform 0.3s ease;
}
.nail-polish-card:hover {
transform: translateY(-5px);
}
.nail-polish-image {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 10px;
}
.search-box {
border-radius: 25px;
border: 2px solid #e9ecef;
padding: 10px 20px;
}
.search-box:focus {
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.card {
margin-bottom: 15px;
}
}
/* Dropdown-Menüs über alle anderen Elemente legen */
.dropdown-menu {
z-index: 9999 !important;
position: absolute !important;
}
/* Navbar hat höheren z-index */
.navbar {
z-index: 1000 !important;
position: relative;
}
/* Dropdown-Container */
.dropdown {
position: relative;
}
/* Sicherstellen, dass Dropdowns über Cards angezeigt werden */
.navbar-nav .dropdown-menu {
z-index: 9999 !important;
position: absolute !important;
top: 100% !important;
left: 0 !important;
float: none !important;
}
</style>
@yield("styles")
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container">
<a class="navbar-brand fw-bold" href="{{ route("user-nail-polishes.index") }}">
<i class="fas fa-palette me-2"></i>NeoNail DB
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
@auth
<li class="nav-item">
<a class="nav-link" href="{{ route("user-nail-polishes.index") }}">
<i class="fas fa-home me-1"></i>Meine Sammlung
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route("user-nail-polishes.available") }}">
<i class="fas fa-plus me-1"></i>Verfügbare Lacke
</a>
</li>
@if(auth()->user()->isAdmin())
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="fas fa-cog me-1"></i>Admin
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ route("admin.dashboard") }}">Dashboard</a></li>
<li><a class="dropdown-item" href="{{ route("admin.users.index") }}">Benutzer</a></li>
<li><a class="dropdown-item" href="{{ route("nail-polishes.index") }}">Nagellacke</a></li>
<li><a class="dropdown-item" href="{{ route("admin.statistics") }}">Statistiken</a></li>
</ul>
</li>
@endif
@endauth
</ul>
<ul class="navbar-nav">
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route("login") }}">Anmelden</a>
</li>
@else
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="fas fa-user me-1"></i>{{ Auth::user()->name }}
@if(auth()->user()->isAdmin())
<span class="badge bg-primary ms-1">Admin</span>
@endif
</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="{{ route("logout") }}"
onclick="event.preventDefault(); document.getElementById("logout-form").submit();">
<i class="fas fa-sign-out-alt me-1"></i>Abmelden
</a>
<form id="logout-form" action="https://neonail.vogt.de.com/logout" method="POST" class="d-none">
@csrf
</form>
</li>
</ul>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
<div class="container">
@if(session("success"))
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle me-2"></i>{{ session("success") }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
@if(session("error"))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle me-2"></i>{{ session("error") }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
@yield("content")
</div>
</main>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
@yield("scripts")
</body>
</html>';
file_put_contents('resources/views/layouts/app.blade.php', $layoutContent);
echo " ✅ Layout-Datei korrigiert\n";
// 2. User Model prüfen und korrigieren
echo "2. 📋 User Model prüfen...\n";
$userModelPath = 'app/Models/User.php';
if (file_exists($userModelPath)) {
$content = file_get_contents($userModelPath);
// Prüfe ob isAdmin Methode korrekt ist
if (strpos($content, 'public function isAdmin()') !== false) {
echo " ✅ isAdmin() Methode vorhanden\n";
// Prüfe ob die Methode korrekt implementiert ist
if (strpos($content, '$this->is_admin || in_array($this->email') !== false) {
echo " ✅ isAdmin() Methode korrekt implementiert\n";
} else {
echo " ⚠️ isAdmin() Methode könnte inkorrekt sein\n";
}
} else {
echo " ❌ isAdmin() Methode fehlt\n";
}
} else {
echo " ❌ User Model nicht gefunden\n";
}
// 3. Cache leeren
echo "3. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 4. Admin-User Status prüfen
echo "4. 👑 Admin-User Status prüfen...\n";
try {
require_once 'vendor/autoload.php';
// Laravel Bootstrap
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Alle User prüfen
$users = \App\Models\User::all();
foreach ($users as $user) {
$isAdmin = $user->isAdmin();
$isAdminColumn = $user->is_admin;
$email = $user->email;
echo " 📧 $email:\n";
echo " - is_admin Spalte: " . ($isAdminColumn ? 'Ja' : 'Nein') . "\n";
echo " - isAdmin() Methode: " . ($isAdmin ? 'Ja' : 'Nein') . "\n";
if ($isAdminColumn && !$isAdmin) {
echo " ⚠️ WARNUNG: Spalte ist true, aber Methode gibt false zurück!\n";
} elseif (!$isAdminColumn && $isAdmin) {
echo " INFO: Spalte ist false, aber Methode gibt true zurück (Email-Check)\n";
}
echo "\n";
}
} catch (Exception $e) {
echo " ❌ Fehler beim Prüfen der User: " . $e->getMessage() . "\n";
}
echo "\n✅ Admin-Layout korrigiert!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Melden Sie sich als neuer Admin an\n";
echo "2. Prüfen Sie ob Admin-Menü sichtbar ist\n";
echo "3. Prüfen Sie ob Admin-Badge neben dem Namen steht\n";
echo "4. Versuchen Sie auf /admin/users zuzugreifen\n";
echo "5. Falls Problem besteht, führen Sie php fix-admin-view.php aus\n";
?>

120
fix-admin-role-database.php Normal file
View File

@ -0,0 +1,120 @@
<?php
// Fix: Admin-Rolle zur Datenbank hinzufügen
// Führen Sie dies aus, um die is_admin Spalte zu erstellen
echo "🔧 Fix: Admin-Rolle zur Datenbank hinzufügen\n";
echo "==========================================\n\n";
try {
// Datenbankverbindung
$pdo = new PDO('sqlite:database.sqlite');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "1. 🔍 Prüfe users-Tabelle...\n";
// Prüfe ob is_admin Spalte existiert
$stmt = $pdo->query("PRAGMA table_info(users)");
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
$hasAdminColumn = false;
echo " 📋 Aktuelle Spalten in users-Tabelle:\n";
foreach ($columns as $column) {
echo " - {$column['name']} ({$column['type']})\n";
if ($column['name'] === 'is_admin') {
$hasAdminColumn = true;
}
}
if (!$hasAdminColumn) {
echo "\n2. Füge is_admin Spalte hinzu...\n";
// Füge is_admin Spalte hinzu
$pdo->exec("ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT 0");
echo " ✅ is_admin Spalte hinzugefügt\n";
// Prüfe nochmal
$stmt = $pdo->query("PRAGMA table_info(users)");
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
$hasAdminColumn = false;
foreach ($columns as $column) {
if ($column['name'] === 'is_admin') {
$hasAdminColumn = true;
break;
}
}
if ($hasAdminColumn) {
echo " ✅ is_admin Spalte erfolgreich erstellt\n";
} else {
echo " ❌ is_admin Spalte konnte nicht erstellt werden\n";
exit;
}
} else {
echo "\n2. is_admin Spalte existiert bereits\n";
}
echo "\n3. 👑 Markiere bestehende Admin-User...\n";
// Markiere bestehende Admin-User
$stmt = $pdo->prepare("UPDATE users SET is_admin = 1 WHERE email IN (?, ?)");
$stmt->execute(['admin@neonail.com', 'neueradmin@neonail.com']);
$affectedRows = $stmt->rowCount();
echo "$affectedRows Admin-User aktualisiert\n";
echo "\n4. 📋 Zeige alle User mit Admin-Status...\n";
// Zeige alle User
$stmt = $pdo->query("SELECT id, name, email, is_admin FROM users ORDER BY is_admin DESC, name");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $user) {
$adminStatus = $user['is_admin'] ? '👑 Admin' : '👤 User';
echo " - {$user['name']} ({$user['email']}) - {$adminStatus}\n";
}
echo "\n5. 🧪 Test: Mache einen User zum Admin...\n";
// Finde einen User, der noch kein Admin ist
$stmt = $pdo->prepare("SELECT id, name, email FROM users WHERE is_admin = 0 LIMIT 1");
$stmt->execute();
$testUser = $stmt->fetch(PDO::FETCH_ASSOC);
if ($testUser) {
echo " 📝 Teste mit User: {$testUser['name']} ({$testUser['email']})\n";
// Mache User zum Admin
$stmt = $pdo->prepare("UPDATE users SET is_admin = 1 WHERE id = ?");
$stmt->execute([$testUser['id']]);
echo " ✅ User zum Admin gemacht\n";
// Prüfe Änderung
$stmt = $pdo->prepare("SELECT is_admin FROM users WHERE id = ?");
$stmt->execute([$testUser['id']]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result['is_admin']) {
echo " ✅ Admin-Status korrekt gesetzt\n";
} else {
echo " ❌ Admin-Status nicht korrekt gesetzt\n";
}
// Mache User wieder zurück
$stmt = $pdo->prepare("UPDATE users SET is_admin = 0 WHERE id = ?");
$stmt->execute([$testUser['id']]);
echo " 🔄 User-Status zurückgesetzt\n";
} else {
echo " Alle User sind bereits Admins\n";
}
echo "\n✅ Admin-Rolle erfolgreich zur Datenbank hinzugefügt!\n";
echo "🔗 Testen Sie jetzt: https://neonail.vogt.de.com/admin/users\n";
echo "📝 Sie können jetzt User zum Admin machen!\n";
} catch (Exception $e) {
echo "❌ Fehler: " . $e->getMessage() . "\n";
echo "📍 Datei: " . $e->getFile() . ":" . $e->getLine() . "\n";
}
?>

54
fix-admin-role.php Executable file
View File

@ -0,0 +1,54 @@
<?php
// Admin-Rolle zur Datenbank hinzufügen
// Führen Sie dies direkt auf dem Webspace aus
try {
// Datenbankverbindung
$pdo = new PDO('sqlite:database.sqlite');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "🔧 Admin-Rolle hinzufügen...\n";
// 1. Prüfe ob is_admin Spalte existiert
$stmt = $pdo->query("PRAGMA table_info(users)");
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
$hasAdminColumn = false;
foreach ($columns as $column) {
if ($column['name'] === 'is_admin') {
$hasAdminColumn = true;
break;
}
}
if (!$hasAdminColumn) {
// 2. Füge is_admin Spalte hinzu
$pdo->exec("ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT 0");
echo "✅ is_admin Spalte hinzugefügt\n";
} else {
echo " is_admin Spalte existiert bereits\n";
}
// 3. Markiere bestehende Admin-User
$stmt = $pdo->prepare("UPDATE users SET is_admin = 1 WHERE email IN (?, ?)");
$stmt->execute(['admin@neonail.com', 'neueradmin@neonail.com']);
echo "✅ Admin-User aktualisiert\n";
// 4. Zeige alle User
echo "\n📋 Alle User:\n";
$stmt = $pdo->query("SELECT id, name, email, is_admin FROM users");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $user) {
$adminStatus = $user['is_admin'] ? '👑 Admin' : '👤 User';
echo "- {$user['name']} ({$user['email']}) - {$adminStatus}\n";
}
echo "\n✅ Admin-Rolle erfolgreich aktiviert!\n";
echo "🔗 Gehen Sie zu: https://neonail.vogt.de.com/admin/users\n";
echo "📝 Bearbeiten Sie einen User und aktivieren Sie die 'Admin-Rechte gewähren' Checkbox\n";
} catch (Exception $e) {
echo "❌ Fehler: " . $e->getMessage() . "\n";
}
?>

165
fix-admin-routes.php Normal file
View File

@ -0,0 +1,165 @@
<?php
// Fix: Admin-Routes korrigieren
echo "👑 Fix: Admin-Routes korrigieren\n";
echo "==============================\n\n";
// 1. Routes-Datei analysieren
echo "1. 📋 Routes-Datei analysieren:\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Zeige alle Admin-bezogenen Zeilen
$lines = explode("\n", $content);
$adminLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'admin') !== false || strpos($line, 'Admin') !== false) {
$adminLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
echo " 📄 Admin-bezogene Zeilen in routes/web.php:\n";
foreach ($adminLines as $line) {
echo " $line\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 2. Route-Liste generieren
echo "\n2. 🛣️ Route-Liste generieren:\n";
try {
// Laravel Bootstrap
require_once 'vendor/autoload.php';
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Route-Liste abrufen
$routes = \Illuminate\Support\Facades\Route::getRoutes();
$adminRoutes = [];
foreach ($routes as $route) {
$uri = $route->uri();
$methods = $route->methods();
$name = $route->getName();
if (strpos($uri, 'admin') !== false || strpos($name, 'admin') !== false) {
$adminRoutes[] = [
'uri' => $uri,
'methods' => $methods,
'name' => $name
];
}
}
if (empty($adminRoutes)) {
echo " ⚠️ Keine Admin-Routes gefunden\n";
} else {
echo " ✅ Admin-Routes gefunden:\n";
foreach ($adminRoutes as $route) {
$methods = implode('|', $route['methods']);
$name = $route['name'] ?: 'kein Name';
echo " $methods $uri ($name)\n";
}
}
} catch (Exception $e) {
echo " ❌ Fehler beim Abrufen der Routes: " . $e->getMessage() . "\n";
}
// 3. Admin-Routes manuell prüfen
echo "\n3. 🔍 Admin-Routes manuell prüfen:\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Suche nach spezifischen Admin-Route-Patterns
$adminPatterns = [
'admin/dashboard' => 'Dashboard Route',
'admin/users' => 'Users Index Route',
'admin/users/create' => 'Users Create Route',
'admin/users/{user}/edit' => 'Users Edit Route',
'admin/statistics' => 'Statistics Route',
'admin/users/{user}' => 'Users Show/Edit Route',
'nail-polishes' => 'Nail Polishes Route'
];
foreach ($adminPatterns as $pattern => $description) {
if (strpos($content, $pattern) !== false) {
echo " ✅ Pattern gefunden: $pattern ($description)\n";
} else {
echo " ❌ Pattern fehlt: $pattern ($description)\n";
}
}
// Prüfe Route-Gruppen
if (strpos($content, "Route::middleware(['admin'])->prefix('admin')") !== false) {
echo " ✅ Admin Route-Gruppe gefunden\n";
} else {
echo " ❌ Admin Route-Gruppe nicht gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 4. Cache leeren und Routes neu laden
echo "\n4. 🧹 Cache leeren und Routes neu laden...\n";
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 5. Admin-User Status prüfen
echo "\n5. 👑 Admin-User Status prüfen:\n";
try {
// Alle User mit Admin-Rechten auflisten
$users = \App\Models\User::all();
foreach ($users as $user) {
$isAdmin = $user->isAdmin();
$isAdminColumn = $user->is_admin;
$email = $user->email;
if ($isAdmin || $isAdminColumn) {
echo " 📧 $email:\n";
echo " - is_admin Spalte: " . ($isAdminColumn ? 'Ja' : 'Nein') . "\n";
echo " - isAdmin() Methode: " . ($isAdmin ? 'Ja' : 'Nein') . "\n";
echo " - Admin-Status: " . ($isAdmin ? '✅ Admin' : '❌ Kein Admin') . "\n";
echo "\n";
}
}
} catch (Exception $e) {
echo " ❌ Fehler beim Prüfen der User: " . $e->getMessage() . "\n";
}
// 6. Test-URLs generieren
echo "\n6. 🔗 Test-URLs für Admin-Zugriffe:\n";
$baseUrl = 'https://neonail.vogt.de.com';
$adminUrls = [
'/admin/dashboard' => 'Admin Dashboard',
'/admin/users' => 'Admin Users',
'/admin/users/create' => 'Admin Create User',
'/admin/statistics' => 'Admin Statistics',
'/nail-polishes' => 'Nail Polishes Management'
];
foreach ($adminUrls as $url => $description) {
echo " 🔗 $baseUrl$url ($description)\n";
}
echo "\n✅ Admin-Routes Analyse abgeschlossen!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Melden Sie sich als Admin an (oliver@vogt.de.com)\n";
echo "2. Prüfen Sie ob Admin-Menü sichtbar ist\n";
echo "3. Klicken Sie auf 'Admin' → 'Benutzer'\n";
echo "4. Oder versuchen Sie direkt: $baseUrl/admin/users\n";
echo "5. Falls 403 Fehler: Prüfen Sie ob User wirklich Admin ist\n";
echo "\n📋 Falls Probleme bestehen:\n";
echo "- Prüfen Sie Browser-Entwicklertools (F12) für Fehler\n";
echo "- Schauen Sie in die Laravel-Logs: tail -f storage/logs/laravel.log\n";
echo "- Teilen Sie eventuelle Fehlermeldungen mit\n";
?>

158
fix-admin-view.php Normal file
View File

@ -0,0 +1,158 @@
<?php
// Fix: Admin-Ansicht Problem
echo "👑 Fix: Admin-Ansicht Problem\n";
echo "============================\n\n";
// 1. Aktuelle User mit Admin-Rechten prüfen
echo "1. 🔍 Aktuelle Admin-User prüfen:\n";
try {
require_once 'vendor/autoload.php';
// Laravel Bootstrap
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Datenbankverbindung herstellen
$users = \App\Models\User::all();
foreach ($users as $user) {
$isAdmin = $user->isAdmin();
$isAdminColumn = $user->is_admin;
$email = $user->email;
echo " 📧 $email:\n";
echo " - is_admin Spalte: " . ($isAdminColumn ? 'Ja' : 'Nein') . "\n";
echo " - isAdmin() Methode: " . ($isAdmin ? 'Ja' : 'Nein') . "\n";
echo " - Admin-Email Check: " . (in_array($email, ['admin@neonail.com', 'neueradmin@neonail.com']) ? 'Ja' : 'Nein') . "\n";
echo "\n";
}
} catch (Exception $e) {
echo " ❌ Fehler beim Prüfen der User: " . $e->getMessage() . "\n";
}
// 2. User Model prüfen
echo "2. 📋 User Model prüfen:\n";
$userModelPath = 'app/Models/User.php';
if (file_exists($userModelPath)) {
$content = file_get_contents($userModelPath);
// Prüfe isAdmin Methode
if (strpos($content, 'public function isAdmin()') !== false) {
echo " ✅ isAdmin() Methode vorhanden\n";
} else {
echo " ❌ isAdmin() Methode fehlt\n";
}
// Prüfe is_admin in fillable
if (strpos($content, "'is_admin'") !== false) {
echo " ✅ is_admin in \$fillable vorhanden\n";
} else {
echo " ❌ is_admin nicht in \$fillable\n";
}
// Prüfe makeAdmin Methode
if (strpos($content, 'public function makeAdmin()') !== false) {
echo " ✅ makeAdmin() Methode vorhanden\n";
} else {
echo " ❌ makeAdmin() Methode fehlt\n";
}
} else {
echo " ❌ User Model nicht gefunden\n";
}
// 3. AdminMiddleware prüfen
echo "3. 🛡️ AdminMiddleware prüfen:\n";
$middlewarePath = 'app/Http/Middleware/AdminMiddleware.php';
if (file_exists($middlewarePath)) {
$content = file_get_contents($middlewarePath);
if (strpos($content, 'auth()->user()->isAdmin()') !== false) {
echo " ✅ AdminMiddleware verwendet isAdmin() Methode\n";
} else {
echo " ❌ AdminMiddleware verwendet nicht isAdmin() Methode\n";
}
} else {
echo " ❌ AdminMiddleware nicht gefunden\n";
}
// 4. Routes prüfen
echo "4. 🛣️ Admin-Routes prüfen:\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
$adminRoutes = [
'admin/users',
'admin/dashboard',
'nail-polishes'
];
foreach ($adminRoutes as $route) {
if (strpos($content, $route) !== false) {
echo " ✅ Route gefunden: $route\n";
} else {
echo " ❌ Route fehlt: $route\n";
}
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 5. Layout prüfen
echo "5. 🎨 Layout prüfen:\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
if (strpos($content, 'auth()->user()->isAdmin()') !== false) {
echo " ✅ Layout verwendet isAdmin() für Admin-Menü\n";
} else {
echo " ❌ Layout verwendet nicht isAdmin() für Admin-Menü\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 6. Cache leeren
echo "6. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 7. Test-Admin erstellen
echo "7. 👑 Test-Admin erstellen...\n";
try {
$testUser = \App\Models\User::where('email', 'testadmin@neonail.com')->first();
if (!$testUser) {
$testUser = new \App\Models\User();
$testUser->name = 'Test Admin';
$testUser->email = 'testadmin@neonail.com';
$testUser->password = bcrypt('password123');
$testUser->is_admin = true;
$testUser->save();
echo " ✅ Test-Admin erstellt: testadmin@neonail.com\n";
} else {
$testUser->is_admin = true;
$testUser->save();
echo " ✅ Test-Admin aktualisiert: testadmin@neonail.com\n";
}
} catch (Exception $e) {
echo " ❌ Fehler beim Erstellen des Test-Admins: " . $e->getMessage() . "\n";
}
echo "\n✅ Admin-Ansicht Problem Analyse abgeschlossen!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Melden Sie sich als neuer Admin an\n";
echo "2. Prüfen Sie ob Admin-Menü sichtbar ist\n";
echo "3. Versuchen Sie auf /admin/users zuzugreifen\n";
echo "4. Falls Problem besteht, teilen Sie die Ausgabe mit\n";
?>

50
fix-all-405-errors.sh Normal file
View File

@ -0,0 +1,50 @@
#!/bin/bash
echo "🔧 Fix: Alle HTTP 405 Method Not Allowed Fehler"
echo "=============================================="
# 1. Laravel Cache leeren
echo "1. 🧹 Laravel Cache leeren..."
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan route:clear 2>/dev/null || echo "⚠️ route:clear übersprungen"
php artisan view:clear 2>/dev/null || echo "⚠️ view:clear übersprungen"
# 2. Bootstrap Cache leeren
echo "2. 🗂️ Bootstrap Cache leeren..."
rm -f bootstrap/cache/*.php 2>/dev/null || echo "⚠️ bootstrap/cache/*.php nicht gefunden"
# 3. Route-Tests ausführen
echo "3. 🧪 Route-Tests ausführen..."
echo " - Create-Route Test:"
php test-route-fix.php 2>/dev/null || echo "⚠️ test-route-fix.php übersprungen"
echo " - Remove-Route Test:"
php test-remove-fix.php 2>/dev/null || echo "⚠️ test-remove-fix.php übersprungen"
# 4. Debug-Modus aktivieren
echo "4. 🐛 Debug-Modus aktivieren..."
if [ -f .env ]; then
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
sed -i 's/APP_ENV=production/APP_ENV=local/' .env
echo " ✅ Debug-Modus aktiviert"
else
echo " ❌ .env Datei nicht gefunden"
fi
# 5. Route-Liste anzeigen
echo "5. 📋 Route-Liste prüfen..."
php artisan route:list | grep -E "(create|remove|store)" 2>/dev/null || echo "⚠️ route:list übersprungen"
echo ""
echo "✅ Alle 405-Fehler behoben!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. Neuen Lack erstellen: https://neonail.vogt.de.com/create-nail-polish"
echo "2. Lack entfernen: https://neonail.vogt.de.com/my-collection"
echo "3. Admin-User verwalten: https://neonail.vogt.de.com/admin/users"
echo ""
echo "📝 Falls Probleme bestehen:"
echo "- Prüfen Sie die Browser-Entwicklertools (F12)"
echo "- Schauen Sie in storage/logs/laravel.log"
echo "- Führen Sie php artisan route:list aus"

97
fix-all-forms-https.sh Executable file
View File

@ -0,0 +1,97 @@
#!/bin/bash
echo "🔒 Alle Formulare für HTTPS reparieren"
echo "====================================="
# 1. Laravel Cache komplett leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
php artisan route:clear 2>/dev/null || echo "⚠️ route:clear übersprungen"
php artisan view:clear 2>/dev/null || echo "⚠️ view:clear übersprungen"
# 2. .env für HTTPS erzwingen
echo "📝 Erzwinge HTTPS in .env..."
sed -i 's|APP_URL=http://|APP_URL=https://|' .env
sed -i 's|APP_URL=https://192.168.30.81|APP_URL=https://neonail.vogt.de.com|' .env
# 3. Session-Konfiguration für HTTPS
echo "🔐 Konfiguriere Session für HTTPS..."
cat > config/session.php << 'EOF'
<?php
use Illuminate\Support\Str;
return [
'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION'),
'table' => 'sessions',
'store' => env('SESSION_STORE'),
'lottery' => [2, 100],
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => '/',
'domain' => env('SESSION_DOMAIN'),
'secure' => true,
'http_only' => true,
'same_site' => 'lax',
];
EOF
# 4. AppServiceProvider für HTTPS erzwingen
echo "⚙️ Konfiguriere AppServiceProvider für HTTPS..."
cat > app/Providers/AppServiceProvider.php << 'EOF'
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Blade;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
// Erzwinge HTTPS in Produktion
if (config('app.env') === 'production') {
URL::forceScheme('https');
}
// Blade-Directive für sichere URLs
Blade::directive('secureUrl', function ($expression) {
return "<?php echo secure_url($expression); ?>";
});
}
}
EOF
# 5. Apache neu laden
echo "🔄 Lade Apache neu..."
systemctl reload apache2
# 6. Test
echo "🧪 Teste HTTPS-Konfiguration..."
curl -I https://neonail.vogt.de.com
echo ""
echo "✅ Alle Formulare für HTTPS repariert!"
echo "📋 Testen Sie: https://neonail.vogt.de.com"
echo ""
echo "📋 Falls Warnung bleibt:"
echo "1. Safari-Cache leeren (Cmd+Shift+R)"
echo "2. Private-Fenster testen"
echo "3. Safari-Einstellungen: Entwickler > Leere Caches"
echo "4. Safari-Einstellungen: Datenschutz > Website-Daten verwalten"
echo "5. Safari komplett neu starten"

189
fix-all-safari-warnings.sh Executable file
View File

@ -0,0 +1,189 @@
#!/bin/bash
echo "🛡️ Fix: Alle Safari Sicherheitswarnungen"
echo "======================================="
# 1. Alle Formulare mit HTTPS-URLs beheben
echo "1. 🔒 Alle Formulare mit HTTPS beheben..."
# Login-Formular
if [ -f resources/views/auth/login.blade.php ]; then
sed -i 's|action="{{ route('\''login'\'') }}"|action="https://neonail.vogt.de.com/login"|' resources/views/auth/login.blade.php
echo " ✅ Login-Formular behoben"
fi
# Create Nail Polish Formular
if [ -f resources/views/user-nail-polishes/create.blade.php ]; then
sed -i 's|action="{{ route('\''user-nail-polishes.store'\'') }}"|action="https://neonail.vogt.de.com/create-nail-polish"|' resources/views/user-nail-polishes/create.blade.php
echo " ✅ Create Nail Polish Formular behoben"
fi
# Remove Nail Polish Formular
if [ -f resources/views/user-nail-polishes/index.blade.php ]; then
sed -i 's|action="https://neonail.vogt.de.com/user-nail-polishes/|action="https://neonail.vogt.de.com/remove-from-collection/|' resources/views/user-nail-polishes/index.blade.php
echo " ✅ Remove Nail Polish Formular behoben"
fi
# Admin Nail Polish Delete Formular
if [ -f resources/views/nail-polishes/index.blade.php ]; then
sed -i 's|action="{{ route('\''nail-polishes.destroy'\'', $nailPolish) }}"|action="https://neonail.vogt.de.com/nail-polishes/{{ $nailPolish->id }}"|' resources/views/nail-polishes/index.blade.php
echo " ✅ Admin Nail Polish Delete Formular behoben"
fi
# Admin User Create Formular
if [ -f resources/views/admin/users/create.blade.php ]; then
sed -i 's|action="{{ route('\''admin.users.store'\'') }}"|action="https://neonail.vogt.de.com/admin/users"|' resources/views/admin/users/create.blade.php
echo " ✅ Admin User Create Formular behoben"
fi
# Admin User Edit Formular
if [ -f resources/views/admin/users/edit.blade.php ]; then
sed -i 's|action="{{ route('\''admin.users.update'\'', $user) }}"|action="https://neonail.vogt.de.com/admin/users/{{ $user->id }}"|' resources/views/admin/users/edit.blade.php
echo " ✅ Admin User Edit Formular behoben"
fi
# Admin User Delete Formular
if [ -f resources/views/admin/users/index.blade.php ]; then
sed -i 's|action="{{ route('\''admin.users.destroy'\'', $user) }}"|action="https://neonail.vogt.de.com/admin/users/{{ $user->id }}"|' resources/views/admin/users/index.blade.php
echo " ✅ Admin User Delete Formular behoben"
fi
# 2. .env HTTPS-Einstellungen
echo "2. 🔒 .env HTTPS-Einstellungen..."
if [ -f .env ]; then
sed -i 's|APP_URL=.*|APP_URL=https://neonail.vogt.de.com|' .env
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/' .env
sed -i 's/APP_ENV=production/APP_ENV=local/' .env
# HTTPS-spezifische Einstellungen
grep -q "FORCE_HTTPS=true" .env || echo "FORCE_HTTPS=true" >> .env
grep -q "SECURE_COOKIES=true" .env || echo "SECURE_COOKIES=true" >> .env
grep -q "SESSION_SECURE_COOKIE=true" .env || echo "SESSION_SECURE_COOKIE=true" >> .env
grep -q "SESSION_SAME_SITE=lax" .env || echo "SESSION_SAME_SITE=lax" >> .env
grep -q "SESSION_HTTP_ONLY=true" .env || echo "SESSION_HTTP_ONLY=true" >> .env
echo " ✅ .env HTTPS-Einstellungen aktualisiert"
else
echo " ❌ .env Datei nicht gefunden"
fi
# 3. Session-Konfiguration
echo "3. 🍪 Session-Konfiguration..."
if [ -f config/session.php ]; then
sed -i "s/'secure' => false/'secure' => true/" config/session.php
sed -i "s/'http_only' => false/'http_only' => true/" config/session.php
echo " ✅ Session-Konfiguration aktualisiert"
else
echo " ❌ config/session.php nicht gefunden"
fi
# 4. CSRF-Konfiguration
echo "4. 🔐 CSRF-Konfiguration..."
if [ -f config/csrf.php ]; then
sed -i "s/'secure' => false/'secure' => true/" config/csrf.php
echo " ✅ CSRF-Konfiguration aktualisiert"
else
echo " ❌ config/csrf.php nicht gefunden"
fi
# 5. Minimale .htaccess mit HTTPS-Force
echo "5. 🌐 .htaccess HTTPS-Force..."
cat > public/.htaccess << 'EOF'
<IfModule mod_rewrite.c>
RewriteEngine On
# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
# Protect sensitive files
<Files ".env">
Order allow,deny
Deny from all
</Files>
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
<Files "*.sqlite">
Order allow,deny
Deny from all
</Files>
EOF
echo " ✅ .htaccess HTTPS-Force erstellt"
# 6. Laravel Cache leeren
echo "6. 🧹 Laravel Cache leeren..."
php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"
php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"
php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"
php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"
# 7. Test-Script erstellen
echo "7. 🧪 Test-Script erstellen..."
cat > test-all-forms.php << 'EOF'
<?php
// Test aller Formulare auf HTTPS
echo "🔒 Test aller Formulare auf HTTPS\n";
echo "===============================\n\n";
$forms = [
'resources/views/auth/login.blade.php' => 'Login-Formular',
'resources/views/user-nail-polishes/create.blade.php' => 'Create Nail Polish',
'resources/views/user-nail-polishes/index.blade.php' => 'Remove Nail Polish',
'resources/views/nail-polishes/index.blade.php' => 'Admin Delete Nail Polish',
'resources/views/admin/users/create.blade.php' => 'Admin Create User',
'resources/views/admin/users/edit.blade.php' => 'Admin Edit User',
'resources/views/admin/users/index.blade.php' => 'Admin Delete User'
];
foreach ($forms as $file => $description) {
if (file_exists($file)) {
$content = file_get_contents($file);
if (strpos($content, 'action="https://neonail.vogt.de.com') !== false) {
echo "$description: HTTPS-URL gefunden\n";
} else {
echo "$description: Keine HTTPS-URL gefunden\n";
}
} else {
echo "$description: Datei nicht gefunden\n";
}
}
echo "\n✅ Alle Formulare getestet!\n";
echo "🔗 Testen Sie jetzt: https://neonail.vogt.de.com\n";
?>
EOF
echo " ✅ Test-Script erstellt"
echo ""
echo "✅ Alle Safari Sicherheitswarnungen behoben!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. Login: https://neonail.vogt.de.com/login"
echo "2. Admin-Panel: https://neonail.vogt.de.com/admin/users"
echo "3. Lack erstellen: https://neonail.vogt.de.com/create-nail-polish"
echo ""
echo "📝 Falls Warnungen bestehen:"
echo "- Führen Sie php test-all-forms.php aus"
echo "- Leeren Sie Browser-Cache"
echo "- Prüfen Sie Browser-Entwicklertools (F12)"

67
fix-apache-documentroot.sh Executable file
View File

@ -0,0 +1,67 @@
#!/bin/bash
echo "🌐 Apache DocumentRoot korrigieren"
echo "================================="
# 1. Standard-Site deaktivieren
echo "🔧 Deaktiviere Standard-Site..."
a2dissite 000-default.conf 2>/dev/null || echo "⚠️ Standard-Site bereits deaktiviert"
# 2. NeoNail-Site neu erstellen
echo "📝 Erstelle NeoNail-Site neu..."
cat > /etc/apache2/sites-available/neonail.conf << 'EOF'
<VirtualHost *:80>
ServerName 192.168.30.81
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride All
Require all granted
Options Indexes FollowSymLinks
</Directory>
# Sicherheit für sensible Dateien
<Directory /var/www/html>
<Files ".env">
Order allow,deny
Deny from all
</Files>
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/neonail_error.log
CustomLog ${APACHE_LOG_DIR}/neonail_access.log combined
</VirtualHost>
EOF
# 3. NeoNail-Site aktivieren
echo "✅ Aktiviere NeoNail-Site..."
a2ensite neonail.conf
# 4. Apache-Konfiguration testen
echo "🔍 Teste Apache-Konfiguration..."
apache2ctl configtest
# 5. Apache neu laden
echo "🔄 Lade Apache neu..."
systemctl reload apache2
# 6. Status prüfen
echo "📊 Apache-Status..."
systemctl status apache2 --no-pager -l
# 7. Test
echo "🧪 Teste Anwendung..."
curl -I http://192.168.30.81
echo ""
echo "✅ Apache DocumentRoot korrigiert!"
echo "📋 Testen Sie: http://192.168.30.81"
echo ""
echo "📋 Falls es nicht funktioniert:"
echo "1. Apache-Logs: tail -f /var/log/apache2/neonail_error.log"
echo "2. DocumentRoot prüfen: apache2ctl -S"

103
fix-apache-headers.sh Executable file
View File

@ -0,0 +1,103 @@
#!/bin/bash
echo "🔧 Fix: Apache mod_headers aktivieren"
echo "===================================="
# 1. Prüfe verfügbare Apache-Module
echo "1. 🔍 Verfügbare Apache-Module prüfen..."
apache2ctl -M 2>/dev/null | grep -E "(headers|rewrite)" || echo " ⚠️ apache2ctl nicht verfügbar"
# 2. Aktiviere mod_headers
echo "2. 🔧 mod_headers aktivieren..."
a2enmod headers 2>/dev/null || echo " ⚠️ a2enmod headers fehlgeschlagen"
# 3. Aktiviere mod_rewrite (falls nicht aktiviert)
echo "3. 🔧 mod_rewrite aktivieren..."
a2enmod rewrite 2>/dev/null || echo " ⚠️ a2enmod rewrite fehlgeschlagen"
# 4. Apache neu laden
echo "4. 🔄 Apache neu laden..."
systemctl reload apache2 2>/dev/null || service apache2 reload 2>/dev/null || echo " ⚠️ Apache reload fehlgeschlagen"
# 5. Prüfe .htaccess Syntax
echo "5. 🔍 .htaccess Syntax prüfen..."
if [ -f public/.htaccess ]; then
echo " 📋 public/.htaccess gefunden"
echo " 📄 Header-Befehle in .htaccess:"
grep -n "Header" public/.htaccess || echo " ⚠️ Keine Header-Befehle gefunden"
else
echo " ❌ public/.htaccess nicht gefunden"
fi
# 6. Alternative .htaccess ohne Header erstellen
echo "6. 🔧 Alternative .htaccess erstellen..."
cat > public/.htaccess.simple << 'EOF'
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
# Protect sensitive files
<Files ".env">
Order allow,deny
Deny from all
</Files>
<Files "database.sqlite">
Order allow,deny
Deny from all
</Files>
<Files "*.sqlite">
Order allow,deny
Deny from all
</Files>
EOF
echo " ✅ Alternative .htaccess erstellt"
# 7. Backup und ersetze .htaccess
echo "7. 🔄 .htaccess ersetzen..."
if [ -f public/.htaccess ]; then
cp public/.htaccess public/.htaccess.backup
echo " ✅ Backup erstellt: public/.htaccess.backup"
fi
cp public/.htaccess.simple public/.htaccess
echo " ✅ .htaccess ersetzt"
# 8. Test Apache-Konfiguration
echo "8. 🧪 Apache-Konfiguration testen..."
apache2ctl -t 2>/dev/null && echo " ✅ Apache-Konfiguration OK" || echo " ❌ Apache-Konfiguration fehlerhaft"
echo ""
echo "✅ Apache mod_headers Fix abgeschlossen!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. https://neonail.vogt.de.com"
echo "2. Admin-Panel: https://neonail.vogt.de.com/admin/users"
echo ""
echo "📝 Falls Problem besteht:"
echo "- Prüfen Sie: apache2ctl -M | grep headers"
echo "- Schauen Sie in: /var/log/apache2/error.log"

View File

@ -0,0 +1,27 @@
#!/bin/bash
echo "🔧 Fix: AppServiceProvider Syntax-Fehler"
echo "======================================="
# 1. Syntax prüfen
echo "1. 🔍 PHP Syntax prüfen..."
php -l app/Providers/AppServiceProvider.php
# 2. Laravel Cache leeren
echo "2. 🧹 Laravel Cache leeren..."
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
# 3. HTTPS-Sicherheit testen
echo "3. 🧪 HTTPS-Sicherheit testen..."
php test-https-security.php
echo ""
echo "✅ AppServiceProvider Syntax-Fehler behoben!"
echo ""
echo "🔗 Testen Sie jetzt:"
echo "1. Admin-Panel: https://neonail.vogt.de.com/admin/users"
echo "2. Lack löschen im Admin-Panel"
echo "3. User bearbeiten/löschen"

48
fix-https-config.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/bash
echo "🔒 HTTPS-Konfiguration für NeoNail DB"
echo "===================================="
# 1. .env für HTTPS aktualisieren
echo "📝 Aktualisiere .env für HTTPS..."
sed -i 's|APP_URL=http://192.168.30.81|APP_URL=https://neonail.vogt.de.com|' .env
sed -i 's|APP_URL=http://neonail.vogt.de.com|APP_URL=https://neonail.vogt.de.com|' .env
# 2. Laravel Cache leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
# 3. Trusted Proxies konfigurieren (falls hinter Proxy)
echo "🔧 Konfiguriere Trusted Proxies..."
cat > config/trusted-proxies.php << 'EOF'
<?php
return [
'proxies' => [
'192.168.30.81',
'neonail.vogt.de.com',
],
'headers' => [
'X-Forwarded-For' => 'X_FORWARDED_FOR',
'X-Forwarded-Host' => 'X_FORWARDED_HOST',
'X-Forwarded-Proto' => 'X_FORWARDED_PROTO',
],
];
EOF
# 4. Session-Konfiguration für HTTPS
echo "🔐 Konfiguriere Sessions für HTTPS..."
sed -i 's|SESSION_SECURE_COOKIE=false|SESSION_SECURE_COOKIE=true|' .env 2>/dev/null || echo "⚠️ SESSION_SECURE_COOKIE nicht gefunden"
# 5. Test
echo "🧪 Teste HTTPS-Konfiguration..."
curl -I https://neonail.vogt.de.com
echo ""
echo "✅ HTTPS-Konfiguration abgeschlossen!"
echo "📋 Testen Sie: https://neonail.vogt.de.com"
echo ""
echo "📋 Falls Probleme auftreten:"
echo "1. Browser-Cache leeren"
echo "2. Laravel-Logs prüfen: tail -f storage/logs/laravel.log"

70
fix-https-form-security.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/bash
echo "🔒 HTTPS-Formular-Sicherheit beheben"
echo "==================================="
# 1. .env für HTTPS konfigurieren
echo "📝 Konfiguriere .env für HTTPS..."
sed -i 's|APP_URL=http://|APP_URL=https://|' .env
sed -i 's|APP_URL=https://192.168.30.81|APP_URL=https://neonail.vogt.de.com|' .env
# 2. Session-Konfiguration für HTTPS
echo "🔐 Konfiguriere Sessions für HTTPS..."
cat >> .env << 'EOF'
# HTTPS-Konfiguration
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax
EOF
# 3. Laravel Cache leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
php artisan route:clear 2>/dev/null || echo "⚠️ route:clear übersprungen"
# 4. CSRF-Token für HTTPS konfigurieren
echo "🛡️ Konfiguriere CSRF für HTTPS..."
cat > config/csrf.php << 'EOF'
<?php
return [
'cookie' => [
'secure' => true,
'same_site' => 'lax',
],
];
EOF
# 5. Trusted Proxies konfigurieren
echo "🌐 Konfiguriere Trusted Proxies..."
cat > config/trusted-proxies.php << 'EOF'
<?php
return [
'proxies' => [
'192.168.30.81',
'neonail.vogt.de.com',
'127.0.0.1',
'::1',
],
'headers' => [
'X-Forwarded-For' => 'X_FORWARDED_FOR',
'X-Forwarded-Host' => 'X_FORWARDED_HOST',
'X-Forwarded-Proto' => 'X_FORWARDED_PROTO',
],
];
EOF
# 6. Test
echo "🧪 Teste HTTPS-Konfiguration..."
curl -I https://neonail.vogt.de.com
echo ""
echo "✅ HTTPS-Formular-Sicherheit behoben!"
echo "📋 Testen Sie: https://neonail.vogt.de.com"
echo ""
echo "📋 Falls Warnungen bleiben:"
echo "1. Browser-Cache leeren (Strg+F5)"
echo "2. Private/Inkognito-Modus testen"
echo "3. HTTPS-Zertifikat prüfen"

55
fix-image-display.sh Executable file
View File

@ -0,0 +1,55 @@
#!/bin/bash
echo "🖼️ Bild-Anzeige reparieren"
echo "========================="
# 1. Storage Link prüfen und neu erstellen
echo "🔗 Prüfe Storage Link..."
if [ -L "public/storage" ]; then
echo "✅ Storage Link existiert"
ls -la public/storage
else
echo "❌ Storage Link fehlt - erstelle neu..."
rm -f public/storage
php artisan storage:link
fi
# 2. Storage-Verzeichnis-Berechtigungen
echo "🔐 Setze Storage-Berechtigungen..."
chmod -R 777 storage/
chmod -R 755 public/storage/
# 3. Bilder-Verzeichnis erstellen
echo "📁 Erstelle Bilder-Verzeichnis..."
mkdir -p storage/app/public/nail_polishes
chmod -R 777 storage/app/public/nail_polishes
# 4. Test-Bild erstellen (falls keine Bilder vorhanden)
echo "🧪 Erstelle Test-Bild..."
if [ ! -f "storage/app/public/nail_polishes/test.jpg" ]; then
# Einfaches Test-Bild erstellen
echo "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" | base64 -d > storage/app/public/nail_polishes/test.jpg
echo "✅ Test-Bild erstellt"
fi
# 5. Laravel Cache leeren
echo "🧹 Leere Laravel Cache..."
php artisan config:clear 2>/dev/null || echo "⚠️ config:clear übersprungen"
php artisan cache:clear 2>/dev/null || echo "⚠️ cache:clear übersprungen"
# 6. Test-URL prüfen
echo "🧪 Teste Bild-URL..."
curl -I https://neonail.vogt.de.com/storage/nail_polishes/test.jpg 2>/dev/null || echo "⚠️ Test-URL nicht erreichbar"
# 7. Datenbank-Bilder prüfen
echo "🗄️ Prüfe Datenbank-Bilder..."
sqlite3 database.sqlite "SELECT id, name, image_path FROM nail_polishes WHERE image_path IS NOT NULL;" 2>/dev/null || echo "⚠️ Keine Bilder in Datenbank gefunden"
echo ""
echo "✅ Bild-Anzeige repariert!"
echo "📋 Testen Sie: https://neonail.vogt.de.com/storage/nail_polishes/test.jpg"
echo ""
echo "📋 Falls Bilder immer noch nicht angezeigt werden:"
echo "1. Browser-Cache leeren (Strg+F5)"
echo "2. Private-Fenster testen"
echo "3. Bild-URL direkt aufrufen"

View File

@ -0,0 +1,49 @@
<?php
// Fallback für Bild-Upload ohne GD Extension
// Fügen Sie dies temporär in UserNailPolishController.php ein
// Ersetzen Sie den Bildverarbeitungs-Code in der store() Methode:
/*
// Original-Code (mit GD):
if ($request->hasFile('image') && $request->file('image')->isValid()) {
$image = $request->file('image');
$filename = 'nail_polish_' . time() . '_' . uniqid() . '.jpg';
$path = 'nail_polishes/' . $filename;
$manager = new ImageManager(new Driver());
$img = $manager->read($image);
$img->resize(400, 400, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
$imageData = $img->toJpeg(80)->toString();
Storage::disk('public')->put($path, $imageData);
$nailPolish->image_path = $path;
}
*/
// Fallback-Code (ohne GD):
if ($request->hasFile('image') && $request->file('image')->isValid()) {
$image = $request->file('image');
// Prüfe Dateigröße (max 2MB)
if ($image->getSize() > 2 * 1024 * 1024) {
return back()->with('error', 'Das Bild darf maximal 2MB groß sein.')->withInput();
}
// Prüfe Dateityp
$allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
if (!in_array($image->getMimeType(), $allowedTypes)) {
return back()->with('error', 'Nur JPG, PNG und GIF Dateien sind erlaubt.')->withInput();
}
// Speichere Original-Bild ohne Verarbeitung
$filename = 'nail_polish_' . time() . '_' . uniqid() . '.' . $image->getClientOriginalExtension();
$path = 'nail_polishes/' . $filename;
Storage::disk('public')->put($path, file_get_contents($image));
$nailPolish->image_path = $path;
}
?>

282
fix-image-upload-final.php Normal file
View File

@ -0,0 +1,282 @@
<?php
// Fix: Finales Bild-Upload-System
echo "📸 Fix: Finales Bild-Upload-System\n";
echo "==================================\n\n";
// 1. Controller mit vereinfachtem Upload erstellen (ohne Intervention Image)
echo "1. 🔧 Controller mit vereinfachtem Upload erstellen...\n";
$controllerContent = '<?php
namespace App\Http\Controllers;
use App\Models\NailPolish;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class UserNailPolishController extends Controller
{
/**
* Zeigt die Sammlung des aktuellen Benutzers an
*/
public function index(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = $user->nailPolishes();
if ($search) {
$query->where(function($q) use ($search) {
$q->where("name", "like", "%{$search}%")
->orWhere("number", "like", "%{$search}%");
});
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.index", compact("nailPolishes", "search"));
}
/**
* Zeigt alle verfügbaren Lacke an, die der User noch nicht hat
*/
public function available(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = NailPolish::whereNotIn("id", $user->nailPolishes()->pluck("nail_polishes.id"));
if ($search) {
$query->search($search);
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.available", compact("nailPolishes", "search"));
}
/**
* Fügt einen Lack zur Sammlung des Users hinzu
*/
public function add(NailPolish $nailPolish)
{
$user = Auth::user();
// Prüfe, ob der Lack bereits in der Sammlung ist
if ($user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist bereits in Ihrer Sammlung!");
}
$user->nailPolishes()->attach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde zu Ihrer Sammlung hinzugefügt!");
}
/**
* Entfernt einen Lack aus der Sammlung des Users
*/
public function remove(NailPolish $nailPolish)
{
try {
$user = Auth::user();
// Prüfe, ob der Lack in der Sammlung ist
if (!$user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist nicht in Ihrer Sammlung!");
}
$user->nailPolishes()->detach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde aus Ihrer Sammlung entfernt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Entfernen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Entfernen des Lackes. Bitte versuchen Sie es erneut.");
}
}
/**
* Zeigt das Formular zum Erstellen eines neuen Lackes
*/
public function create()
{
return view("user-nail-polishes.create");
}
/**
* Speichert einen neuen Lack (wird automatisch zum Hauptkatalog hinzugefügt)
*/
public function store(Request $request)
{
$request->validate([
"name" => "required|string|max:255",
"number" => "required|string|max:50",
"image" => "nullable|image|max:10240", // Max 10MB
], [
"name.required" => "Der Name des Lackes ist erforderlich.",
"number.required" => "Die Nummer des Lackes ist erforderlich.",
"image.image" => "Die Datei muss ein Bild sein.",
"image.max" => "Das Bild darf maximal 10MB groß sein.",
]);
try {
$nailPolish = new NailPolish();
$nailPolish->name = trim($request->name);
$nailPolish->number = trim($request->number);
// Vereinfachte Bildverarbeitung ohne Intervention Image
if ($request->hasFile("image") && $request->file("image")->isValid()) {
$image = $request->file("image");
// Erstelle einen eindeutigen Dateinamen
$filename = "nail_polish_" . time() . "_" . uniqid() . "." . $image->getClientOriginalExtension();
$path = "nail_polishes/" . $filename;
// Speichere das Bild direkt ohne Verarbeitung
Storage::disk("public")->putFileAs("nail_polishes", $image, $filename);
$nailPolish->image_path = $path;
\Log::info("Bild erfolgreich gespeichert: " . $path);
}
$nailPolish->save();
// Füge den Lack automatisch zur Sammlung des Users hinzu
$user = Auth::user();
$user->nailPolishes()->attach($nailPolish->id);
return redirect()->route("user-nail-polishes.index")
->with("success", "Lack \"{$nailPolish->name}\" wurde erfolgreich erstellt und zu Ihrer Sammlung hinzugefügt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Erstellen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Erstellen des Lackes: " . $e->getMessage())
->withInput();
}
}
/**
* Zeigt die Sammlung eines bestimmten Users (für Admin)
*/
public function showUserCollection(User $user)
{
$nailPolishes = $user->nailPolishes()->orderBy("name")->paginate(12);
return view("user-nail-polishes.show-user", compact("user", "nailPolishes"));
}
}';
file_put_contents('app/Http/Controllers/UserNailPolishController.php', $controllerContent);
echo " ✅ Controller mit vereinfachtem Upload erstellt\n";
// 2. Storage-Verzeichnisse erstellen
echo "2. 📁 Storage-Verzeichnisse erstellen...\n";
$directories = [
'storage/app/public',
'storage/app/public/nail_polishes'
];
foreach ($directories as $dir) {
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
echo " ✅ Verzeichnis erstellt: $dir\n";
} else {
echo " Verzeichnis existiert bereits: $dir\n";
}
}
// 3. Berechtigungen setzen
echo "3. 🔐 Berechtigungen setzen...\n";
system('chmod -R 755 storage/');
system('chown -R www-data:www-data storage/ 2>/dev/null || echo " ⚠️ chown fehlgeschlagen"');
echo " ✅ Berechtigungen gesetzt\n";
// 4. Storage Link erstellen
echo "4. 🔗 Storage Link erstellen...\n";
if (file_exists('public/storage')) {
if (is_dir('public/storage')) {
system('rm -rf public/storage');
}
}
system('ln -sf ../storage/app/public public/storage');
echo " ✅ Storage Link erstellt\n";
// 5. Laravel Cache leeren
echo "5. 🧹 Laravel Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 6. Test-Bild erstellen
echo "6. 🖼️ Test-Bild erstellen...\n";
$testImagePath = 'storage/app/public/nail_polishes/test.jpg';
if (extension_loaded('gd')) {
$image = imagecreate(100, 100);
$bgColor = imagecolorallocate($image, 255, 255, 255);
$textColor = imagecolorallocate($image, 0, 0, 0);
imagestring($image, 5, 10, 40, 'TEST', $textColor);
if (imagejpeg($image, $testImagePath, 80)) {
echo " ✅ Test-Bild erstellt: $testImagePath\n";
} else {
echo " ❌ Test-Bild erstellen fehlgeschlagen\n";
}
imagedestroy($image);
} else {
echo " ❌ GD Extension nicht verfügbar\n";
}
// 7. Upload-Limits in .htaccess prüfen
echo "7. 📏 Upload-Limits prüfen...\n";
$htaccessPath = 'public/.htaccess';
if (file_exists($htaccessPath)) {
$htaccessContent = file_get_contents($htaccessPath);
$requiredSettings = [
'upload_max_filesize 10M',
'post_max_size 10M',
'max_file_uploads 20',
'memory_limit 256M'
];
$missingSettings = [];
foreach ($requiredSettings as $setting) {
if (strpos($htaccessContent, $setting) === false) {
$missingSettings[] = $setting;
}
}
if (empty($missingSettings)) {
echo " ✅ Alle Upload-Limits in .htaccess vorhanden\n";
} else {
echo " ⚠️ Fehlende Upload-Limits: " . implode(', ', $missingSettings) . "\n";
// Füge fehlende Settings hinzu
$uploadSettings = "\n# Upload-Limits für Bild-Upload\n";
foreach ($missingSettings as $setting) {
$uploadSettings .= "php_value " . $setting . "\n";
}
$htaccessContent .= $uploadSettings;
file_put_contents($htaccessPath, $htaccessContent);
echo " ✅ Upload-Limits zu .htaccess hinzugefügt\n";
}
} else {
echo " ❌ .htaccess nicht gefunden\n";
}
echo "\n✅ Finales Bild-Upload-System erstellt!\n";
echo "🔗 Testen Sie jetzt: https://neonail.vogt.de.com/create-nail-polish\n";
echo "📝 Das System speichert Bilder jetzt direkt ohne Verarbeitung\n";
echo "📋 Falls Upload immer noch fehlschlägt:\n";
echo "- Prüfen Sie die Laravel-Logs: tail -f storage/logs/laravel.log\n";
echo "- Testen Sie mit einem kleinen Bild (< 1MB)\n";
echo "- Prüfen Sie Browser-Entwicklertools (F12) für Netzwerk-Fehler\n";
?>

222
fix-image-upload-simple.php Normal file
View File

@ -0,0 +1,222 @@
<?php
// Fix: Vereinfachtes Bild-Upload-System
echo "📸 Fix: Vereinfachtes Bild-Upload-System\n";
echo "======================================\n\n";
// 1. Controller mit vereinfachtem Upload erstellen
echo "1. 🔧 Controller mit vereinfachtem Upload erstellen...\n";
$controllerContent = '<?php
namespace App\Http\Controllers;
use App\Models\NailPolish;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class UserNailPolishController extends Controller
{
/**
* Zeigt die Sammlung des aktuellen Benutzers an
*/
public function index(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = $user->nailPolishes();
if ($search) {
$query->where(function($q) use ($search) {
$q->where("name", "like", "%{$search}%")
->orWhere("number", "like", "%{$search}%");
});
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.index", compact("nailPolishes", "search"));
}
/**
* Zeigt alle verfügbaren Lacke an, die der User noch nicht hat
*/
public function available(Request $request)
{
$user = Auth::user();
$search = $request->get("search");
$query = NailPolish::whereNotIn("id", $user->nailPolishes()->pluck("nail_polishes.id"));
if ($search) {
$query->search($search);
}
$nailPolishes = $query->orderBy("name")->paginate(12);
return view("user-nail-polishes.available", compact("nailPolishes", "search"));
}
/**
* Fügt einen Lack zur Sammlung des Users hinzu
*/
public function add(NailPolish $nailPolish)
{
$user = Auth::user();
// Prüfe, ob der Lack bereits in der Sammlung ist
if ($user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist bereits in Ihrer Sammlung!");
}
$user->nailPolishes()->attach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde zu Ihrer Sammlung hinzugefügt!");
}
/**
* Entfernt einen Lack aus der Sammlung des Users
*/
public function remove(NailPolish $nailPolish)
{
try {
$user = Auth::user();
// Prüfe, ob der Lack in der Sammlung ist
if (!$user->nailPolishes()->where("nail_polish_id", $nailPolish->id)->exists()) {
return back()->with("warning", "Dieser Lack ist nicht in Ihrer Sammlung!");
}
$user->nailPolishes()->detach($nailPolish->id);
return back()->with("success", "Lack \"{$nailPolish->name}\" wurde aus Ihrer Sammlung entfernt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Entfernen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Entfernen des Lackes. Bitte versuchen Sie es erneut.");
}
}
/**
* Zeigt das Formular zum Erstellen eines neuen Lackes
*/
public function create()
{
return view("user-nail-polishes.create");
}
/**
* Speichert einen neuen Lack (wird automatisch zum Hauptkatalog hinzugefügt)
*/
public function store(Request $request)
{
$request->validate([
"name" => "required|string|max:255",
"number" => "required|string|max:50",
"image" => "nullable|image|max:10240", // Max 10MB
], [
"name.required" => "Der Name des Lackes ist erforderlich.",
"number.required" => "Die Nummer des Lackes ist erforderlich.",
"image.image" => "Die Datei muss ein Bild sein.",
"image.max" => "Das Bild darf maximal 10MB groß sein.",
]);
try {
$nailPolish = new NailPolish();
$nailPolish->name = trim($request->name);
$nailPolish->number = trim($request->number);
// Vereinfachte Bildverarbeitung ohne Intervention Image
if ($request->hasFile("image") && $request->file("image")->isValid()) {
$image = $request->file("image");
// Erstelle einen eindeutigen Dateinamen
$filename = "nail_polish_" . time() . "_" . uniqid() . "." . $image->getClientOriginalExtension();
$path = "nail_polishes/" . $filename;
// Speichere das Bild direkt ohne Verarbeitung
Storage::disk("public")->putFileAs("nail_polishes", $image, $filename);
$nailPolish->image_path = $path;
\Log::info("Bild erfolgreich gespeichert: " . $path);
}
$nailPolish->save();
// Füge den Lack automatisch zur Sammlung des Users hinzu
$user = Auth::user();
$user->nailPolishes()->attach($nailPolish->id);
return redirect()->route("user-nail-polishes.index")
->with("success", "Lack \"{$nailPolish->name}\" wurde erfolgreich erstellt und zu Ihrer Sammlung hinzugefügt!");
} catch (\Exception $e) {
\Log::error("Fehler beim Erstellen des Lackes: " . $e->getMessage());
return back()->with("error", "Fehler beim Erstellen des Lackes: " . $e->getMessage())
->withInput();
}
}
/**
* Zeigt die Sammlung eines bestimmten Users (für Admin)
*/
public function showUserCollection(User $user)
{
$nailPolishes = $user->nailPolishes()->orderBy("name")->paginate(12);
return view("user-nail-polishes.show-user", compact("user", "nailPolishes"));
}
}';
file_put_contents('app/Http/Controllers/UserNailPolishController.php', $controllerContent);
echo " ✅ Controller mit vereinfachtem Upload erstellt\n";
// 2. Storage-Verzeichnisse erstellen
echo "2. 📁 Storage-Verzeichnisse erstellen...\n";
$directories = [
'storage/app/public',
'storage/app/public/nail_polishes'
];
foreach ($directories as $dir) {
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
echo " ✅ Verzeichnis erstellt: $dir\n";
} else {
echo " Verzeichnis existiert bereits: $dir\n";
}
}
// 3. Berechtigungen setzen
echo "3. 🔐 Berechtigungen setzen...\n";
system('chmod -R 755 storage/');
system('chown -R www-data:www-data storage/ 2>/dev/null || echo " ⚠️ chown fehlgeschlagen"');
echo " ✅ Berechtigungen gesetzt\n";
// 4. Storage Link erstellen
echo "4. 🔗 Storage Link erstellen...\n";
if (file_exists('public/storage')) {
if (is_dir('public/storage')) {
system('rm -rf public/storage');
}
}
system('ln -sf ../storage/app/public public/storage');
echo " ✅ Storage Link erstellt\n";
// 5. Laravel Cache leeren
echo "5. 🧹 Laravel Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
echo " ✅ Cache geleert\n";
echo "\n✅ Vereinfachtes Bild-Upload-System erstellt!\n";
echo "🔗 Testen Sie jetzt: https://neonail.vogt.de.com/create-nail-polish\n";
echo "📝 Das System speichert Bilder jetzt direkt ohne Verarbeitung\n";
echo "📋 Falls Upload immer noch fehlschlägt:\n";
echo "- Führen Sie php debug-image-upload.php aus\n";
echo "- Prüfen Sie die Laravel-Logs\n";
echo "- Testen Sie mit einem kleinen Bild (< 1MB)\n";
?>

60
fix-image-urls.php Normal file
View File

@ -0,0 +1,60 @@
<?php
// Robuste Bild-URL-Lösung für NeoNail DB
// Fügen Sie diese Helper-Funktion hinzu
// In app/Helpers/ImageHelper.php erstellen:
namespace App\Helpers;
class ImageHelper
{
public static function getImageUrl($imagePath)
{
if (!$imagePath) {
return null;
}
// Prüfe ob das Bild existiert
if (!\Storage::disk('public')->exists($imagePath)) {
return null;
}
// Erstelle die URL
$url = \Storage::disk('public')->url($imagePath);
// Stelle sicher, dass HTTPS verwendet wird
if (strpos($url, 'http://') === 0) {
$url = str_replace('http://', 'https://', $url);
}
return $url;
}
public static function getImageUrlOrPlaceholder($imagePath, $size = '400x400')
{
$url = self::getImageUrl($imagePath);
if ($url) {
return $url;
}
// Fallback zu einem Placeholder-Bild
return "https://via.placeholder.com/{$size}/cccccc/666666?text=Kein+Bild";
}
}
// In der View verwenden:
// {{ \App\Helpers\ImageHelper::getImageUrlOrPlaceholder($nailPolish->image_path) }}
// Oder als Blade-Directive in AppServiceProvider.php registrieren:
/*
public function boot()
{
Blade::directive('nailPolishImage', function ($expression) {
return "<?php echo \App\Helpers\ImageHelper::getImageUrlOrPlaceholder($expression); ?>";
});
}
*/
// Dann in der View:
// @nailPolishImage($nailPolish->image_path)
?>

53
fix-laravel-setup.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
echo "🔧 Laravel Setup Reparieren"
echo "==========================="
# 1. Vendor-Ordner prüfen
echo "📦 Prüfe vendor/ Ordner..."
if [ ! -d "vendor" ]; then
echo "❌ vendor/ Ordner nicht gefunden!"
echo "📋 Bitte laden Sie den vendor/ Ordner hoch oder führen Sie composer install aus"
exit 1
fi
# 2. Composer autoload neu generieren
echo "🔄 Generiere Composer autoload neu..."
if command -v composer &> /dev/null; then
composer dump-autoload --optimize
elif [ -f "composer.phar" ]; then
php composer.phar dump-autoload --optimize
else
echo "⚠️ Composer nicht verfügbar, überspringe autoload"
fi
# 3. Laravel Cache leeren
echo "🗑️ Leere Laravel Cache..."
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
# 4. Laravel neu initialisieren
echo "⚙️ Initialisiere Laravel neu..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 5. Berechtigungen setzen
echo "🔐 Setze Berechtigungen..."
chmod -R 755 vendor/
chmod -R 777 storage/
chmod -R 777 bootstrap/cache/
# 6. .env prüfen
echo "📝 Prüfe .env Datei..."
if [ ! -f ".env" ]; then
echo "❌ .env Datei nicht gefunden!"
echo "📋 Kopieren Sie env-production-example.txt zu .env"
exit 1
fi
echo ""
echo "✅ Laravel Setup repariert!"
echo "📋 Testen Sie jetzt: php artisan --version"

110
fix-logout-final.php Normal file
View File

@ -0,0 +1,110 @@
<?php
// Fix: Logout-Problem final beheben
echo "🔧 Fix: Logout-Problem final beheben\n";
echo "===================================\n\n";
// 1. Layout korrigieren
echo "1. 🎨 Layout korrigieren...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Ersetze hardcodierte Logout-URL
$oldAction = 'action="https://neonail.vogt.de.com/logout"';
$newAction = 'action="{{ route("logout") }}"';
if (strpos($content, $oldAction) !== false) {
$content = str_replace($oldAction, $newAction, $content);
file_put_contents($layoutPath, $content);
echo " ✅ Hardcodierte URL ersetzt: $oldAction$newAction\n";
} else {
echo " Keine hardcodierte URL gefunden\n";
}
// Prüfe ob die Korrektur erfolgreich war
if (strpos($content, '{{ route("logout") }}') !== false) {
echo " ✅ Laravel Route wird verwendet\n";
} else {
echo " ❌ Laravel Route wird nicht verwendet\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 2. Cache leeren
echo "\n2. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 3. Layout nochmal prüfen
echo "\n3. 🎨 Layout final prüfen...\n";
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Suche nach Logout-Form
if (strpos($content, 'logout-form') !== false) {
echo " ✅ Logout-Form gefunden\n";
// Zeige Logout-Form Details
$lines = explode("\n", $content);
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 Zeile " . ($lineNumber + 1) . ": " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Form nicht gefunden\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 4. JavaScript prüfen
echo "\n4. 🔧 JavaScript prüfen...\n";
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Suche nach onclick Event
if (strpos($content, 'onclick="event.preventDefault(); document.getElementById("logout-form").submit();"') !== false) {
echo " ✅ JavaScript Event Handler gefunden\n";
} else {
echo " ❌ JavaScript Event Handler nicht gefunden\n";
}
// Suche nach Bootstrap JS
if (strpos($content, 'bootstrap.bundle.min.js') !== false) {
echo " ✅ Bootstrap JS geladen\n";
} else {
echo " ❌ Bootstrap JS nicht geladen\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 5. Test-Anleitung
echo "\n5. 🧪 Test-Anleitung...\n";
echo " 📋 1. Öffnen Sie: https://neonail.vogt.de.com\n";
echo " 📋 2. Melden Sie sich an\n";
echo " 📋 3. Klicken Sie auf Ihren Benutzernamen (oben rechts)\n";
echo " 📋 4. Wählen Sie 'Abmelden' aus dem Dropdown\n";
echo " 📋 5. Sie sollten zur Login-Seite weitergeleitet werden\n";
echo "\n 🔍 Falls Problem besteht:\n";
echo " 📋 - Öffnen Sie Browser-Entwicklertools (F12)\n";
echo " 📋 - Gehen Sie zu Console-Tab\n";
echo " 📋 - Klicken Sie auf Abmelden\n";
echo " 📋 - Schauen Sie nach JavaScript-Fehlern\n";
echo " 📋 - Gehen Sie zu Network-Tab\n";
echo " 📋 - Schauen Sie welche URL aufgerufen wird\n";
echo "\n✅ Logout-Problem final behoben!\n";
echo "🔗 Testen Sie jetzt das Logout und teilen Sie mit:\n";
echo "1. Funktioniert das Logout jetzt?\n";
echo "2. Werden Sie zur Login-Seite weitergeleitet?\n";
echo "3. Falls nicht: Welche Fehlermeldungen sehen Sie?\n";
?>

194
fix-logout-route.php Normal file
View File

@ -0,0 +1,194 @@
<?php
// Fix: Logout-Route Cache-Problem beheben
echo "🔧 Fix: Logout-Route Cache-Problem beheben\n";
echo "=========================================\n\n";
// 1. Alle Cache-Dateien löschen
echo "1. 🗑️ Alle Cache-Dateien löschen...\n";
$cacheFiles = [
'bootstrap/cache/packages.php',
'bootstrap/cache/services.php',
'bootstrap/cache/routes.php',
'bootstrap/cache/config.php',
'bootstrap/cache/application.php'
];
foreach ($cacheFiles as $cacheFile) {
if (file_exists($cacheFile)) {
unlink($cacheFile);
echo " ✅ Gelöscht: $cacheFile\n";
} else {
echo " Nicht vorhanden: $cacheFile\n";
}
}
// 2. Composer autoload neu generieren
echo "\n2. 🔄 Composer autoload neu generieren...\n";
system('composer dump-autoload 2>/dev/null || echo " ⚠️ composer dump-autoload übersprungen"');
echo " ✅ Autoload neu generiert\n";
// 3. Laravel Cache komplett leeren
echo "\n3. 🧹 Laravel Cache komplett leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
system('php artisan optimize:clear 2>/dev/null || echo " ⚠️ optimize:clear übersprungen"');
echo " ✅ Laravel Cache geleert\n";
// 4. Routes-Datei prüfen und korrigieren
echo "\n4. 🛣️ Routes-Datei prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Zeige alle Logout-bezogenen Zeilen
$lines = explode("\n", $content);
$logoutLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
$logoutLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
if (!empty($logoutLines)) {
echo " ✅ Logout-Routes gefunden:\n";
foreach ($logoutLines as $line) {
echo " 📋 $line\n";
}
} else {
echo " ❌ Keine Logout-Routes gefunden\n";
}
// Prüfe ob die Route korrekt ist
if (strpos($content, "Route::post('/logout', [LoginController::class, 'logout'])->name('logout')->middleware('auth');") !== false) {
echo " ✅ Logout-Route ist korrekt definiert\n";
} else {
echo " ❌ Logout-Route ist nicht korrekt definiert\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 5. LoginController prüfen
echo "\n5. 🔐 LoginController prüfen...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
if (strpos($content, 'public function logout') !== false) {
echo " ✅ Logout-Methode vorhanden\n";
// Zeige Logout-Methode
$lines = explode("\n", $content);
$inLogoutMethod = false;
$methodLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'public function logout') !== false) {
$inLogoutMethod = true;
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
} elseif ($inLogoutMethod && strpos($line, 'public function') !== false) {
$inLogoutMethod = false;
} elseif ($inLogoutMethod) {
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
echo " 📋 Logout-Methode:\n";
foreach ($methodLines as $line) {
echo " $line\n";
}
} else {
echo " ❌ Logout-Methode nicht gefunden\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 6. Route-Liste neu generieren
echo "\n6. 🛣️ Route-Liste neu generieren...\n";
try {
require_once 'vendor/autoload.php';
// Laravel Bootstrap
$app = require_once 'bootstrap/app.php';
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
// Route-Liste abrufen
$routes = \Illuminate\Support\Facades\Route::getRoutes();
$logoutRoutes = [];
foreach ($routes as $route) {
$uri = $route->uri();
$methods = $route->methods();
$name = $route->getName();
if (strpos($uri, 'logout') !== false || strpos($name, 'logout') !== false) {
$logoutRoutes[] = [
'uri' => $uri,
'methods' => $methods,
'name' => $name
];
}
}
if (empty($logoutRoutes)) {
echo " ❌ Keine Logout-Routes in Laravel registriert\n";
} else {
echo " ✅ Logout-Routes in Laravel gefunden:\n";
foreach ($logoutRoutes as $route) {
$methods = implode('|', $route['methods']);
$name = $route['name'] ?: 'kein Name';
echo " 📋 $methods $uri ($name)\n";
}
}
} catch (Exception $e) {
echo " ❌ Fehler beim Abrufen der Routes: " . $e->getMessage() . "\n";
}
// 7. Test-Logout-Form erstellen
echo "\n7. 🧪 Test-Logout-Form erstellen...\n";
$testForm = '<!DOCTYPE html>
<html>
<head>
<title>Logout Test</title>
<meta charset="utf-8">
</head>
<body>
<h1>Logout Test</h1>
<form action="{{ route("logout") }}" method="POST">
@csrf
<button type="submit">Abmelden</button>
</form>
<p>Route: {{ route("logout") }}</p>
</body>
</html>';
file_put_contents('public/logout-test.blade.php', $testForm);
echo " ✅ Test-Form erstellt: public/logout-test.blade.php\n";
// 8. Apache neu laden (falls möglich)
echo "\n8. 🔄 Apache neu laden...\n";
system('systemctl reload apache2 2>/dev/null || echo " ⚠️ Apache reload übersprungen"');
echo " ✅ Apache neu geladen\n";
echo "\n✅ Logout-Route Fix abgeschlossen!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Klicken Sie auf Ihren Benutzernamen (oben rechts)\n";
echo "2. Wählen Sie 'Abmelden' aus dem Dropdown\n";
echo "3. Falls das nicht funktioniert:\n";
echo " - Öffnen Sie Browser-Entwicklertools (F12)\n";
echo " - Gehen Sie zu Network-Tab\n";
echo " - Klicken Sie auf Abmelden\n";
echo " - Schauen Sie welche URL aufgerufen wird\n";
echo "\n📋 Falls Problem besteht:\n";
echo "- Teilen Sie die Network-Tab Ausgabe mit\n";
echo "- Schauen Sie in die Laravel-Logs: tail -f storage/logs/laravel.log\n";
echo "- Testen Sie direkt: https://neonail.vogt.de.com/logout\n";
?>

147
fix-logout-simple-2.php Normal file
View File

@ -0,0 +1,147 @@
<?php
// Fix: Logout-Route Cache-Problem beheben (vereinfacht)
echo "🔧 Fix: Logout-Route Cache-Problem beheben (vereinfacht)\n";
echo "======================================================\n\n";
// 1. Alle Cache-Dateien löschen
echo "1. 🗑️ Alle Cache-Dateien löschen...\n";
$cacheFiles = [
'bootstrap/cache/packages.php',
'bootstrap/cache/services.php',
'bootstrap/cache/routes.php',
'bootstrap/cache/config.php',
'bootstrap/cache/application.php'
];
foreach ($cacheFiles as $cacheFile) {
if (file_exists($cacheFile)) {
unlink($cacheFile);
echo " ✅ Gelöscht: $cacheFile\n";
} else {
echo " Nicht vorhanden: $cacheFile\n";
}
}
// 2. Laravel Cache leeren (ohne Composer)
echo "\n2. 🧹 Laravel Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Laravel Cache geleert\n";
// 3. Routes-Datei prüfen
echo "\n3. 🛣️ Routes-Datei prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
// Zeige alle Logout-bezogenen Zeilen
$lines = explode("\n", $content);
$logoutLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
$logoutLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
if (!empty($logoutLines)) {
echo " ✅ Logout-Routes gefunden:\n";
foreach ($logoutLines as $line) {
echo " 📋 $line\n";
}
} else {
echo " ❌ Keine Logout-Routes gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 4. LoginController prüfen
echo "\n4. 🔐 LoginController prüfen...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
if (strpos($content, 'public function logout') !== false) {
echo " ✅ Logout-Methode vorhanden\n";
// Zeige Logout-Methode
$lines = explode("\n", $content);
$inLogoutMethod = false;
$methodLines = [];
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'public function logout') !== false) {
$inLogoutMethod = true;
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
} elseif ($inLogoutMethod && strpos($line, 'public function') !== false) {
$inLogoutMethod = false;
} elseif ($inLogoutMethod) {
$methodLines[] = ($lineNumber + 1) . ": " . trim($line);
}
}
echo " 📋 Logout-Methode:\n";
foreach ($methodLines as $line) {
echo " $line\n";
}
} else {
echo " ❌ Logout-Methode nicht gefunden\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 5. Layout prüfen
echo "\n5. 🎨 Layout prüfen...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Suche nach Logout-Form
if (strpos($content, 'logout-form') !== false) {
echo " ✅ Logout-Form gefunden\n";
// Zeige Logout-Form Details
$lines = explode("\n", $content);
foreach ($lines as $lineNumber => $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 Zeile " . ($lineNumber + 1) . ": " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Form nicht gefunden\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 6. Test-Logout-URL erstellen
echo "\n6. 🧪 Test-Logout-URL erstellen...\n";
$testUrl = 'https://neonail.vogt.de.com/logout';
echo " 🔗 Test-URL: $testUrl\n";
echo " 📋 Methode: POST\n";
echo " 📋 CSRF-Token erforderlich\n";
// 7. Einfacher Test
echo "\n7. 🧪 Einfacher Test...\n";
echo " 📋 Öffnen Sie: https://neonail.vogt.de.com\n";
echo " 📋 Melden Sie sich an\n";
echo " 📋 Klicken Sie auf Ihren Benutzernamen\n";
echo " 📋 Wählen Sie 'Abmelden'\n";
echo " 📋 Falls Fehler: Öffnen Sie Browser-Entwicklertools (F12)\n";
echo " 📋 Gehen Sie zu Network-Tab\n";
echo " 📋 Schauen Sie welche URL aufgerufen wird\n";
echo "\n✅ Logout-Route Fix abgeschlossen!\n";
echo "🔗 Testen Sie jetzt das Logout und teilen Sie mit:\n";
echo "1. Funktioniert das Logout?\n";
echo "2. Falls nicht: Welche URL wird im Network-Tab angezeigt?\n";
echo "3. Gibt es Fehlermeldungen in der Browser-Konsole?\n";
?>

81
fix-logout-simple.php Normal file
View File

@ -0,0 +1,81 @@
<?php
// Fix: Logout-Problem einfach beheben
echo "🚪 Fix: Logout-Problem einfach beheben\n";
echo "=====================================\n\n";
// 1. Layout-Datei korrigieren - nur den Logout-Teil
echo "1. 🎨 Logout-Teil im Layout korrigieren...\n";
$layoutPath = 'resources/views/layouts/app.blade.php';
if (file_exists($layoutPath)) {
$content = file_get_contents($layoutPath);
// Hardcodierte HTTPS-URL durch Laravel Route ersetzen
$oldLogoutForm = 'action="https://neonail.vogt.de.com/logout"';
$newLogoutForm = 'action="{{ route("logout") }}"';
if (strpos($content, $oldLogoutForm) !== false) {
$content = str_replace($oldLogoutForm, $newLogoutForm, $content);
file_put_contents($layoutPath, $content);
echo " ✅ Logout-Form korrigiert\n";
} else {
echo " Logout-Form bereits korrekt\n";
}
// Prüfe ob Route verwendet wird
if (strpos($content, '{{ route("logout") }}') !== false) {
echo " ✅ Laravel Route wird verwendet\n";
} else {
echo " ❌ Laravel Route wird nicht verwendet\n";
}
} else {
echo " ❌ Layout-Datei nicht gefunden\n";
}
// 2. Routes prüfen
echo "\n2. 🛣️ Logout-Route prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
if (strpos($content, 'logout') !== false) {
echo " ✅ Logout-Route gefunden\n";
// Zeige Logout-Route
$lines = explode("\n", $content);
foreach ($lines as $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Route nicht gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 3. Cache leeren
echo "\n3. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 4. Alternative Logout-URL testen
echo "\n4. 🔗 Alternative Logout-URLs:\n";
echo " - https://neonail.vogt.de.com/logout\n";
echo " - https://neonail.vogt.de.com/logout (POST)\n";
echo "\n✅ Logout-Problem behoben!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Klicken Sie auf Ihren Benutzernamen (oben rechts)\n";
echo "2. Wählen Sie 'Abmelden' aus dem Dropdown\n";
echo "3. Sie sollten zur Login-Seite weitergeleitet werden\n";
echo "\n📋 Falls Problem besteht:\n";
echo "- Versuchen Sie direkt: https://neonail.vogt.de.com/logout\n";
echo "- Prüfen Sie Browser-Entwicklertools (F12) für Fehler\n";
echo "- Schauen Sie in die Laravel-Logs: tail -f storage/logs/laravel.log\n";
?>

277
fix-logout.php Normal file
View File

@ -0,0 +1,277 @@
<?php
// Fix: Logout-Problem beheben
echo "🚪 Fix: Logout-Problem beheben\n";
echo "=============================\n\n";
// 1. Routes prüfen
echo "1. 🛣️ Logout-Route prüfen...\n";
$routesPath = 'routes/web.php';
if (file_exists($routesPath)) {
$content = file_get_contents($routesPath);
if (strpos($content, 'logout') !== false) {
echo " ✅ Logout-Route gefunden\n";
// Zeige Logout-Route Details
$lines = explode("\n", $content);
foreach ($lines as $line) {
if (strpos($line, 'logout') !== false) {
echo " 📋 " . trim($line) . "\n";
}
}
} else {
echo " ❌ Logout-Route nicht gefunden\n";
}
} else {
echo " ❌ Routes-Datei nicht gefunden\n";
}
// 2. Layout korrigieren
echo "\n2. 🎨 Layout korrigieren...\n";
$layoutContent = '<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>@yield("title", "NeoNail Datenbank")</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.navbar {
background: rgba(255, 255, 255, 0.95) !important;
backdrop-filter: blur(10px);
}
.card {
border: none;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.9);
}
.btn-primary {
background: linear-gradient(45deg, #667eea, #764ba2);
border: none;
border-radius: 25px;
padding: 10px 25px;
}
.btn-primary:hover {
background: linear-gradient(45deg, #5a6fd8, #6a4190);
transform: translateY(-2px);
}
.nail-polish-card {
transition: transform 0.3s ease;
}
.nail-polish-card:hover {
transform: translateY(-5px);
}
.nail-polish-image {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 10px;
}
.search-box {
border-radius: 25px;
border: 2px solid #e9ecef;
padding: 10px 20px;
}
.search-box:focus {
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.card {
margin-bottom: 15px;
}
}
/* Dropdown-Menüs über alle anderen Elemente legen */
.dropdown-menu {
z-index: 9999 !important;
position: absolute !important;
}
/* Navbar hat höheren z-index */
.navbar {
z-index: 1000 !important;
position: relative;
}
/* Dropdown-Container */
.dropdown {
position: relative;
}
/* Sicherstellen, dass Dropdowns über Cards angezeigt werden */
.navbar-nav .dropdown-menu {
z-index: 9999 !important;
position: absolute !important;
top: 100% !important;
left: 0 !important;
float: none !important;
}
</style>
@yield("styles")
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light">
<div class="container">
<a class="navbar-brand fw-bold" href="{{ route("user-nail-polishes.index") }}">
<i class="fas fa-palette me-2"></i>NeoNail DB
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
@auth
<li class="nav-item">
<a class="nav-link" href="{{ route("user-nail-polishes.index") }}">
<i class="fas fa-home me-1"></i>Meine Sammlung
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route("user-nail-polishes.available") }}">
<i class="fas fa-plus me-1"></i>Verfügbare Lacke
</a>
</li>
@if(auth()->user()->isAdmin())
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="fas fa-cog me-1"></i>Admin
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ route("admin.dashboard") }}">Dashboard</a></li>
<li><a class="dropdown-item" href="{{ route("admin.users.index") }}">Benutzer</a></li>
<li><a class="dropdown-item" href="{{ route("nail-polishes.index") }}">Nagellacke</a></li>
<li><a class="dropdown-item" href="{{ route("admin.statistics") }}">Statistiken</a></li>
</ul>
</li>
@endif
@endauth
</ul>
<ul class="navbar-nav">
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route("login") }}">Anmelden</a>
</li>
@else
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="fas fa-user me-1"></i>{{ Auth::user()->name }}
@if(auth()->user()->isAdmin())
<span class="badge bg-primary ms-1">Admin</span>
@endif
</a>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="#" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
<i class="fas fa-sign-out-alt me-1"></i>Abmelden
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</li>
</ul>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
<div class="container">
@if(session("success"))
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle me-2"></i>{{ session("success") }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
@if(session("error"))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle me-2"></i>{{ session("error") }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
@yield("content")
</div>
</main>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
@yield("scripts")
</body>
</html>';
file_put_contents('resources/views/layouts/app.blade.php', $layoutContent);
echo " ✅ Layout korrigiert\n";
// 3. LoginController prüfen
echo "\n3. 🔐 LoginController prüfen...\n";
$controllerPath = 'app/Http/Controllers/Auth/LoginController.php';
if (file_exists($controllerPath)) {
$content = file_get_contents($controllerPath);
if (strpos($content, 'logout') !== false) {
echo " ✅ Logout-Methode gefunden\n";
} else {
echo " ❌ Logout-Methode fehlt\n";
}
} else {
echo " ❌ LoginController nicht gefunden\n";
}
// 4. Cache leeren
echo "\n4. 🧹 Cache leeren...\n";
system('php artisan cache:clear 2>/dev/null || echo " ⚠️ cache:clear übersprungen"');
system('php artisan config:clear 2>/dev/null || echo " ⚠️ config:clear übersprungen"');
system('php artisan view:clear 2>/dev/null || echo " ⚠️ view:clear übersprungen"');
system('php artisan route:clear 2>/dev/null || echo " ⚠️ route:clear übersprungen"');
echo " ✅ Cache geleert\n";
// 5. Test-Logout-URL generieren
echo "\n5. 🔗 Test-Logout-URL:\n";
echo " https://neonail.vogt.de.com/logout\n";
echo "\n✅ Logout-Problem behoben!\n";
echo "🔗 Testen Sie jetzt:\n";
echo "1. Klicken Sie auf Ihren Benutzernamen (oben rechts)\n";
echo "2. Wählen Sie 'Abmelden' aus dem Dropdown\n";
echo "3. Sie sollten zur Login-Seite weitergeleitet werden\n";
echo "\n📋 Falls Problem besteht:\n";
echo "- Prüfen Sie Browser-Entwicklertools (F12) für Fehler\n";
echo "- Schauen Sie in die Laravel-Logs: tail -f storage/logs/laravel.log\n";
echo "- Versuchen Sie direkt: https://neonail.vogt.de.com/logout\n";
?>

Some files were not shown because too many files have changed in this diff Show More