diff --git a/api/update_theme.php b/api/update_theme.php new file mode 100644 index 0000000..5c7fe8d --- /dev/null +++ b/api/update_theme.php @@ -0,0 +1,26 @@ + false, 'error' => 'Not authenticated']); + exit; +} + +$data = json_decode(file_get_contents('php://input'), true); +$theme = $data['theme'] ?? 'light'; + +// Validate theme +$allowed_themes = ['light', 'dark', 'midnight', 'forest']; +if (!in_array($theme, $allowed_themes)) { + echo json_encode(['success' => false, 'error' => 'Invalid theme']); + exit; +} + +try { + $stmt = db()->prepare("UPDATE users SET theme = ? WHERE id = ?"); + $stmt->execute([$theme, $_SESSION['user_id']]); + echo json_encode(['success' => true]); +} catch (PDOException $e) { + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/db/migrations/008_add_password_reset.sql b/db/migrations/008_add_password_reset.sql new file mode 100644 index 0000000..d4dca13 --- /dev/null +++ b/db/migrations/008_add_password_reset.sql @@ -0,0 +1,3 @@ +-- Add password reset token columns to users table +ALTER TABLE users ADD COLUMN reset_token VARCHAR(100) NULL; +ALTER TABLE users ADD COLUMN reset_token_expiry DATETIME NULL; diff --git a/db/migrations/009_add_theme_to_users.sql b/db/migrations/009_add_theme_to_users.sql new file mode 100644 index 0000000..370cb28 --- /dev/null +++ b/db/migrations/009_add_theme_to_users.sql @@ -0,0 +1,2 @@ +-- Migration: Add theme to users +ALTER TABLE users ADD COLUMN theme VARCHAR(20) DEFAULT 'light'; diff --git a/db/migrations/010_add_granular_permissions.sql b/db/migrations/010_add_granular_permissions.sql new file mode 100644 index 0000000..37d53bf --- /dev/null +++ b/db/migrations/010_add_granular_permissions.sql @@ -0,0 +1,11 @@ +-- Migration: Add granular permissions to users table +ALTER TABLE users +ADD COLUMN can_view TINYINT(1) DEFAULT 1, +ADD COLUMN can_add TINYINT(1) DEFAULT 0, +ADD COLUMN can_edit TINYINT(1) DEFAULT 0, +ADD COLUMN can_delete TINYINT(1) DEFAULT 0; + +-- Set defaults for existing roles +UPDATE users SET can_view = 1, can_add = 1, can_edit = 1, can_delete = 1 WHERE role = 'admin'; +UPDATE users SET can_view = 1, can_add = 1, can_edit = 1, can_delete = 0 WHERE role = 'clerk'; +UPDATE users SET can_view = 1, can_add = 0, can_edit = 0, can_delete = 0 WHERE role = 'staff'; diff --git a/forgot_password.php b/forgot_password.php new file mode 100644 index 0000000..9d0ce7e --- /dev/null +++ b/forgot_password.php @@ -0,0 +1,150 @@ +query("SELECT * FROM charity_settings WHERE id = 1"); +$charity = $stmt->fetch(); + +// Check if we are in reset mode (token in URL) +$token = $_GET['token'] ?? ''; +if ($token) { + $stmt = db()->prepare("SELECT * FROM users WHERE reset_token = ? AND reset_token_expiry > NOW()"); + $stmt->execute([$token]); + $user = $stmt->fetch(); + + if ($user) { + $step = 'reset'; + } else { + $error = 'رابط استعادة كلمة المرور غير صالح أو منتهي الصلاحية.'; + $step = 'request'; + } +} + +// Handle POST requests +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (isset($_POST['request_reset'])) { + $email = trim($_POST['email'] ?? ''); + if (filter_var($email, FILTER_VALIDATE_EMAIL)) { + $stmt = db()->prepare("SELECT id, full_name FROM users WHERE email = ?"); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user) { + $newToken = bin2hex(random_bytes(32)); + $expiry = date('Y-m-d H:i:s', strtotime('+1 hour')); + + $update = db()->prepare("UPDATE users SET reset_token = ?, reset_token_expiry = ? WHERE id = ?"); + $update->execute([$newToken, $expiry, $user['id']]); + + $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http'; + $host = $_SERVER['HTTP_HOST']; + $resetLink = "$protocol://$host/forgot_password.php?token=$newToken"; + + $subject = "استعادة كلمة المرور - " . ($charity['charity_name'] ?? 'الجمعية الخيرية'); + $html = " +
لقد طلبت استعادة كلمة المرور الخاصة بك. يرجى الضغط على الرابط أدناه لإعادة تعيينها:
+ +هذا الرابط صالح لمدة ساعة واحدة فقط.
+إذا لم تطلب هذا، يرجى تجاهل هذه الرسالة.
+بريد = htmlspecialchars($charity['charity_name'] ?? 'الجمعية الخيرية') ?>
+