Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84ac9e812a | |||
| d2f882ed61 | |||
| 4c586abee0 | |||
| 50c4096f3f |
+3
-1
@@ -4,4 +4,6 @@ certs
|
||||
build
|
||||
.venv
|
||||
__pycache__
|
||||
.pyc
|
||||
.pycvapid.json
|
||||
Web/vapid.json
|
||||
Web/vapid_*.pem
|
||||
|
||||
+4
-4
@@ -71,6 +71,10 @@ def get_current_status(ausleihung, log_changes=False, user=None):
|
||||
# Bei stornierten Ausleihungen bleibt der Status immer storniert
|
||||
if original_status == 'cancelled':
|
||||
return 'cancelled'
|
||||
|
||||
# Wenn die Ausleihung bereits abgeschlossen ist, bleibt sie es
|
||||
if original_status == 'completed':
|
||||
return 'completed'
|
||||
|
||||
current_time = datetime.datetime.now()
|
||||
start_time = ausleihung.get('Start')
|
||||
@@ -79,10 +83,6 @@ def get_current_status(ausleihung, log_changes=False, user=None):
|
||||
# Wenn kein Startdatum vorhanden ist, Status auf 'planned' setzen
|
||||
if not start_time:
|
||||
new_status = 'planned'
|
||||
# Wenn die Ausleihung als 'completed' markiert wurde und ein Enddatum hat,
|
||||
# bleibt sie bei 'completed'
|
||||
elif original_status == 'completed' and end_time:
|
||||
new_status = 'completed'
|
||||
# Wenn die aktuelle Zeit vor dem Startdatum liegt, ist die Ausleihung geplant
|
||||
elif current_time < start_time:
|
||||
# DEBUG: Log info wenn Booking noch lange in der Zukunft ist
|
||||
|
||||
@@ -16,11 +16,39 @@ import settings as cfg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# VAPID keys for push notifications (should be in environment variables)
|
||||
# VAPID keys for push notifications
|
||||
VAPID_PUBLIC_KEY = os.getenv('VAPID_PUBLIC_KEY', '')
|
||||
VAPID_PRIVATE_KEY = os.getenv('VAPID_PRIVATE_KEY', '')
|
||||
VAPID_SUBJECT = os.getenv('VAPID_SUBJECT', f'mailto:admin@{os.getenv("SERVER_NAME", "localhost")}')
|
||||
|
||||
VAPID_PRIVATE_PEM = os.path.join(os.path.dirname(__file__), 'vapid_private.pem')
|
||||
VAPID_PUBLIC_PEM = os.path.join(os.path.dirname(__file__), 'vapid_public.pem')
|
||||
|
||||
# Auto-generate VAPID keys if none are provided
|
||||
if not VAPID_PUBLIC_KEY or not VAPID_PRIVATE_KEY:
|
||||
try:
|
||||
from py_vapid import Vapid, b64urlencode
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
vapid = Vapid()
|
||||
if not os.path.exists(VAPID_PRIVATE_PEM):
|
||||
vapid.generate_keys()
|
||||
vapid.save_key(VAPID_PRIVATE_PEM)
|
||||
vapid.save_public_key(VAPID_PUBLIC_PEM)
|
||||
logger.info("Auto-generated new VAPID keys")
|
||||
else:
|
||||
vapid = Vapid.from_file(VAPID_PRIVATE_PEM)
|
||||
|
||||
raw_pub = vapid.public_key.public_bytes(
|
||||
serialization.Encoding.X962,
|
||||
serialization.PublicFormat.UncompressedPoint
|
||||
)
|
||||
|
||||
VAPID_PUBLIC_KEY = b64urlencode(raw_pub)
|
||||
VAPID_PRIVATE_KEY = VAPID_PRIVATE_PEM
|
||||
except Exception as e:
|
||||
logger.error(f'Could not load or generate VAPID keys: {e}')
|
||||
|
||||
# Push service endpoint (typically Firebase or Web Push Service)
|
||||
PUSH_SERVICE_URL = 'https://fcm.googleapis.com/fcm/send' # Firebase Cloud Messaging
|
||||
FCM_API_KEY = os.getenv('FCM_API_KEY', '') # Firebase API key
|
||||
@@ -296,7 +324,8 @@ def _send_web_push_notification(subscription, payload):
|
||||
data=json.dumps(payload),
|
||||
vapid_private_key=VAPID_PRIVATE_KEY,
|
||||
vapid_claims={'sub': VAPID_SUBJECT},
|
||||
timeout=10
|
||||
timeout=10,
|
||||
ttl=3600 # Notification expires after 1 hour if device is offline
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
@@ -13,4 +13,5 @@ redis
|
||||
reportlab
|
||||
python-barcode
|
||||
openpyxl
|
||||
cryptography
|
||||
cryptography
|
||||
pywebpush
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
<label for="booking-type">Reservierungstyp:</label>
|
||||
<select id="booking-type" name="booking_type">
|
||||
<option value="single">Einzeltermin</option>
|
||||
<option value="range">Zeitraum</option>
|
||||
<option value="recurring">Wiederkehrend</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -624,6 +626,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
|
||||
const userId = document.getElementById('user-id').value || 'Admin'; // Get user ID or use fallback
|
||||
const bookingType = document.getElementById('booking-type').value;
|
||||
|
||||
// Convert JSON data to FormData
|
||||
const formData = new FormData();
|
||||
@@ -631,16 +634,43 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Add all required fields with correct names the server expects
|
||||
formData.append('item_id', itemId);
|
||||
formData.append('booking_date', startDate);
|
||||
formData.append('booking_end_date', startDate); // For single bookings, end = start
|
||||
formData.append('period_start', periodStart);
|
||||
formData.append('period_end', periodEnd);
|
||||
formData.append('notes', document.getElementById('booking-notes').value || '');
|
||||
formData.append('booking_type', document.getElementById('booking-type').value);
|
||||
formData.append('user_id', userId);
|
||||
|
||||
if (bookingType === 'range') {
|
||||
const endDate = document.getElementById('booking-end-date').value;
|
||||
if (!endDate) {
|
||||
alert('Bitte wählen Sie ein Enddatum für den Zeitraum.');
|
||||
return;
|
||||
}
|
||||
formData.append('booking_end_date', endDate);
|
||||
formData.append('booking_type', 'range');
|
||||
} else if (bookingType === 'recurring') {
|
||||
formData.append('booking_type', 'single'); // Server expects 'single' structure for these individually sent requests
|
||||
const dates = calculateDates();
|
||||
if (dates.length === 0) {
|
||||
alert('Es konnten keine Termine berechnet werden. Bitte überprüfen Sie Ihre Eingaben.');
|
||||
return;
|
||||
}
|
||||
if (confirm(`Möchten Sie wirklich ${dates.length} Termine planen?`)) {
|
||||
processMultipleDates(formData, dates, periodStart, periodEnd);
|
||||
}
|
||||
return; // Use processMultipleDates instead
|
||||
} else {
|
||||
formData.append('booking_end_date', startDate); // For single bookings, end = start
|
||||
formData.append('booking_type', 'single');
|
||||
}
|
||||
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]') ? document.querySelector('meta[name="csrf-token"]').content : '';
|
||||
|
||||
// Submit with FormData instead of JSON
|
||||
fetch('/plan_booking', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
body: formData // Remove the Content-Type header and JSON.stringify
|
||||
})
|
||||
.then(response => {
|
||||
@@ -681,8 +711,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Cancel booking
|
||||
document.getElementById('cancel-booking').addEventListener('click', function() {
|
||||
if (confirm('Möchten Sie diese Ausleihe wirklich stornieren?')) {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]') ? document.querySelector('meta[name="csrf-token"]').content : '';
|
||||
fetch('/cancel_booking/' + currentEventId, {
|
||||
method: 'POST'
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': csrfToken
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -1131,8 +1165,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
newFormData.get('end_date'));
|
||||
|
||||
// Submit this booking
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]') ? document.querySelector('meta[name="csrf-token"]').content : '';
|
||||
fetch('/plan_booking', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
body: newFormData
|
||||
})
|
||||
.then(response => response.json())
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
from app import app
|
||||
with app.test_client() as client:
|
||||
with client.session_transaction() as sess:
|
||||
sess['username'] = 'admin'
|
||||
sess['admin'] = True
|
||||
resp = client.get('/terminplan')
|
||||
print("Status:", resp.status_code)
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# VAPID Key Generation Script for Web Push Notifications
|
||||
# Generates VAPID (Voluntary Application Server Identification) keys required for push notifications
|
||||
|
||||
echo "==========================================="
|
||||
echo "VAPID Key Generation for Inventarsystem"
|
||||
echo "==========================================="
|
||||
echo ""
|
||||
|
||||
# Check if Python is available
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "❌ Error: Python 3 is required but not installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if pywebpush is installed
|
||||
echo "Checking for pywebpush..."
|
||||
python3 -c "import pywebpush" 2>/dev/null
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Installing pywebpush..."
|
||||
pip3 install pywebpush
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Error: Failed to install pywebpush"
|
||||
echo "Please install manually: pip3 install pywebpush"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✓ pywebpush is installed"
|
||||
echo ""
|
||||
|
||||
# Generate VAPID keys
|
||||
echo "Generating VAPID keys..."
|
||||
python3 << 'EOF'
|
||||
from pywebpush import generate_keys
|
||||
|
||||
try:
|
||||
keys = generate_keys()
|
||||
print("✓ VAPID Keys generated successfully!")
|
||||
print("")
|
||||
print("PUBLIC KEY (share with browsers):")
|
||||
print(keys['public_key'])
|
||||
print("")
|
||||
print("PRIVATE KEY (keep secret!):")
|
||||
print(keys['private_key'])
|
||||
print("")
|
||||
print("==========================================="
|
||||
print("Add these to your environment variables:")
|
||||
print("==========================================="
|
||||
print("")
|
||||
print("export VAPID_PUBLIC_KEY='" + keys['public_key'] + "'")
|
||||
print("export VAPID_PRIVATE_KEY='" + keys['private_key'] + "'")
|
||||
print("export VAPID_SUBJECT='mailto:admin@yourdomain.com'")
|
||||
print("")
|
||||
print("Or add to your .env file:")
|
||||
print("")
|
||||
print("VAPID_PUBLIC_KEY=" + keys['public_key'])
|
||||
print("VAPID_PRIVATE_KEY=" + keys['private_key'])
|
||||
print("VAPID_SUBJECT=mailto:admin@yourdomain.com")
|
||||
print("")
|
||||
print("⚠️ IMPORTANT: Keep the PRIVATE KEY secret!")
|
||||
print("==========================================="
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error generating VAPID keys: {e}")
|
||||
exit(1)
|
||||
EOF
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✓ Next steps:"
|
||||
echo "1. Copy the PUBLIC KEY to your browser-side code"
|
||||
echo "2. Set the PRIVATE KEY in your server environment"
|
||||
echo "3. Update config.json with your email address"
|
||||
echo "4. Test with: curl http://localhost:5000/api/push/vapid-key"
|
||||
else
|
||||
echo "❌ Error generating keys"
|
||||
exit 1
|
||||
fi
|
||||
+1
-1
@@ -13,4 +13,4 @@ reportlab
|
||||
python-barcode
|
||||
openpyxl
|
||||
cryptography
|
||||
pywebpush
|
||||
pywebpush
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from Web.app import app
|
||||
with app.test_client() as client:
|
||||
resp = client.get('/terminplan')
|
||||
print(resp.status_code)
|
||||
# print(resp.data.decode('utf-8')[:200])
|
||||
Reference in New Issue
Block a user