From 4db23e43179d88adc156758482449b5bdf5bd6cb Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 26 Nov 2025 07:02:50 +0000 Subject: [PATCH] Creating user roles version --- admin_classes.php | 10 +- admin_edit_teacher.php | 134 +++++++++++ admin_subjects.php | 36 +-- admin_teachers.php | 81 +++++-- admin_workloads.php | 39 ++-- dashboard.php | 81 +++++++ db/migrate.php | 27 ++- db/migrations/001_create_classes_table.sql | 6 - db/migrations/001_create_schools_table.sql | 6 + db/migrations/002_create_subjects_table.sql | 5 - db/migrations/002_create_users_table.sql | 12 + db/migrations/003_create_classes_table.sql | 7 + db/migrations/003_create_teachers_table.sql | 6 - db/migrations/004_create_subjects_table.sql | 9 + db/migrations/004_create_workloads_table.sql | 12 - db/migrations/005_create_teachers_table.sql | 10 + db/migrations/005_create_users_table.sql | 7 - db/migrations/006_add_subject_options.sql | 3 - db/migrations/006_create_workloads_table.sql | 16 ++ db/migrations/007_create_timeslots_table.sql | 14 +- db/migrations/008_create_schedules_table.sql | 31 ++- .../009_add_multischool_and_roles.sql | 23 ++ includes/auth_check_teacher.php | 8 + includes/auth_check_workload.php | 26 +++ login.php | 7 +- register.php | 86 +++++-- teacher_timetable.php | 46 +++- teacher_workload.php | 219 ++++++++++++++++++ 28 files changed, 813 insertions(+), 154 deletions(-) create mode 100644 admin_edit_teacher.php create mode 100644 dashboard.php delete mode 100644 db/migrations/001_create_classes_table.sql create mode 100644 db/migrations/001_create_schools_table.sql delete mode 100644 db/migrations/002_create_subjects_table.sql create mode 100644 db/migrations/002_create_users_table.sql create mode 100644 db/migrations/003_create_classes_table.sql delete mode 100644 db/migrations/003_create_teachers_table.sql create mode 100644 db/migrations/004_create_subjects_table.sql delete mode 100644 db/migrations/004_create_workloads_table.sql create mode 100644 db/migrations/005_create_teachers_table.sql delete mode 100644 db/migrations/005_create_users_table.sql delete mode 100644 db/migrations/006_add_subject_options.sql create mode 100644 db/migrations/006_create_workloads_table.sql create mode 100644 db/migrations/009_add_multischool_and_roles.sql create mode 100644 includes/auth_check_teacher.php create mode 100644 includes/auth_check_workload.php create mode 100644 teacher_workload.php diff --git a/admin_classes.php b/admin_classes.php index 67532af..70ce0a1 100644 --- a/admin_classes.php +++ b/admin_classes.php @@ -4,6 +4,7 @@ require_once __DIR__ . '/db/config.php'; $message = ''; $error = ''; +$school_id = $_SESSION['school_id']; // Handle POST request to add a new class if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['class_name'])) { @@ -13,8 +14,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['class_name'])) { } else { try { $pdo = db(); - $stmt = $pdo->prepare("INSERT INTO classes (name) VALUES (?)"); - if ($stmt->execute([$className])) { + $stmt = $pdo->prepare("INSERT INTO classes (name, school_id) VALUES (?, ?)"); + if ($stmt->execute([$className, $school_id])) { $message = "Class '" . htmlspecialchars($className) . "' created successfully!"; } else { $error = 'Failed to create class.'; @@ -33,7 +34,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['class_name'])) { $classes = []; try { $pdo = db(); - $classes_stmt = $pdo->query("SELECT id, name, created_at FROM classes ORDER BY created_at DESC"); + $classes_stmt = $pdo->prepare("SELECT id, name, created_at FROM classes WHERE school_id = ? ORDER BY created_at DESC"); + $classes_stmt->execute([$school_id]); $classes = $classes_stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); @@ -147,4 +149,4 @@ try { - \ No newline at end of file + diff --git a/admin_edit_teacher.php b/admin_edit_teacher.php new file mode 100644 index 0000000..58c7b5e --- /dev/null +++ b/admin_edit_teacher.php @@ -0,0 +1,134 @@ +prepare("UPDATE teachers SET can_edit_workload = ? WHERE id = ? AND school_id = ?"); + if ($stmt->execute([$can_edit_workload, $teacher_id, $school_id])) { + $message = 'Teacher updated successfully!'; + } else { + $error = 'Failed to update teacher.'; + } + } catch (PDOException $e) { + $error = 'Database error: ' . $e->getMessage(); + } +} + +// Fetch teacher data +try { + $stmt = $pdo->prepare("SELECT t.id, t.name, u.email, t.can_edit_workload FROM teachers t JOIN users u ON t.user_id = u.id WHERE t.id = ? AND t.school_id = ?"); + $stmt->execute([$teacher_id, $school_id]); + $teacher = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$teacher) { + header("Location: admin_teachers.php?error=not_found"); + exit; + } +} catch (PDOException $e) { + $error = 'Database error: ' . $e->getMessage(); +} + +?> + + + + + + Admin: Edit Teacher - Haki Schedule + + + + + + + +
+
+
+

