"Add legal page (rechtliches.html) with impressum and privacy policy content in German, including styling and structure"
This commit is contained in:
parent
a973b40789
commit
d0db293bb8
@ -38,6 +38,12 @@ StartBackgroundServices();
|
||||
_serviceProvider.GetRequiredService<MainWindow>().Show();
|
||||
}
|
||||
|
||||
protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
|
||||
{
|
||||
TryShutdownCamera("OnSessionEnding");
|
||||
base.OnSessionEnding(e);
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
try
|
||||
@ -50,6 +56,8 @@ catch (Exception ex)
|
||||
System.Diagnostics.Debug.WriteLine($"Error stopping upload service: {ex.Message}");
|
||||
}
|
||||
|
||||
TryShutdownCamera("OnExit");
|
||||
|
||||
try
|
||||
{
|
||||
(_serviceProvider as IDisposable)?.Dispose();
|
||||
@ -129,4 +137,17 @@ catch (Exception ex)
|
||||
System.Diagnostics.Debug.WriteLine($"Error starting background services: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TryShutdownCamera(string source)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cameraService = _serviceProvider?.GetService<CameraService>();
|
||||
cameraService?.CloseSession();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error closing camera session ({source}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using Timer = System.Timers.Timer;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CamBooth.App.Core.AppSettings;
|
||||
@ -21,6 +22,7 @@ public class CameraService : IDisposable
|
||||
private ICamera? _mainCamera;
|
||||
private List<ICamera>? _camList;
|
||||
private bool _isConnected;
|
||||
private Timer? _shutdownKeepAliveTimer;
|
||||
|
||||
/// <summary>Fires whenever the camera delivers a new live-view frame.</summary>
|
||||
public event Action<Stream>? LiveViewUpdated;
|
||||
@ -99,6 +101,7 @@ public class CameraService : IDisposable
|
||||
{
|
||||
if (_mainCamera?.SessionOpen == true)
|
||||
{
|
||||
StopShutdownKeepAlive();
|
||||
_mainCamera.CloseSession();
|
||||
_logger.Info("Camera session closed");
|
||||
}
|
||||
@ -209,6 +212,9 @@ public class CameraService : IDisposable
|
||||
_mainCamera.StateChanged += MainCamera_StateChanged;
|
||||
_mainCamera.DownloadReady += MainCamera_DownloadReady;
|
||||
_mainCamera.LiveViewUpdated += MainCamera_LiveViewUpdated;
|
||||
_mainCamera.LiveViewStopped += MainCamera_LiveViewStopped;
|
||||
_mainCamera.CameraHasShutdown += MainCamera_CameraHasShutdown;
|
||||
StartShutdownKeepAlive();
|
||||
}
|
||||
|
||||
|
||||
@ -225,8 +231,6 @@ public class CameraService : IDisposable
|
||||
{
|
||||
if (!_mainCamera!.IsLiveViewOn)
|
||||
_mainCamera.StartLiveView();
|
||||
else
|
||||
_mainCamera.StopLiveView();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -247,11 +251,29 @@ public class CameraService : IDisposable
|
||||
private void MainCamera_LiveViewUpdated(ICamera sender, Stream img) =>
|
||||
LiveViewUpdated?.Invoke(img);
|
||||
|
||||
private void MainCamera_LiveViewStopped(ICamera sender)
|
||||
{
|
||||
if (!_isConnected) return;
|
||||
|
||||
_logger.Warning("LiveView stopped; attempting restart.");
|
||||
try
|
||||
{
|
||||
sender.StartLiveView();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to restart LiveView: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void MainCamera_StateChanged(EOSDigital.API.Camera sender, StateEventID eventID, int parameter)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (eventID == StateEventID.WillSoonShutDown || eventID == StateEventID.ShutDownTimerUpdate)
|
||||
ExtendShutdownTimer();
|
||||
|
||||
if (eventID == StateEventID.Shutdown && _isConnected)
|
||||
Application.Current.Dispatcher.Invoke(CloseSession);
|
||||
}
|
||||
@ -294,5 +316,49 @@ public class CameraService : IDisposable
|
||||
private void ErrorHandler_SevereErrorHappened(object sender, Exception ex) =>
|
||||
_logger.Error(ex.Message);
|
||||
|
||||
private void MainCamera_CameraHasShutdown(ICamera sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
StopShutdownKeepAlive();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed stopping shutdown keep-alive: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void StartShutdownKeepAlive()
|
||||
{
|
||||
if (_shutdownKeepAliveTimer != null) return;
|
||||
|
||||
_shutdownKeepAliveTimer = new Timer(20_000);
|
||||
_shutdownKeepAliveTimer.AutoReset = true;
|
||||
_shutdownKeepAliveTimer.Elapsed += (_, _) => ExtendShutdownTimer();
|
||||
_shutdownKeepAliveTimer.Start();
|
||||
}
|
||||
|
||||
private void StopShutdownKeepAlive()
|
||||
{
|
||||
if (_shutdownKeepAliveTimer == null) return;
|
||||
|
||||
_shutdownKeepAliveTimer.Stop();
|
||||
_shutdownKeepAliveTimer.Dispose();
|
||||
_shutdownKeepAliveTimer = null;
|
||||
}
|
||||
|
||||
private void ExtendShutdownTimer()
|
||||
{
|
||||
if (_mainCamera == null || !_mainCamera.SessionOpen) return;
|
||||
try
|
||||
{
|
||||
_mainCamera.SendCommand(CameraCommand.ExtendShutDownTimer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning($"ExtendShutDownTimer failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,79 +1,166 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
using System.Windows.Threading;
|
||||
using CamBooth.App.Core.Logging;
|
||||
using CamBooth.App.Features.Camera;
|
||||
|
||||
using EOSDigital.API;
|
||||
|
||||
namespace CamBooth.App.Features.LiveView;
|
||||
|
||||
public partial class LiveViewPage : Page, IDisposable
|
||||
{
|
||||
private readonly CameraService _cameraService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ImageBrush _bgBrush = new();
|
||||
private readonly CameraService _cameraService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ImageBrush _bgBrush = new();
|
||||
private int _targetPixelWidth;
|
||||
private readonly object _frameLock = new();
|
||||
private byte[]? _latestFrame;
|
||||
private int _workerRunning;
|
||||
|
||||
|
||||
public LiveViewPage(Logger logger, CameraService cameraService)
|
||||
{
|
||||
_logger = logger;
|
||||
_cameraService = cameraService;
|
||||
public LiveViewPage(Logger logger, CameraService cameraService)
|
||||
{
|
||||
_logger = logger;
|
||||
_cameraService = cameraService;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeComponent();
|
||||
|
||||
_bgBrush.Stretch = Stretch.UniformToFill;
|
||||
_bgBrush.AlignmentX = AlignmentX.Center;
|
||||
_bgBrush.AlignmentY = AlignmentY.Center;
|
||||
LVCanvas.Background = _bgBrush;
|
||||
_bgBrush.Stretch = Stretch.UniformToFill;
|
||||
_bgBrush.AlignmentX = AlignmentX.Center;
|
||||
_bgBrush.AlignmentY = AlignmentY.Center;
|
||||
LVCanvas.Background = _bgBrush;
|
||||
if (LVCanvas.ActualWidth > 0)
|
||||
_targetPixelWidth = (int)Math.Round(LVCanvas.ActualWidth);
|
||||
RenderOptions.SetBitmapScalingMode(LVCanvas, BitmapScalingMode.LowQuality);
|
||||
|
||||
var transformGroup = new TransformGroup();
|
||||
transformGroup.Children.Add(new ScaleTransform { ScaleX = -1, ScaleY = 1 });
|
||||
transformGroup.Children.Add(new TranslateTransform { X = 1, Y = 0 });
|
||||
LVCanvas.RenderTransform = transformGroup;
|
||||
LVCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
var transformGroup = new TransformGroup();
|
||||
transformGroup.Children.Add(new ScaleTransform { ScaleX = -1, ScaleY = 1 });
|
||||
transformGroup.Children.Add(new TranslateTransform { X = 1, Y = 0 });
|
||||
LVCanvas.RenderTransform = transformGroup;
|
||||
LVCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
LVCanvas.SizeChanged += (_, e) =>
|
||||
{
|
||||
var width = (int)Math.Round(e.NewSize.Width);
|
||||
if (width > 0) _targetPixelWidth = width;
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
cameraService.ConnectCamera();
|
||||
cameraService.LiveViewUpdated += OnLiveViewUpdated;
|
||||
_logger.Info("LiveViewPage initialized successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to initialize LiveViewPage: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cameraService.LiveViewUpdated -= OnLiveViewUpdated;
|
||||
_cameraService.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void OnLiveViewUpdated(Stream img)
|
||||
{
|
||||
try
|
||||
{
|
||||
using WrapStream s = new(img);
|
||||
img.Position = 0;
|
||||
var evfImage = new BitmapImage();
|
||||
evfImage.BeginInit();
|
||||
evfImage.StreamSource = s;
|
||||
evfImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
evfImage.EndInit();
|
||||
evfImage.Freeze();
|
||||
Application.Current.Dispatcher.BeginInvoke(() => _bgBrush.ImageSource = evfImage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
cameraService.ConnectCamera();
|
||||
cameraService.LiveViewUpdated += OnLiveViewUpdated;
|
||||
_logger.Info("LiveViewPage initialized successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Failed to initialize LiveViewPage: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cameraService.LiveViewUpdated -= OnLiveViewUpdated;
|
||||
_cameraService.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void OnLiveViewUpdated(Stream img)
|
||||
{
|
||||
if (img == null) return;
|
||||
if (!img.CanRead) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (img.CanSeek) img.Position = 0;
|
||||
using var ms = new MemoryStream();
|
||||
img.CopyTo(ms);
|
||||
lock (_frameLock)
|
||||
{
|
||||
_latestFrame = ms.ToArray();
|
||||
}
|
||||
TryStartWorker();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"LiveView update failed: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TryStartWorker()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _workerRunning, 1) == 1)
|
||||
return;
|
||||
|
||||
_ = Task.Run(ProcessFramesAsync);
|
||||
}
|
||||
|
||||
private async Task ProcessFramesAsync()
|
||||
{
|
||||
const int targetFps = 60;
|
||||
const double minFrameMs = 1000d / targetFps;
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
byte[]? frame;
|
||||
lock (_frameLock)
|
||||
{
|
||||
frame = _latestFrame;
|
||||
_latestFrame = null;
|
||||
}
|
||||
|
||||
if (frame == null)
|
||||
break;
|
||||
|
||||
BitmapImage? evfImage = null;
|
||||
try
|
||||
{
|
||||
using var ms = new MemoryStream(frame);
|
||||
evfImage = new BitmapImage();
|
||||
evfImage.BeginInit();
|
||||
evfImage.StreamSource = ms;
|
||||
evfImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
if (_targetPixelWidth > 0)
|
||||
evfImage.DecodePixelWidth = _targetPixelWidth;
|
||||
evfImage.EndInit();
|
||||
evfImage.Freeze();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"LiveView decode failed: {ex}");
|
||||
}
|
||||
|
||||
if (evfImage != null)
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(
|
||||
() => _bgBrush.ImageSource = evfImage,
|
||||
DispatcherPriority.Render);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
var remainingMs = minFrameMs - sw.Elapsed.TotalMilliseconds;
|
||||
if (remainingMs > 0)
|
||||
await Task.Delay((int)remainingMs);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Exchange(ref _workerRunning, 0);
|
||||
lock (_frameLock)
|
||||
{
|
||||
if (_latestFrame != null)
|
||||
TryStartWorker();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ public partial class PictureGalleryPage : Page
|
||||
|
||||
public async Task ShowPhotoDialogAsync(string picturePath)
|
||||
{
|
||||
var imageToShow = new System.Windows.Controls.Image
|
||||
var imageToShow = new Image
|
||||
{
|
||||
MaxHeight = 570,
|
||||
MaxWidth = 800,
|
||||
|
||||
193
src/CamBooth/CamBooth.App/rechtliches.html
Normal file
193
src/CamBooth/CamBooth.App/rechtliches.html
Normal file
@ -0,0 +1,193 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<title>Rechtliches – Impressum & Datenschutz</title>
|
||||
<style>
|
||||
:root { color-scheme: light; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #0f172a;
|
||||
background: #f8fafc;
|
||||
}
|
||||
.wrap {
|
||||
max-width: 920px;
|
||||
margin: 28px auto;
|
||||
padding: 0 16px;
|
||||
}
|
||||
header {
|
||||
background: linear-gradient(135deg, #0f172a 0%, #1f2937 55%, #111827 100%);
|
||||
color: #fff;
|
||||
border-radius: 14px;
|
||||
padding: 22px 22px;
|
||||
box-shadow: 0 10px 30px rgba(2, 6, 23, 0.18);
|
||||
}
|
||||
header h1 {
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 28px;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
header p {
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
main {
|
||||
margin-top: 16px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 14px;
|
||||
padding: 20px 22px;
|
||||
box-shadow: 0 8px 18px rgba(2, 6, 23, 0.06);
|
||||
}
|
||||
h2 {
|
||||
margin: 22px 0 10px 0;
|
||||
font-size: 18px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #eef2f7;
|
||||
}
|
||||
h2:first-of-type { border-top: none; padding-top: 0; }
|
||||
h3 {
|
||||
margin: 16px 0 6px 0;
|
||||
font-size: 15px;
|
||||
color: #111827;
|
||||
}
|
||||
.grid {
|
||||
display: table;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
}
|
||||
.row { display: table-row; }
|
||||
.cell {
|
||||
display: table-cell;
|
||||
padding: 6px 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.k { width: 160px; color: #334155; font-weight: 700; }
|
||||
.v { color: #0f172a; }
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
background: #eef2ff;
|
||||
color: #3730a3;
|
||||
border: 1px solid #e0e7ff;
|
||||
margin-left: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.callout {
|
||||
margin: 14px 0;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5f9;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.callout strong { display: block; margin-bottom: 4px; }
|
||||
|
||||
ul { margin: 6px 0 10px 18px; }
|
||||
li { margin: 4px 0; }
|
||||
|
||||
code {
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 0 6px;
|
||||
border-radius: 6px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
a { color: #1d4ed8; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
footer {
|
||||
margin: 12px 2px 0 2px;
|
||||
color: #475569;
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
.muted { color: #475569; }
|
||||
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<header>
|
||||
<h1>Rechtliches</h1>
|
||||
<p>Impressum & Datenschutzerklärung für die private Fotobox‑Online‑Galerie</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h2>Impressum <span class="badge">Deutschland</span></h2>
|
||||
<div class="grid" aria-label="Impressum">
|
||||
<div class="row">
|
||||
<div class="cell k">Betreiber</div>
|
||||
<div class="cell v">Tobias Wohlleben</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell k">Anschrift</div>
|
||||
<div class="cell v">Grethener Str. 32, 04668 Parthenstein</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell k">E‑Mail</div>
|
||||
<div class="cell v">info@fgrimma-fotobox.de</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Datenschutzerklärung</h2>
|
||||
|
||||
<h3>1. Verantwortlicher</h3>
|
||||
<p>Verantwortlich für die Verarbeitung personenbezogener Daten im Sinne der Datenschutz‑Grundverordnung (DSGVO) ist die im Impressum genannte Person.</p>
|
||||
|
||||
<h3>2. Zweck der Verarbeitung</h3>
|
||||
<p>Diese Webseite dient der Bereitstellung einer privaten Online‑Galerie (PhotoPrism). Nutzer/Teilnehmer einer Veranstaltung können die mit der Fotobox aufgenommenen Fotos ansehen und herunterladen. Der Zugriff erfolgt über individuelle Album‑Share‑Links (z. B. per QR‑Code).</p>
|
||||
|
||||
<h3>3. Art der verarbeiteten Daten</h3>
|
||||
<ul>
|
||||
<li><strong>Bilddaten (Fotos)</strong>, auf denen Personen erkennbar sein können.</li>
|
||||
<li><strong>Technische Zugriffsdaten</strong> (Server‑Logfiles), z. B. IP‑Adresse, Datum/Uhrzeit, aufgerufene Ressourcen, User‑Agent.</li>
|
||||
<li><strong>Nutzungsdaten</strong> (aggregierte Statistikdaten) im Rahmen der Webanalyse mit Umami (self‑hosted).</li>
|
||||
</ul>
|
||||
|
||||
<h3>4. Rechtsgrundlagen</h3>
|
||||
<ul>
|
||||
<li><strong>Bereitstellung der Galerie / Verarbeitung der Fotos:</strong> Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Die erforderlichen Informationen werden zusätzlich direkt an der Fotobox bereitgestellt.</li>
|
||||
<li><strong>Server‑Logfiles:</strong> Berechtigtes Interesse (Art. 6 Abs. 1 lit. f DSGVO) an IT‑Sicherheit, Stabilität, Fehleranalyse und Missbrauchsabwehr.</li>
|
||||
<li><strong>Webanalyse (Umami):</strong> Berechtigtes Interesse (Art. 6 Abs. 1 lit. f DSGVO) an datensparsamer Reichweitenmessung und technischer Optimierung. Umami wird ohne Cookies betrieben.</li>
|
||||
</ul>
|
||||
|
||||
<h3>5. Zugriff auf die Alben / Empfängerkreis</h3>
|
||||
<p>Die Fotoalben sind <strong>nicht öffentlich indexierbar</strong>. Zugriff erhalten nur Personen, die den jeweiligen Album‑Share‑Link/QR‑Code besitzen (ggf. zusätzlich passwortgeschützt). Eine Veröffentlichung der Fotos außerhalb der Galerie erfolgt nicht durch den Betreiber.</p>
|
||||
|
||||
<h3>6. Speicherdauer / Löschung</h3>
|
||||
<p>Die Fotos werden für <strong>6 Monate ab dem Folgetag nach dem Event</strong> vorgehalten und anschließend <strong>automatisch gelöscht</strong>, sofern keine Gründe für eine längere Speicherung bestehen (z. B. zur Abwehr von Rechtsansprüchen im Einzelfall).</p>
|
||||
<p>Server‑Logfiles werden nur so lange gespeichert, wie es für den technischen Betrieb und die Sicherheit erforderlich ist (in der Regel kurzzeitig) und anschließend gelöscht bzw. rotiert.</p>
|
||||
|
||||
<h3>7. Hosting / Auftragsverarbeitung</h3>
|
||||
<p>Die Systeme werden auf einem virtuellen Server (VPS) bei <strong>STRATO</strong> in <strong>Deutschland</strong> betrieben. Der Hosting‑Anbieter verarbeitet dabei technische Daten (z. B. IP‑Adressen in Server‑Logs) im Rahmen der Bereitstellung der Infrastruktur.</p>
|
||||
|
||||
<h3>8. Webanalyse mit Umami (self‑hosted)</h3>
|
||||
<p>Zur statistischen Auswertung der Nutzung setzen wir <strong>Umami</strong> ein (self‑hosted). Umami wird <strong>ohne Cookies</strong> betrieben. Es werden keine Profile über einzelne Besucher erstellt. Die Auswertung erfolgt in aggregierter Form (z. B. Seitenaufrufe). Da Umami auf dem eigenen Server betrieben wird, werden keine Analysedaten an einen Drittanbieter übermittelt.</p>
|
||||
|
||||
<h3>9. Sicherheit (HTTPS)</h3>
|
||||
<p>Die Verbindung zu dieser Webseite erfolgt verschlüsselt (HTTPS), um Inhalte und Zugangsdaten während der Übertragung zu schützen.</p>
|
||||
|
||||
<h3>10. Rechte der betroffenen Personen</h3>
|
||||
<p>Du hast nach der DSGVO insbesondere folgende Rechte: Auskunft (Art. 15), Berichtigung (Art. 16), Löschung (Art. 17), Einschränkung der Verarbeitung (Art. 18), Datenübertragbarkeit (Art. 20, soweit anwendbar), Widerspruch (Art. 21) sowie Widerruf erteilter Einwilligungen mit Wirkung für die Zukunft (Art. 7 Abs. 3).</p>
|
||||
<p>Wenn du die Entfernung eines Fotos wünschst, schreibe bitte an <strong>info@grimma-fotobox.de</strong> und nenne (wenn möglich) das Event/Album und das betroffene Foto.</p>
|
||||
|
||||
<h3>11. Beschwerderecht</h3>
|
||||
<p>Du hast das Recht, dich bei einer Datenschutzaufsichtsbehörde zu beschweren (Art. 77 DSGVO).</p>
|
||||
|
||||
<h3>12. Stand</h3>
|
||||
<p>Stand: <span class="mono">10.03.2026</span></p>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user