740 lines
22 KiB
Markdown
740 lines
22 KiB
Markdown
# Authentication System - Implementatie Voorbeelden
|
|
|
|
## Code Voorbeelden
|
|
|
|
### 1. Login Pagina (auth/login.php)
|
|
|
|
```php
|
|
<?php
|
|
session_start();
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
use Dotenv\Dotenv;
|
|
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
|
|
$dotenv->load();
|
|
|
|
$db = new PDO(
|
|
"mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_NAME']}",
|
|
$_ENV['DB_USER'],
|
|
$_ENV['DB_PASS']
|
|
);
|
|
|
|
$error = '';
|
|
$redirect = $_GET['redirect'] ?? 'index.php';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$username = $_POST['username'] ?? '';
|
|
$password = $_POST['password'] ?? '';
|
|
|
|
// Check brute force
|
|
$stmt = $db->prepare("
|
|
SELECT COUNT(*) FROM login_attempts
|
|
WHERE username = ? AND success = 0
|
|
AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
|
|
");
|
|
$stmt->execute([$username]);
|
|
$failedAttempts = $stmt->fetchColumn();
|
|
|
|
if ($failedAttempts >= 5) {
|
|
$error = 'Te veel mislukte pogingen. Probeer het over 15 minuten opnieuw.';
|
|
} else {
|
|
// Verify credentials
|
|
$stmt = $db->prepare("
|
|
SELECT id, username, email, password_hash, role, is_active
|
|
FROM users
|
|
WHERE (username = ? OR email = ?) AND is_active = 1
|
|
");
|
|
$stmt->execute([$username, $username]);
|
|
$user = $stmt->fetch();
|
|
|
|
if ($user && password_verify($password, $user['password_hash'])) {
|
|
// Success - create session
|
|
session_regenerate_id(true);
|
|
$_SESSION['user_id'] = $user['id'];
|
|
$_SESSION['user'] = [
|
|
'id' => $user['id'],
|
|
'username' => $user['username'],
|
|
'email' => $user['email'],
|
|
'role' => $user['role']
|
|
];
|
|
|
|
// Log success
|
|
$stmt = $db->prepare("
|
|
INSERT INTO login_attempts (username, ip_address, success)
|
|
VALUES (?, ?, 1)
|
|
");
|
|
$stmt->execute([$username, $_SERVER['REMOTE_ADDR']]);
|
|
|
|
// Update last login
|
|
$stmt = $db->prepare("UPDATE users SET last_login = NOW() WHERE id = ?");
|
|
$stmt->execute([$user['id']]);
|
|
|
|
header("Location: ../$redirect");
|
|
exit;
|
|
} else {
|
|
// Failed login
|
|
$error = 'Ongeldige gebruikersnaam of wachtwoord';
|
|
|
|
$stmt = $db->prepare("
|
|
INSERT INTO login_attempts (username, ip_address, success)
|
|
VALUES (?, ?, 0)
|
|
");
|
|
$stmt->execute([$username, $_SERVER['REMOTE_ADDR']]);
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Login - Telvero Talpa</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
|
<style>
|
|
body {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.login-card {
|
|
max-width: 400px;
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="login-card">
|
|
<div class="card shadow-lg">
|
|
<div class="card-body p-5">
|
|
<div class="text-center mb-4">
|
|
<i class="bi bi-tv" style="font-size: 3rem; color: #667eea;"></i>
|
|
<h3 class="mt-3">Telvero Talpa</h3>
|
|
<p class="text-muted">Planning System</p>
|
|
</div>
|
|
|
|
<?php if ($error): ?>
|
|
<div class="alert alert-danger">
|
|
<i class="bi bi-exclamation-triangle"></i>
|
|
<?= htmlspecialchars($error) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<form method="POST">
|
|
<div class="mb-3">
|
|
<label class="form-label">Gebruikersnaam of Email</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">
|
|
<i class="bi bi-person"></i>
|
|
</span>
|
|
<input type="text"
|
|
name="username"
|
|
class="form-control"
|
|
required
|
|
autofocus
|
|
value="<?= htmlspecialchars($_POST['username'] ?? '') ?>">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Wachtwoord</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">
|
|
<i class="bi bi-lock"></i>
|
|
</span>
|
|
<input type="password"
|
|
name="password"
|
|
class="form-control"
|
|
required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3 form-check">
|
|
<input type="checkbox" class="form-check-input" id="remember" name="remember">
|
|
<label class="form-check-label" for="remember">
|
|
Onthoud mij
|
|
</label>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary w-100">
|
|
<i class="bi bi-box-arrow-in-right"></i> Inloggen
|
|
</button>
|
|
</form>
|
|
|
|
<div class="mt-4 text-center">
|
|
<small class="text-muted">
|
|
Telvero © <?= date('Y') ?>
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
### 2. Authenticatie Functies (auth/auth_functions.php)
|
|
|
|
```php
|
|
<?php
|
|
/**
|
|
* Authentication Helper Functions
|
|
*/
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
use Dotenv\Dotenv;
|
|
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
|
|
$dotenv->load();
|
|
|
|
/**
|
|
* Get database connection
|
|
*/
|
|
function getAuthDb() {
|
|
static $db = null;
|
|
if ($db === null) {
|
|
$db = new PDO(
|
|
"mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_NAME']}",
|
|
$_ENV['DB_USER'],
|
|
$_ENV['DB_PASS']
|
|
);
|
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
}
|
|
return $db;
|
|
}
|
|
|
|
/**
|
|
* Check if user is logged in
|
|
*/
|
|
function isLoggedIn() {
|
|
return isset($_SESSION['user_id']) && isset($_SESSION['user']);
|
|
}
|
|
|
|
/**
|
|
* Get current logged in user
|
|
*/
|
|
function getCurrentUser() {
|
|
return $_SESSION['user'] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Check if user has specific role
|
|
*/
|
|
function hasRole($role) {
|
|
if (!isLoggedIn()) {
|
|
return false;
|
|
}
|
|
return $_SESSION['user']['role'] === $role;
|
|
}
|
|
|
|
/**
|
|
* Check if user is admin
|
|
*/
|
|
function isAdmin() {
|
|
return hasRole('admin');
|
|
}
|
|
|
|
/**
|
|
* Check if user is guest
|
|
*/
|
|
function isGuest() {
|
|
return hasRole('guest');
|
|
}
|
|
|
|
/**
|
|
* Require user to be logged in
|
|
*/
|
|
function requireLogin() {
|
|
if (!isLoggedIn()) {
|
|
$currentUrl = $_SERVER['REQUEST_URI'];
|
|
$redirect = urlencode($currentUrl);
|
|
header("Location: /auth/login.php?redirect=$redirect");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Require user to have specific role
|
|
*/
|
|
function requireRole($role) {
|
|
requireLogin();
|
|
|
|
if (!hasRole($role)) {
|
|
http_response_code(403);
|
|
echo '<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Geen Toegang</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
|
</head>
|
|
<body class="bg-light">
|
|
<div class="container mt-5">
|
|
<div class="alert alert-danger">
|
|
<h4><i class="bi bi-exclamation-triangle"></i> Geen Toegang</h4>
|
|
<p>Je hebt geen toegang tot deze pagina.</p>
|
|
<a href="/index.php" class="btn btn-primary">Terug naar Dashboard</a>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>';
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Require admin role
|
|
*/
|
|
function requireAdmin() {
|
|
requireRole('admin');
|
|
}
|
|
|
|
/**
|
|
* Logout user
|
|
*/
|
|
function logout() {
|
|
$_SESSION = [];
|
|
|
|
if (isset($_COOKIE[session_name()])) {
|
|
setcookie(session_name(), '', time() - 3600, '/');
|
|
}
|
|
|
|
session_destroy();
|
|
}
|
|
|
|
/**
|
|
* Check if user can perform write operations
|
|
*/
|
|
function canWrite() {
|
|
return isLoggedIn() && isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Check if user can only read
|
|
*/
|
|
function canOnlyRead() {
|
|
return isLoggedIn() && isGuest();
|
|
}
|
|
```
|
|
|
|
### 3. Middleware (auth/middleware.php)
|
|
|
|
```php
|
|
<?php
|
|
/**
|
|
* Authorization Middleware
|
|
*/
|
|
|
|
require_once __DIR__ . '/auth_functions.php';
|
|
|
|
/**
|
|
* Check if user can create
|
|
*/
|
|
function canCreate() {
|
|
return isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Check if user can edit
|
|
*/
|
|
function canEdit() {
|
|
return isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Check if user can delete
|
|
*/
|
|
function canDelete() {
|
|
return isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Check if user can sync with Talpa
|
|
*/
|
|
function canSync() {
|
|
return isAdmin();
|
|
}
|
|
|
|
/**
|
|
* Render button only if user has permission
|
|
*/
|
|
function renderButton($permission, $html) {
|
|
if ($permission) {
|
|
echo $html;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render form only if user has permission
|
|
*/
|
|
function renderForm($permission, $html) {
|
|
if ($permission) {
|
|
echo $html;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get disabled attribute for guest users
|
|
*/
|
|
function getDisabledAttr() {
|
|
return isGuest() ? 'disabled' : '';
|
|
}
|
|
|
|
/**
|
|
* Get readonly attribute for guest users
|
|
*/
|
|
function getReadonlyAttr() {
|
|
return isGuest() ? 'readonly' : '';
|
|
}
|
|
```
|
|
|
|
### 4. Aangepaste Navigatie
|
|
|
|
```php
|
|
<!-- In alle pagina's: index.php, planner.php, calendar.php, etc. -->
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container-fluid">
|
|
<a class="navbar-brand" href="index.php">
|
|
<i class="bi bi-tv"></i> Telvero Talpa Planner
|
|
</a>
|
|
<div class="navbar-nav">
|
|
<a class="nav-link" href="index.php">Dashboard</a>
|
|
<a class="nav-link" href="planner.php">Planner</a>
|
|
<a class="nav-link" href="calendar.php">Kalender</a>
|
|
<a class="nav-link" href="blocks.php">Blokken</a>
|
|
<a class="nav-link" href="infomercials.php">Infomercials</a>
|
|
<?php if (isAdmin()): ?>
|
|
<a class="nav-link" href="admin/users.php">Gebruikers</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- User Info & Logout -->
|
|
<div class="navbar-nav ms-auto">
|
|
<span class="nav-link">
|
|
<i class="bi bi-person-circle"></i>
|
|
<?= htmlspecialchars(getCurrentUser()['username']) ?>
|
|
<span class="badge bg-<?= isAdmin() ? 'danger' : 'secondary' ?>">
|
|
<?= isAdmin() ? 'Admin' : 'Guest' ?>
|
|
</span>
|
|
</span>
|
|
<a class="nav-link" href="auth/logout.php">
|
|
<i class="bi bi-box-arrow-right"></i> Uitloggen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
```
|
|
|
|
### 5. Voorbeeld: Dashboard met Role-based UI
|
|
|
|
```php
|
|
<?php
|
|
require_once __DIR__ . '/auth/auth_functions.php';
|
|
require_once __DIR__ . '/auth/middleware.php';
|
|
|
|
// Require login
|
|
requireLogin();
|
|
|
|
// Rest of existing code...
|
|
?>
|
|
|
|
<!-- In de HTML -->
|
|
<div class="container mt-4">
|
|
<?php if (isGuest()): ?>
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle"></i>
|
|
Je bent ingelogd als <strong>Guest</strong>. Je kunt alleen informatie bekijken.
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Existing content -->
|
|
|
|
<!-- Infomercial Registration Form - Only for Admins -->
|
|
<?php if (canCreate()): ?>
|
|
<div class="card p-3 shadow-sm">
|
|
<h5>1. Infomercial Registreren</h5>
|
|
<form method="POST">
|
|
<input type="text" name="title" class="form-control mb-2" placeholder="Product Naam" required>
|
|
<input type="text" name="duration" class="form-control mb-2" placeholder="Duur (HH:MM:SS)" required>
|
|
<input type="hidden" name="season_id" value="<?= $_ENV['TV_SEASON_ID'] ?>">
|
|
<button type="submit" name="add_commercial" class="btn btn-primary w-100">
|
|
Registreren bij Talpa
|
|
</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Sync buttons - Only for Admins -->
|
|
<?php if (canSync()): ?>
|
|
<form method="POST" style="display:inline;">
|
|
<input type="hidden" name="sync_id" value="<?= $tx['id'] ?>">
|
|
<button type="submit" name="sync_item" class="btn-icon btn-icon-xs btn-icon-success">
|
|
<i class="bi bi-cloud-upload"></i>
|
|
</button>
|
|
</form>
|
|
<?php else: ?>
|
|
<button type="button"
|
|
class="btn-icon btn-icon-xs btn-icon-secondary"
|
|
disabled
|
|
title="Alleen admins kunnen synchroniseren">
|
|
<i class="bi bi-cloud-upload"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
```
|
|
|
|
### 6. API Beveiliging Voorbeeld
|
|
|
|
```php
|
|
<?php
|
|
// api/create_transmission.php
|
|
require_once __DIR__ . '/../auth/auth_functions.php';
|
|
|
|
// Check authentication
|
|
if (!isLoggedIn()) {
|
|
http_response_code(401);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Niet geautoriseerd. Log eerst in.'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Check authorization (admin only for write operations)
|
|
if (!isAdmin()) {
|
|
http_response_code(403);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Geen toegang. Alleen admins kunnen uitzendingen aanmaken.'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Continue with existing logic...
|
|
```
|
|
|
|
### 7. Gebruikersbeheer Interface (admin/users.php)
|
|
|
|
```php
|
|
<?php
|
|
require_once __DIR__ . '/../auth/auth_functions.php';
|
|
require_once __DIR__ . '/../auth/middleware.php';
|
|
|
|
// Only admins can access
|
|
requireAdmin();
|
|
|
|
$db = getAuthDb();
|
|
|
|
// Handle user creation
|
|
if (isset($_POST['create_user'])) {
|
|
$username = $_POST['username'];
|
|
$email = $_POST['email'];
|
|
$password = $_POST['password'];
|
|
$role = $_POST['role'];
|
|
|
|
$passwordHash = password_hash($password, PASSWORD_BCRYPT);
|
|
|
|
$stmt = $db->prepare("
|
|
INSERT INTO users (username, email, password_hash, role)
|
|
VALUES (?, ?, ?, ?)
|
|
");
|
|
$stmt->execute([$username, $email, $passwordHash, $role]);
|
|
|
|
header("Location: users.php?success=created");
|
|
exit;
|
|
}
|
|
|
|
// Handle user update
|
|
if (isset($_POST['update_user'])) {
|
|
$userId = $_POST['user_id'];
|
|
$username = $_POST['username'];
|
|
$email = $_POST['email'];
|
|
$role = $_POST['role'];
|
|
$isActive = isset($_POST['is_active']) ? 1 : 0;
|
|
|
|
$stmt = $db->prepare("
|
|
UPDATE users
|
|
SET username = ?, email = ?, role = ?, is_active = ?
|
|
WHERE id = ?
|
|
");
|
|
$stmt->execute([$username, $email, $role, $isActive, $userId]);
|
|
|
|
header("Location: users.php?success=updated");
|
|
exit;
|
|
}
|
|
|
|
// Get all users
|
|
$users = $db->query("
|
|
SELECT id, username, email, role, is_active, last_login, created_at
|
|
FROM users
|
|
ORDER BY created_at DESC
|
|
")->fetchAll();
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Gebruikersbeheer - Telvero Talpa</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
|
</head>
|
|
<body class="bg-light">
|
|
<!-- Navigation -->
|
|
<?php include __DIR__ . '/../includes/nav.php'; ?>
|
|
|
|
<div class="container mt-4">
|
|
<h1><i class="bi bi-people"></i> Gebruikersbeheer</h1>
|
|
|
|
<?php if (isset($_GET['success'])): ?>
|
|
<div class="alert alert-success alert-dismissible fade show">
|
|
Gebruiker succesvol <?= $_GET['success'] === 'created' ? 'aangemaakt' : 'bijgewerkt' ?>!
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Create User Button -->
|
|
<button type="button" class="btn btn-primary mb-3" data-bs-toggle="modal" data-bs-target="#createUserModal">
|
|
<i class="bi bi-plus-circle"></i> Nieuwe Gebruiker
|
|
</button>
|
|
|
|
<!-- Users Table -->
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Gebruikersnaam</th>
|
|
<th>Email</th>
|
|
<th>Rol</th>
|
|
<th>Status</th>
|
|
<th>Laatste Login</th>
|
|
<th>Acties</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($users as $user): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($user['username']) ?></td>
|
|
<td><?= htmlspecialchars($user['email']) ?></td>
|
|
<td>
|
|
<span class="badge bg-<?= $user['role'] === 'admin' ? 'danger' : 'secondary' ?>">
|
|
<?= ucfirst($user['role']) ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-<?= $user['is_active'] ? 'success' : 'warning' ?>">
|
|
<?= $user['is_active'] ? 'Actief' : 'Inactief' ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<?= $user['last_login'] ? date('d-m-Y H:i', strtotime($user['last_login'])) : 'Nooit' ?>
|
|
</td>
|
|
<td>
|
|
<button type="button"
|
|
class="btn btn-sm btn-primary"
|
|
onclick="editUser(<?= htmlspecialchars(json_encode($user)) ?>)">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create User Modal -->
|
|
<div class="modal fade" id="createUserModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form method="POST">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Nieuwe Gebruiker</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Gebruikersnaam</label>
|
|
<input type="text" name="username" class="form-control" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Email</label>
|
|
<input type="email" name="email" class="form-control" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Wachtwoord</label>
|
|
<input type="password" name="password" class="form-control" required minlength="8">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Rol</label>
|
|
<select name="role" class="form-select" required>
|
|
<option value="guest">Guest</option>
|
|
<option value="admin">Admin</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
|
|
<button type="submit" name="create_user" class="btn btn-primary">Aanmaken</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
### 8. JavaScript voor Guest Mode (calendar-init.js aanpassing)
|
|
|
|
```javascript
|
|
// In assets/js/calendar-init.js
|
|
|
|
// Check if user is guest
|
|
const isGuest = <?= json_encode(isGuest()) ?>;
|
|
|
|
// Disable drag and drop for guests
|
|
if (isGuest) {
|
|
// Disable external events
|
|
document.querySelectorAll('.infomercial-item').forEach(item => {
|
|
item.style.cursor = 'not-allowed';
|
|
item.style.opacity = '0.6';
|
|
item.removeAttribute('draggable');
|
|
});
|
|
|
|
// Make calendar read-only
|
|
calendar = new FullCalendar.Calendar(calendarEl, {
|
|
// ... existing config
|
|
editable: false,
|
|
droppable: false,
|
|
eventStartEditable: false,
|
|
eventDurationEditable: false,
|
|
eventResourceEditable: false
|
|
});
|
|
|
|
// Show tooltip on hover
|
|
document.querySelectorAll('.infomercial-item').forEach(item => {
|
|
item.title = 'Alleen admins kunnen infomercials slepen';
|
|
});
|
|
}
|
|
```
|
|
|
|
## Visuele Voorbeelden
|
|
|
|
### Login Pagina
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ │
|
|
│ 📺 Telvero Talpa │
|
|
│ Planning System |