Edit Teacher

+ + +
+ + +
+ + +
+
+
+
+ + +
+
+ + +
+
+ > + +
+ + Back to Teachers +
+
+
+ +
+
+
+ + + + + + diff --git a/admin_subjects.php b/admin_subjects.php index 217ffb9..34bfc1d 100644 --- a/admin_subjects.php +++ b/admin_subjects.php @@ -5,6 +5,7 @@ require_once __DIR__ . '/db/config.php'; $message = ''; $error = ''; $editing_subject = null; +$school_id = $_SESSION['school_id']; $pdo = db(); @@ -12,8 +13,8 @@ $pdo = db(); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_id'])) { try { $delete_id = $_POST['delete_id']; - $stmt = $pdo->prepare("DELETE FROM subjects WHERE id = ?"); - $stmt->execute([$delete_id]); + $stmt = $pdo->prepare("DELETE FROM subjects WHERE id = ? AND school_id = ?"); + $stmt->execute([$delete_id, $school_id]); $message = "Subject deleted successfully."; } catch (PDOException $e) { $error = "Error deleting subject: " . $e->getMessage(); @@ -24,7 +25,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_id'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['subject_name'])) { $subjectName = trim($_POST['subject_name']); $has_double_lesson = isset($_POST['has_double_lesson']) ? 1 : 0; - $elective_group = !empty($_POST['elective_group']) ? trim($_POST['elective_group']) : null; + $is_elective = isset($_POST['is_elective']) ? 1 : 0; $subject_id = $_POST['subject_id'] ?? null; if (empty($subjectName)) { @@ -33,13 +34,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['subject_name'])) { try { if ($subject_id) { // Update existing subject - $stmt = $pdo->prepare("UPDATE subjects SET name = ?, has_double_lesson = ?, elective_group = ? WHERE id = ?"); - $stmt->execute([$subjectName, $has_double_lesson, $elective_group, $subject_id]); + $stmt = $pdo->prepare("UPDATE subjects SET name = ?, has_double_lesson = ?, is_elective = ? WHERE id = ? AND school_id = ?"); + $stmt->execute([$subjectName, $has_double_lesson, $is_elective, $subject_id, $school_id]); $message = "Subject updated successfully!"; } else { // Insert new subject - $stmt = $pdo->prepare("INSERT INTO subjects (name, has_double_lesson, elective_group) VALUES (?, ?, ?)"); - $stmt->execute([$subjectName, $has_double_lesson, $elective_group]); + $stmt = $pdo->prepare("INSERT INTO subjects (name, has_double_lesson, is_elective, school_id) VALUES (?, ?, ?, ?)"); + $stmt->execute([$subjectName, $has_double_lesson, $is_elective, $school_id]); $message = "Subject created successfully!"; } } catch (PDOException $e) { @@ -56,8 +57,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['subject_name'])) { if (isset($_GET['edit_id'])) { try { $edit_id = $_GET['edit_id']; - $stmt = $pdo->prepare("SELECT * FROM subjects WHERE id = ?"); - $stmt->execute([$edit_id]); + $stmt = $pdo->prepare("SELECT * FROM subjects WHERE id = ? AND school_id = ?"); + $stmt->execute([$edit_id, $school_id]); $editing_subject = $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = "Error fetching subject: " . $e->getMessage(); @@ -67,7 +68,8 @@ if (isset($_GET['edit_id'])) { // Fetch all subjects to display $subjects = []; try { - $subjects_stmt = $pdo->query("SELECT * FROM subjects ORDER BY created_at DESC"); + $subjects_stmt = $pdo->prepare("SELECT * FROM subjects WHERE school_id = ? ORDER BY name ASC"); + $subjects_stmt->execute([$school_id]); $subjects = $subjects_stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); @@ -143,15 +145,15 @@ try { -
- - -
>
+
+ > + +
Cancel Edit @@ -173,7 +175,7 @@ try { Name Double Lesson - Elective Group + Is Elective Actions @@ -182,7 +184,7 @@ try { - + Edit
@@ -211,4 +213,4 @@ try { - + \ No newline at end of file diff --git a/admin_teachers.php b/admin_teachers.php index 5c129c0..af96cf0 100644 --- a/admin_teachers.php +++ b/admin_teachers.php @@ -4,11 +4,13 @@ require_once __DIR__ . '/db/config.php'; $message = ''; $error = ''; +$school_id = $_SESSION['school_id']; // Handle POST request to add a new teacher if ($_SERVER['REQUEST_METHOD'] === 'POST') { $teacherName = trim($_POST['teacher_name'] ?? ''); $teacherEmail = trim($_POST['teacher_email'] ?? ''); + $can_edit_workload = isset($_POST['can_edit_workload']) ? 1 : 0; if (empty($teacherName) || empty($teacherEmail)) { $error = 'Teacher name and email cannot be empty.'; @@ -17,18 +19,43 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } else { try { $pdo = db(); - $stmt = $pdo->prepare("INSERT INTO teachers (name, email) VALUES (?, ?)"); - if ($stmt->execute([$teacherName, $teacherEmail])) { - $message = 'Teacher "' . htmlspecialchars($teacherName) . '" created successfully!'; + $pdo->beginTransaction(); + + // Check if user with this email already exists + $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?"); + $stmt->execute([$teacherEmail]); + if ($stmt->fetch()) { + $error = 'A user with this email already exists.'; + $pdo->rollBack(); } else { - $error = 'Failed to create teacher.'; + // Generate a random password + $password = bin2hex(random_bytes(8)); + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + + // Create a user account for the teacher + $stmt = $pdo->prepare("INSERT INTO users (username, password, email, school_id, role) VALUES (?, ?, ?, ?, 'teacher')"); + $stmt->execute([$teacherEmail, $hashed_password, $teacherEmail, $school_id]); + $user_id = $pdo->lastInsertId(); + + // Create the teacher + $stmt = $pdo->prepare("INSERT INTO teachers (name, user_id, school_id, can_edit_workload) VALUES (?, ?, ?, ?)"); + if ($stmt->execute([$teacherName, $user_id, $school_id, $can_edit_workload])) { + $pdo->commit(); + $message = 'Teacher "' . htmlspecialchars($teacherName) . '" created successfully! Their password is: ' . $password; + } else { + $error = 'Failed to create teacher.'; + $pdo->rollBack(); + } } } catch (PDOException $e) { if ($e->errorInfo[1] == 1062) { // Duplicate entry - $error = 'Error: A teacher with the email "' . htmlspecialchars($teacherEmail) . '" already exists.'; + $error = 'Error: A teacher with this email already exists.'; } else { $error = 'Database error: ' . $e->getMessage(); } + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } } } } @@ -37,7 +64,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $teachers = []; try { $pdo = db(); - $stmt = $pdo->query("SELECT id, name, email, created_at FROM teachers ORDER BY created_at DESC"); + $stmt = $pdo->prepare("SELECT t.id, t.name, u.email, t.can_edit_workload, t.created_at FROM teachers t JOIN users u ON t.user_id = u.id WHERE t.school_id = ? ORDER BY t.created_at DESC"); + $stmt->execute([$school_id]); $teachers = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); @@ -115,6 +143,10 @@ try { +
+ + +
@@ -128,17 +160,30 @@ try {

No teachers have been created yet. Use the form above to add the first one.

- +
+ + + + + + + + + + + + + + + + + + + + + +
NameEmailCan Edit WorkloadCreatedActions
Edit
+
@@ -155,4 +200,4 @@ try { - + \ No newline at end of file diff --git a/admin_workloads.php b/admin_workloads.php index e7ca161..bd34ca8 100644 --- a/admin_workloads.php +++ b/admin_workloads.php @@ -6,12 +6,13 @@ $message = ''; $error = ''; $pdo = db(); $edit_workload = null; +$school_id = $_SESSION['school_id']; // Handle Delete request if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_id'])) { try { - $stmt = $pdo->prepare("DELETE FROM workloads WHERE id = ?"); - if ($stmt->execute([$_POST['delete_id']])) { + $stmt = $pdo->prepare("DELETE FROM workloads WHERE id = ? AND school_id = ?"); + if ($stmt->execute([$_POST['delete_id'], $school_id])) { $message = 'Workload deleted successfully!'; } else { $error = 'Failed to delete workload.'; @@ -35,15 +36,15 @@ elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { } else { try { if ($workload_id) { // Update - $stmt = $pdo->prepare("UPDATE workloads SET class_id = ?, subject_id = ?, teacher_id = ?, lessons_per_week = ? WHERE id = ?"); - if ($stmt->execute([$class_id, $subject_id, $teacher_id, $lessons_per_week, $workload_id])) { + $stmt = $pdo->prepare("UPDATE workloads SET class_id = ?, subject_id = ?, teacher_id = ?, lessons_per_week = ? WHERE id = ? AND school_id = ?"); + if ($stmt->execute([$class_id, $subject_id, $teacher_id, $lessons_per_week, $workload_id, $school_id])) { $message = 'Workload updated successfully!'; } else { $error = 'Failed to update workload.'; } } else { // Insert - $stmt = $pdo->prepare("INSERT INTO workloads (class_id, subject_id, teacher_id, lessons_per_week) VALUES (?, ?, ?, ?)"); - if ($stmt->execute([$class_id, $subject_id, $teacher_id, $lessons_per_week])) { + $stmt = $pdo->prepare("INSERT INTO workloads (class_id, subject_id, teacher_id, lessons_per_week, school_id) VALUES (?, ?, ?, ?, ?)"); + if ($stmt->execute([$class_id, $subject_id, $teacher_id, $lessons_per_week, $school_id])) { $message = 'Workload created successfully!'; } else { $error = 'Failed to create workload.'; @@ -62,8 +63,8 @@ elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { // Handle Edit request (fetch workload to edit) if (isset($_GET['edit_id'])) { try { - $stmt = $pdo->prepare("SELECT * FROM workloads WHERE id = ?"); - $stmt->execute([$_GET['edit_id']]); + $stmt = $pdo->prepare("SELECT * FROM workloads WHERE id = ? AND school_id = ?"); + $stmt->execute([$_GET['edit_id'], $school_id]); $edit_workload = $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); @@ -72,9 +73,17 @@ if (isset($_GET['edit_id'])) { // Fetch related data for dropdowns try { - $classes = $pdo->query("SELECT id, name FROM classes ORDER BY name")->fetchAll(PDO::FETCH_ASSOC); - $subjects = $pdo->query("SELECT id, name FROM subjects ORDER BY name")->fetchAll(PDO::FETCH_ASSOC); - $teachers = $pdo->query("SELECT id, name FROM teachers ORDER BY name")->fetchAll(PDO::FETCH_ASSOC); + $classes_stmt = $pdo->prepare("SELECT id, name FROM classes WHERE school_id = ? ORDER BY name"); + $classes_stmt->execute([$school_id]); + $classes = $classes_stmt->fetchAll(PDO::FETCH_ASSOC); + + $subjects_stmt = $pdo->prepare("SELECT id, name FROM subjects WHERE school_id = ? ORDER BY name"); + $subjects_stmt->execute([$school_id]); + $subjects = $subjects_stmt->fetchAll(PDO::FETCH_ASSOC); + + $teachers_stmt = $pdo->prepare("SELECT id, name FROM teachers WHERE school_id = ? ORDER BY name"); + $teachers_stmt->execute([$school_id]); + $teachers = $teachers_stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error while fetching data: ' . $e->getMessage(); } @@ -82,14 +91,16 @@ try { // Fetch all workloads to display $workloads = []; try { - $workloads_stmt = $pdo->query(" + $workloads_stmt = $pdo->prepare(" SELECT w.id, c.name as class_name, s.name as subject_name, t.name as teacher_name, w.lessons_per_week, w.created_at, w.class_id, w.subject_id, w.teacher_id FROM workloads w JOIN classes c ON w.class_id = c.id JOIN subjects s ON w.subject_id = s.id JOIN teachers t ON w.teacher_id = t.id + WHERE w.school_id = ? ORDER BY w.created_at DESC "); + $workloads_stmt->execute([$school_id]); $workloads = $workloads_stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $error = 'Database error while fetching workloads: ' . $e->getMessage(); @@ -126,7 +137,7 @@ try {
  • Classes
  • Subjects
  • Teachers
  • -
  • Workloads
  • +
  • Workloads
  • Timeslots
  • @@ -231,4 +242,4 @@ try { - \ No newline at end of file + diff --git a/dashboard.php b/dashboard.php new file mode 100644 index 0000000..6c2f7fb --- /dev/null +++ b/dashboard.php @@ -0,0 +1,81 @@ +prepare("SELECT can_edit_workload FROM teachers WHERE user_id = ?"); + $stmt->execute([$user_id]); + $teacher = $stmt->fetch(PDO::FETCH_ASSOC); + if ($teacher && $teacher['can_edit_workload']) { + $can_edit_workload = true; + } +} + +?> + + + + + + Dashboard - Haki Schedule + + + + + + +
    +

    Welcome, !

    +

    You are logged in as a .

    + + +

    You can manage the school's data using the links in the navigation.

    + +

    You can view your timetable using the link in the navigation.

    + +

    You can also manage your workload.

    + + +
    + + + + + \ No newline at end of file diff --git a/db/migrate.php b/db/migrate.php index 501fb9d..f29d47e 100644 --- a/db/migrate.php +++ b/db/migrate.php @@ -4,17 +4,22 @@ require_once __DIR__ . '/config.php'; try { $pdo = db(); - // Check if PDO connection is valid if (!$pdo) { throw new Exception("PDO connection is not valid. Check db/config.php"); } + // Create migrations table if it doesn't exist + $pdo->exec("CREATE TABLE IF NOT EXISTS `migrations` ( + `migration` VARCHAR(255) NOT NULL, + PRIMARY KEY (`migration`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); + + // Get all migration files $migrationsDir = __DIR__ . '/migrations'; if (!is_dir($migrationsDir)) { echo "No migrations directory found. Nothing to do.\n"; exit(0); } - $files = glob($migrationsDir . '/*.sql'); sort($files); @@ -23,10 +28,23 @@ try { exit(0); } + // Get already run migrations + $stmt = $pdo->query("SELECT `migration` FROM `migrations`"); + $runMigrations = $stmt->fetchAll(PDO::FETCH_COLUMN); + foreach ($files as $file) { - echo "Running migration: " . basename($file) . "\n"; + $migrationName = basename($file); + if (in_array($migrationName, $runMigrations)) { + continue; // Skip already run migration + } + + echo "Running migration: " . $migrationName . "\n"; $sql = file_get_contents($file); $pdo->exec($sql); + + // Record the migration + $stmt = $pdo->prepare("INSERT INTO `migrations` (`migration`) VALUES (?)"); + $stmt->execute([$migrationName]); } echo "Migrations completed successfully.\n"; @@ -37,5 +55,4 @@ try { } catch (Exception $e) { http_response_code(500); die("An error occurred: " . $e->getMessage() . "\n"); -} - +} \ No newline at end of file diff --git a/db/migrations/001_create_classes_table.sql b/db/migrations/001_create_classes_table.sql deleted file mode 100644 index b8f96b3..0000000 --- a/db/migrations/001_create_classes_table.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE IF NOT EXISTS classes ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - school_id INT UNSIGNED DEFAULT 1, -- For future multi-tenancy - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -) ENGINE=INNODB; diff --git a/db/migrations/001_create_schools_table.sql b/db/migrations/001_create_schools_table.sql new file mode 100644 index 0000000..8f46a2f --- /dev/null +++ b/db/migrations/001_create_schools_table.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `schools` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/db/migrations/002_create_subjects_table.sql b/db/migrations/002_create_subjects_table.sql deleted file mode 100644 index 14357f6..0000000 --- a/db/migrations/002_create_subjects_table.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE IF NOT EXISTS subjects ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL UNIQUE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); diff --git a/db/migrations/002_create_users_table.sql b/db/migrations/002_create_users_table.sql new file mode 100644 index 0000000..113a5bd --- /dev/null +++ b/db/migrations/002_create_users_table.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(50) NOT NULL, + `password` varchar(255) NOT NULL, + `email` varchar(100) NOT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `school_id` INT, + `role` VARCHAR(255) NOT NULL DEFAULT 'teacher', + PRIMARY KEY (`id`), + UNIQUE KEY `username` (`username`), + CONSTRAINT `fk_users_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/003_create_classes_table.sql b/db/migrations/003_create_classes_table.sql new file mode 100644 index 0000000..26979dd --- /dev/null +++ b/db/migrations/003_create_classes_table.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS `classes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `school_id` INT, + PRIMARY KEY (`id`), + CONSTRAINT `fk_classes_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/003_create_teachers_table.sql b/db/migrations/003_create_teachers_table.sql deleted file mode 100644 index 1ab5fa6..0000000 --- a/db/migrations/003_create_teachers_table.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE IF NOT EXISTS teachers ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - email VARCHAR(255) NOT NULL UNIQUE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); diff --git a/db/migrations/004_create_subjects_table.sql b/db/migrations/004_create_subjects_table.sql new file mode 100644 index 0000000..f53b6c7 --- /dev/null +++ b/db/migrations/004_create_subjects_table.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS `subjects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `is_elective` tinyint(1) DEFAULT '0', + `has_double_lesson` tinyint(1) DEFAULT '0', + `school_id` INT, + PRIMARY KEY (`id`), + CONSTRAINT `fk_subjects_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/004_create_workloads_table.sql b/db/migrations/004_create_workloads_table.sql deleted file mode 100644 index be1f1ed..0000000 --- a/db/migrations/004_create_workloads_table.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE IF NOT EXISTS workloads ( - id INT AUTO_INCREMENT PRIMARY KEY, - class_id INT NOT NULL, - subject_id INT NOT NULL, - teacher_id INT NOT NULL, - lessons_per_week INT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE, - FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE, - FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE, - UNIQUE KEY (class_id, subject_id, teacher_id) -); diff --git a/db/migrations/005_create_teachers_table.sql b/db/migrations/005_create_teachers_table.sql new file mode 100644 index 0000000..1527092 --- /dev/null +++ b/db/migrations/005_create_teachers_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `teachers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `school_id` INT, + `user_id` INT, + `can_edit_workload` BOOLEAN NOT NULL DEFAULT FALSE, + PRIMARY KEY (`id`), + CONSTRAINT `fk_teachers_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE, + CONSTRAINT `fk_teachers_user_id` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/005_create_users_table.sql b/db/migrations/005_create_users_table.sql deleted file mode 100644 index d7f4f66..0000000 --- a/db/migrations/005_create_users_table.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE IF NOT EXISTS users ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(255) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - role VARCHAR(50) NOT NULL DEFAULT 'admin', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -) ENGINE=INNODB; diff --git a/db/migrations/006_add_subject_options.sql b/db/migrations/006_add_subject_options.sql deleted file mode 100644 index 77a3cf7..0000000 --- a/db/migrations/006_add_subject_options.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE `subjects` -ADD COLUMN `has_double_lesson` BOOLEAN NOT NULL DEFAULT FALSE, -ADD COLUMN `elective_group` VARCHAR(255) NULL; diff --git a/db/migrations/006_create_workloads_table.sql b/db/migrations/006_create_workloads_table.sql new file mode 100644 index 0000000..3e3646d --- /dev/null +++ b/db/migrations/006_create_workloads_table.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS `workloads` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `teacher_id` int(11) NOT NULL, + `subject_id` int(11) NOT NULL, + `class_id` int(11) NOT NULL, + `lessons_per_week` int(11) NOT NULL, + `school_id` INT, + PRIMARY KEY (`id`), + KEY `teacher_id` (`teacher_id`), + KEY `subject_id` (`subject_id`), + KEY `class_id` (`class_id`), + CONSTRAINT `workloads_ibfk_1` FOREIGN KEY (`teacher_id`) REFERENCES `teachers` (`id`), + CONSTRAINT `workloads_ibfk_2` FOREIGN KEY (`subject_id`) REFERENCES `subjects` (`id`), + CONSTRAINT `workloads_ibfk_3` FOREIGN KEY (`class_id`) REFERENCES `classes` (`id`), + CONSTRAINT `fk_workloads_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/007_create_timeslots_table.sql b/db/migrations/007_create_timeslots_table.sql index e702712..22805a8 100644 --- a/db/migrations/007_create_timeslots_table.sql +++ b/db/migrations/007_create_timeslots_table.sql @@ -1,7 +1,7 @@ -CREATE TABLE IF NOT EXISTS timeslots ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - start_time TIME NOT NULL, - end_time TIME NOT NULL, - is_break BOOLEAN NOT NULL DEFAULT 0 -); +CREATE TABLE IF NOT EXISTS `timeslots` ( + `id` INT NOT NULL AUTO_INCREMENT, + `day_of_week` VARCHAR(20) NOT NULL, + `start_time` TIME NOT NULL, + `end_time` TIME NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/008_create_schedules_table.sql b/db/migrations/008_create_schedules_table.sql index 24a57e5..c5c3ac9 100644 --- a/db/migrations/008_create_schedules_table.sql +++ b/db/migrations/008_create_schedules_table.sql @@ -1,18 +1,15 @@ CREATE TABLE IF NOT EXISTS `schedules` ( - `id` INT AUTO_INCREMENT PRIMARY KEY, - `class_id` INT NOT NULL, - `day_of_week` INT NOT NULL, - `timeslot_id` INT NOT NULL, - `subject_id` INT, - `teacher_id` INT, - `lesson_display_name` VARCHAR(255) NOT NULL, - `teacher_display_name` VARCHAR(255) NOT NULL, - `is_double` BOOLEAN DEFAULT FALSE, - `is_elective` BOOLEAN DEFAULT FALSE, - `is_horizontal_elective` BOOLEAN DEFAULT FALSE, - UNIQUE KEY `unique_schedule_entry` (`class_id`, `day_of_week`, `timeslot_id`), - FOREIGN KEY (`class_id`) REFERENCES `classes`(`id`) ON DELETE CASCADE, - FOREIGN KEY (`timeslot_id`) REFERENCES `timeslots`(`id`) ON DELETE CASCADE, - FOREIGN KEY (`subject_id`) REFERENCES `subjects`(`id`) ON DELETE SET NULL, - FOREIGN KEY (`teacher_id`) REFERENCES `teachers`(`id`) ON DELETE SET NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file + `id` INT NOT NULL AUTO_INCREMENT, + `class_id` INT NOT NULL, + `timeslot_id` INT NOT NULL, + `teacher_id` INT, + `subject_id` INT, + `subject_name_override` VARCHAR(255), + `school_id` INT, + PRIMARY KEY (`id`), + FOREIGN KEY (`class_id`) REFERENCES `classes`(`id`), + FOREIGN KEY (`timeslot_id`) REFERENCES `timeslots`(`id`), + FOREIGN KEY (`teacher_id`) REFERENCES `teachers`(`id`), + FOREIGN KEY (`subject_id`) REFERENCES `subjects`(`id`), + CONSTRAINT `fk_schedules_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/009_add_multischool_and_roles.sql b/db/migrations/009_add_multischool_and_roles.sql new file mode 100644 index 0000000..7a66262 --- /dev/null +++ b/db/migrations/009_add_multischool_and_roles.sql @@ -0,0 +1,23 @@ +-- Add school_id and role to users table +ALTER TABLE `users` +ADD COLUMN `school_id` INT(11) NULL, +ADD COLUMN `role` VARCHAR(50) NOT NULL DEFAULT 'teacher'; + +-- Add workload_editable to users table +ALTER TABLE `users` +ADD COLUMN `workload_editable` BOOLEAN NOT NULL DEFAULT FALSE; + +-- Add school_id to other tables +ALTER TABLE `classes` ADD COLUMN `school_id` INT(11) NULL; +ALTER TABLE `subjects` ADD COLUMN `school_id` INT(11) NULL; +ALTER TABLE `teachers` ADD COLUMN `school_id` INT(11) NULL; +ALTER TABLE `workloads` ADD COLUMN `school_id` INT(11) NULL; +ALTER TABLE `schedules` ADD COLUMN `school_id` INT(11) NULL; + +-- Add foreign key constraints +ALTER TABLE `users` ADD CONSTRAINT `fk_users_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; +ALTER TABLE `classes` ADD CONSTRAINT `fk_classes_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; +ALTER TABLE `subjects` ADD CONSTRAINT `fk_subjects_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; +ALTER TABLE `teachers` ADD CONSTRAINT `fk_teachers_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; +ALTER TABLE `workloads` ADD CONSTRAINT `fk_workloads_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; +ALTER TABLE `schedules` ADD CONSTRAINT `fk_schedules_school_id` FOREIGN KEY (`school_id`) REFERENCES `schools`(`id`) ON DELETE CASCADE; diff --git a/includes/auth_check_teacher.php b/includes/auth_check_teacher.php new file mode 100644 index 0000000..3340fd7 --- /dev/null +++ b/includes/auth_check_teacher.php @@ -0,0 +1,8 @@ +prepare("SELECT can_edit_workload FROM teachers WHERE user_id = ?"); +$stmt->execute([$_SESSION['user_id']]); +$teacher = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$teacher || !$teacher['can_edit_workload']) { + header("Location: dashboard.php?error=workload_not_editable"); + exit; +} diff --git a/login.php b/login.php index 3a58dc5..ddac017 100644 --- a/login.php +++ b/login.php @@ -29,9 +29,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['user_id'] = $user['id']; $_SESSION['username'] = $user['username']; $_SESSION['role'] = $user['role']; + $_SESSION['school_id'] = $user['school_id']; // Redirect to the main page - header("Location: index.php"); + header("Location: dashboard.php"); exit; } else { $error = 'Invalid username or password.'; @@ -63,7 +64,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    -

    Admin Login

    +

    Login

    @@ -93,4 +94,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    © Haki Schedule. All Rights Reserved.

    - + \ No newline at end of file diff --git a/register.php b/register.php index 915a14a..37333d8 100644 --- a/register.php +++ b/register.php @@ -3,35 +3,68 @@ require_once __DIR__ . '/db/config.php'; $message = ''; $error = ''; +$registration_open = false; -if ($_SERVER['REQUEST_METHOD'] === 'POST') { +try { + $pdo = db(); + $stmt = $pdo->query("SELECT COUNT(*) FROM schools"); + if ($stmt->fetchColumn() == 0) { + $registration_open = true; + } +} catch (PDOException $e) { + $error = 'Database error: ' . $e->getMessage(); +} + +if ($registration_open && $_SERVER['REQUEST_METHOD'] === 'POST') { $username = $_POST['username'] ?? null; $password = $_POST['password'] ?? null; + $school_name = $_POST['school_name'] ?? null; + $email = $_POST['email'] ?? null; - if (empty($username) || empty($password)) { - $error = 'Username and password are required.'; + if (empty($username) || empty($password) || empty($school_name) || empty($email)) { + $error = 'All fields are required.'; } else { try { - $pdo = db(); - // Check if username already exists - $stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?"); - $stmt->execute([$username]); - if ($stmt->fetch()) { - $error = 'Username already taken. Please choose another one.'; - } else { - // Hash the password - $hashed_password = password_hash($password, PASSWORD_DEFAULT); + $pdo->beginTransaction(); - // Insert new user - $stmt = $pdo->prepare("INSERT INTO users (username, password, role) VALUES (?, ?, 'admin')"); - if ($stmt->execute([$username, $hashed_password])) { - $message = 'Registration successful! You can now login.'; + // Check if school name already exists + $stmt = $pdo->prepare("SELECT id FROM schools WHERE name = ?"); + $stmt->execute([$school_name]); + if ($stmt->fetch()) { + $error = 'School name already taken. Please choose another one.'; + $pdo->rollBack(); + } else { + // Insert new school + $stmt = $pdo->prepare("INSERT INTO schools (name) VALUES (?)"); + $stmt->execute([$school_name]); + $school_id = $pdo->lastInsertId(); + + // Check if username already exists + $stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?"); + $stmt->execute([$username]); + if ($stmt->fetch()) { + $error = 'Username already taken. Please choose another one.'; + $pdo->rollBack(); } else { - $error = 'Failed to register user.'; + // Hash the password + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + + // Insert new user + $stmt = $pdo->prepare("INSERT INTO users (username, password, email, school_id, role) VALUES (?, ?, ?, ?, 'admin')"); + if ($stmt->execute([$username, $hashed_password, $email, $school_id])) { + $pdo->commit(); + $message = 'Registration successful! You can now login.'; + } else { + $error = 'Failed to register user.'; + $pdo->rollBack(); + } } } } catch (PDOException $e) { $error = 'Database error: ' . $e->getMessage(); + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } } } } @@ -66,11 +99,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    - +
    - + + +
    +
    + +
    +
    + +
    @@ -83,6 +124,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    Already have an account? Login here.

    + +
    + Registration is currently closed. Only one school can be registered. +

    Go to Login

    +
    @@ -92,4 +138,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    © Haki Schedule. All Rights Reserved.

    - + \ No newline at end of file diff --git a/teacher_timetable.php b/teacher_timetable.php index 1d3847f..bd00b5d 100644 --- a/teacher_timetable.php +++ b/teacher_timetable.php @@ -1,18 +1,18 @@ query("SELECT * FROM teachers ORDER BY name")->fetchAll(PDO::FETCH_ASSOC); +function get_teachers($pdo, $school_id) { + return $pdo->prepare("SELECT * FROM teachers WHERE school_id = ? ORDER BY name")->execute([$school_id])->fetchAll(PDO::FETCH_ASSOC); } function get_timeslots($pdo) { return $pdo->query("SELECT * FROM timeslots ORDER BY start_time")->fetchAll(PDO::FETCH_ASSOC); } -function get_teacher_schedule($pdo, $teacher_id) { +function get_teacher_schedule($pdo, $teacher_id, $school_id) { $stmt = $pdo->prepare(" SELECT s.day_of_week, @@ -24,19 +24,41 @@ function get_teacher_schedule($pdo, $teacher_id) { s.is_horizontal_elective FROM schedules s JOIN classes c ON s.class_id = c.id - WHERE s.teacher_id = :teacher_id + WHERE s.teacher_id = :teacher_id AND s.school_id = :school_id "); - $stmt->execute([':teacher_id' => $teacher_id]); + $stmt->execute([':teacher_id' => $teacher_id, ':school_id' => $school_id]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } // --- Main Logic --- $pdoconn = db(); -$teachers = get_teachers($pdoconn); +$school_id = $_SESSION['school_id']; +$role = $_SESSION['role']; +$user_id = $_SESSION['user_id']; + +$teachers = []; +if ($role === 'admin') { + $stmt = $pdoconn->prepare("SELECT * FROM teachers WHERE school_id = ? ORDER BY name"); + $stmt->execute([$school_id]); + $teachers = $stmt->fetchAll(PDO::FETCH_ASSOC); +} else { // Teacher + $stmt = $pdoconn->prepare("SELECT * FROM teachers WHERE user_id = ? AND school_id = ?"); + $stmt->execute([$user_id, $school_id]); + $teachers = $stmt->fetchAll(PDO::FETCH_ASSOC); +} + $timeslots = get_timeslots($pdoconn); $days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']; -$selected_teacher_id = isset($_GET['teacher_id']) ? $_GET['teacher_id'] : null; +$selected_teacher_id = null; +if ($role === 'admin') { + $selected_teacher_id = isset($_GET['teacher_id']) ? $_GET['teacher_id'] : null; +} else { // Teacher + if (!empty($teachers)) { + $selected_teacher_id = $teachers[0]['id']; + } +} + $selected_teacher_name = ''; $teacher_schedule_raw = []; if ($selected_teacher_id) { @@ -46,7 +68,7 @@ if ($selected_teacher_id) { break; } } - $teacher_schedule_raw = get_teacher_schedule($pdoconn, $selected_teacher_id); + $teacher_schedule_raw = get_teacher_schedule($pdoconn, $selected_teacher_id, $school_id); } // Organize schedule for easy display @@ -110,6 +132,7 @@ foreach ($teacher_schedule_raw as $lesson) { + @@ -146,6 +170,7 @@ foreach ($teacher_schedule_raw as $lesson) {
    +
    @@ -153,7 +178,7 @@ foreach ($teacher_schedule_raw as $lesson) { +
    +
    + + +
    +
    + + +
    +
    +
    +
    + + +
    +
    + + + Cancel Edit + + +
    +
    + +
    +
    +
    My Existing Workloads
    +
    + + + + + + + + + + + + +
    ClassSubjectLessons/WeekActions
    + +
    + + +
    +
    +
    +
    +
    +
    + + + + + + + +