├── favicon.ico ├── src ├── images │ ├── logo.png │ └── test.png ├── css │ └── login_signup.css └── js │ └── adminlte.min.js ├── README.md ├── user ├── src │ ├── images │ │ ├── AdminLTELogo.png │ │ └── user2-160x160.jpg │ ├── css │ │ ├── sweetalert2.css │ │ ├── login_signup.css │ │ └── toastr.min.css │ └── js │ │ └── toastr.min.js ├── auth.php ├── includes │ ├── footer.php │ ├── js.php │ ├── css.php │ └── navbar.php ├── index.php ├── user.php ├── results.php ├── active_sessions.php ├── dropdown.php ├── fill_in_the_blank.php ├── matching.php ├── topics.php ├── true_false.php ├── test.php └── question.php ├── signup ├── check_availability.php └── index.php ├── logout └── index.php ├── footer.php ├── config.php ├── index.php ├── header.php ├── database.sql ├── login └── index.php └── test.php /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqbolshoh/php-test-platform/main/favicon.ico -------------------------------------------------------------------------------- /src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqbolshoh/php-test-platform/main/src/images/logo.png -------------------------------------------------------------------------------- /src/images/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqbolshoh/php-test-platform/main/src/images/test.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ## This project is currently under development... 4 | 🚧 Work in progress! 🚧 5 | 6 | --- 7 | -------------------------------------------------------------------------------- /user/src/images/AdminLTELogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqbolshoh/php-test-platform/main/user/src/images/AdminLTELogo.png -------------------------------------------------------------------------------- /user/src/images/user2-160x160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iqbolshoh/php-test-platform/main/user/src/images/user2-160x160.jpg -------------------------------------------------------------------------------- /user/auth.php: -------------------------------------------------------------------------------- 1 | checkUserSession('user'); 7 | -------------------------------------------------------------------------------- /user/includes/footer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /user/includes/js.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /user/includes/css.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /signup/check_availability.php: -------------------------------------------------------------------------------- 1 | false]; 8 | 9 | if (isset($_POST['email'])) { 10 | $email = $_POST['email']; 11 | $email_check = $query->select('users', 'email', 'email = ?', [$email], 's'); 12 | if ($email_check) { 13 | $response['exists'] = true; 14 | } 15 | } 16 | 17 | if (isset($_POST['username'])) { 18 | $username = $_POST['username']; 19 | $username_check = $query->select('users', 'username', 'username = ?', [$username], 's'); 20 | if ($username_check) { 21 | $response['exists'] = true; 22 | } 23 | } 24 | 25 | echo json_encode($response); 26 | exit; 27 | -------------------------------------------------------------------------------- /user/src/css/sweetalert2.css: -------------------------------------------------------------------------------- 1 | .swal2-popup { 2 | font-family: 'Arial', sans-serif; 3 | } 4 | 5 | .swal2-title { 6 | color: #2c3e50; 7 | font-size: 1.5rem; 8 | } 9 | 10 | .swal2-html-container { 11 | color: #34495e; 12 | font-size: 1rem; 13 | } 14 | 15 | .swal2-confirm { 16 | background-color: #28a745; 17 | color: #fff; 18 | border: none; 19 | border-radius: 4px; 20 | padding: 0.5em 1em; 21 | margin-left: 10px; 22 | } 23 | 24 | .swal2-cancel { 25 | background-color: #dc3545; 26 | color: #fff; 27 | border: none; 28 | border-radius: 4px; 29 | padding: 0.5em 1em; 30 | margin-right: 10px; 31 | } 32 | 33 | .swal2-confirm:hover { 34 | background-color: #218838; 35 | } 36 | 37 | .swal2-cancel:hover { 38 | background-color: #c82333; 39 | } -------------------------------------------------------------------------------- /logout/index.php: -------------------------------------------------------------------------------- 1 | delete('active_sessions', 'session_token = ?', [session_id()], 's'); 8 | 9 | session_unset(); 10 | $_SESSION = []; 11 | session_destroy(); 12 | session_write_close(); 13 | 14 | $cookies = ['username', 'session_token']; 15 | foreach ($cookies as $cookie) { 16 | if (isset($_COOKIE[$cookie])) { 17 | setcookie($cookie, '', [ 18 | 'expires' => time() - 3600, 19 | 'path' => '/', 20 | 'secure' => true, 21 | 'httponly' => true, 22 | 'samesite' => 'Strict' 23 | ]); 24 | } 25 | } 26 | 27 | header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); 28 | header("Pragma: no-cache"); 29 | header("Expires: Sat, 01 Jan 2000 00:00:00 GMT"); 30 | 31 | header("Location: ../login/"); 32 | exit; 33 | -------------------------------------------------------------------------------- /src/css/login_signup.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | font-family: 'Arial', sans-serif; 7 | margin: 0px; 8 | } 9 | 10 | .form-container { 11 | background-color: #fff; 12 | border-radius: 8px; 13 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 14 | padding: 30px; 15 | width: calc(100% - 40px); 16 | max-width: 450px; 17 | box-sizing: border-box; 18 | } 19 | 20 | h1 { 21 | margin: 0 0 20px; 22 | font-size: 24px; 23 | color: #333; 24 | } 25 | 26 | .form-group { 27 | margin-bottom: 15px; 28 | position: relative; 29 | } 30 | 31 | .form-group label { 32 | display: block; 33 | margin-bottom: 5px; 34 | font-weight: bold; 35 | color: #555; 36 | } 37 | 38 | .form-group input { 39 | width: 100%; 40 | padding: 10px; 41 | border: 1px solid #ddd; 42 | border-radius: 4px; 43 | box-sizing: border-box; 44 | font-size: 16px; 45 | } 46 | 47 | .form-group .password-container { 48 | display: flex; 49 | align-items: center; 50 | } 51 | 52 | .form-group .password-container input { 53 | flex: 1; 54 | padding-right: 40px; 55 | } 56 | 57 | .form-group .password-toggle { 58 | position: absolute; 59 | right: 10px; 60 | font-size: 18px; 61 | cursor: pointer; 62 | border: none; 63 | background: transparent; 64 | } 65 | 66 | .form-group #submit { 67 | width: 100%; 68 | background-color: #007bff; 69 | color: #fff; 70 | border: none; 71 | padding: 12px 15px; 72 | border-radius: 4px; 73 | font-size: 18px; 74 | cursor: pointer; 75 | transition: background-color 0.3s; 76 | } 77 | 78 | .form-group #submit:hover { 79 | background-color: #0056b3; 80 | } 81 | 82 | .text-center { 83 | text-align: center; 84 | margin-top: 15px; 85 | } 86 | 87 | .text-center a { 88 | color: #007bff; 89 | text-decoration: none; 90 | } 91 | 92 | .text-center a:hover { 93 | text-decoration: underline; 94 | } 95 | 96 | #email-message, 97 | #username-message { 98 | color: red; 99 | font-size: 14px; 100 | margin-top: 5px; 101 | } -------------------------------------------------------------------------------- /user/src/css/login_signup.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | font-family: 'Arial', sans-serif; 7 | margin: 0px; 8 | } 9 | 10 | .form-container { 11 | background-color: #fff; 12 | border-radius: 8px; 13 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 14 | padding: 30px; 15 | width: calc(100% - 40px); 16 | max-width: 450px; 17 | box-sizing: border-box; 18 | } 19 | 20 | h1 { 21 | margin: 0 0 20px; 22 | font-size: 24px; 23 | color: #333; 24 | } 25 | 26 | .form-group { 27 | margin-bottom: 15px; 28 | position: relative; 29 | } 30 | 31 | .form-group label { 32 | display: block; 33 | margin-bottom: 5px; 34 | font-weight: bold; 35 | color: #555; 36 | } 37 | 38 | .form-group input { 39 | width: 100%; 40 | padding: 10px; 41 | border: 1px solid #ddd; 42 | border-radius: 4px; 43 | box-sizing: border-box; 44 | font-size: 16px; 45 | } 46 | 47 | .form-group .password-container { 48 | display: flex; 49 | align-items: center; 50 | } 51 | 52 | .form-group .password-container input { 53 | flex: 1; 54 | padding-right: 40px; 55 | } 56 | 57 | .form-group .password-toggle { 58 | position: absolute; 59 | right: 10px; 60 | font-size: 18px; 61 | cursor: pointer; 62 | border: none; 63 | background: transparent; 64 | } 65 | 66 | .form-group #submit { 67 | width: 100%; 68 | background-color: #007bff; 69 | color: #fff; 70 | border: none; 71 | padding: 12px 15px; 72 | border-radius: 4px; 73 | font-size: 18px; 74 | cursor: pointer; 75 | transition: background-color 0.3s; 76 | } 77 | 78 | .form-group #submit:hover { 79 | background-color: #0056b3; 80 | } 81 | 82 | .text-center { 83 | text-align: center; 84 | margin-top: 15px; 85 | } 86 | 87 | .text-center a { 88 | color: #007bff; 89 | text-decoration: none; 90 | } 91 | 92 | .text-center a:hover { 93 | text-decoration: underline; 94 | } 95 | 96 | #email-message, 97 | #username-message { 98 | color: red; 99 | font-size: 14px; 100 | margin-top: 5px; 101 | } -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 | 34 | 35 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | '/user/' 12 | ]; 13 | 14 | class Database 15 | { 16 | private $conn; 17 | 18 | public function __construct() 19 | { 20 | $this->conn = new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME); 21 | 22 | if ($this->conn->connect_error) { 23 | die("Database connection error: " . $this->conn->connect_error); 24 | } 25 | } 26 | 27 | public function __destruct() 28 | { 29 | if ($this->conn) { 30 | $this->conn->close(); 31 | } 32 | } 33 | 34 | public function executeQuery($sql, $params = [], $types = "") 35 | { 36 | $result = $this->conn->prepare($sql); 37 | 38 | if (!$result) { 39 | return "SQL error: " . $this->conn->error; 40 | } 41 | 42 | if ($params) { 43 | $result->bind_param($types, ...$params); 44 | } 45 | 46 | if (!$result->execute()) { 47 | return "Execution error: " . $result->error; 48 | } 49 | 50 | return $result; 51 | } 52 | 53 | function validate($value) 54 | { 55 | return htmlspecialchars(trim(stripslashes($value)), ENT_QUOTES, 'UTF-8'); 56 | } 57 | 58 | public function select($table, $columns = "*", $condition = "", $params = [], $types = "") 59 | { 60 | $sql = "SELECT $columns FROM $table" . ($condition ? " WHERE $condition" : ""); 61 | $result = $this->executeQuery($sql, $params, $types); 62 | 63 | if (is_string($result)) { 64 | return $result; 65 | } 66 | 67 | return $result->get_result()->fetch_all(MYSQLI_ASSOC); 68 | } 69 | 70 | public function insert($table, $data) 71 | { 72 | $keys = implode(', ', array_keys($data)); 73 | $placeholders = implode(', ', array_fill(0, count($data), '?')); 74 | $sql = "INSERT INTO $table ($keys) VALUES ($placeholders)"; 75 | $types = str_repeat('s', count($data)); 76 | 77 | $result = $this->executeQuery($sql, array_values($data), $types); 78 | if (is_string($result)) { 79 | return $result; 80 | } 81 | 82 | return $this->conn->insert_id; 83 | } 84 | 85 | public function update($table, $data, $condition = "", $params = [], $types = "") 86 | { 87 | $set = implode(", ", array_map(function ($k) { 88 | return "$k = ?"; 89 | }, array_keys($data))); 90 | $sql = "UPDATE $table SET $set" . ($condition ? " WHERE $condition" : ""); 91 | $types = str_repeat('s', count($data)) . $types; 92 | 93 | $result = $this->executeQuery($sql, array_merge(array_values($data), $params), $types); 94 | if (is_string($result)) { 95 | return $result; 96 | } 97 | 98 | return $this->conn->affected_rows; 99 | } 100 | 101 | public function delete($table, $condition = "", $params = [], $types = "") 102 | { 103 | $sql = "DELETE FROM $table" . ($condition ? " WHERE $condition" : ""); 104 | 105 | $result = $this->executeQuery($sql, $params, $types); 106 | if (is_string($result)) { 107 | return $result; 108 | } 109 | 110 | return $this->conn->affected_rows; 111 | } 112 | 113 | public function hashPassword($password) 114 | { 115 | return hash_hmac('sha256', $password, 'iqbolshoh'); 116 | } 117 | 118 | public function checkUserSession($role) 119 | { 120 | if (($_SESSION['loggedin'] ?? false) !== true || ($_SESSION['role'] ?? '') !== $role) { 121 | header("Location: " . SITE_PATH . "/login/"); 122 | exit; 123 | } 124 | 125 | if (!$this->select('active_sessions', '*', 'session_token = ?', [session_id()], 's')) { 126 | header("Location: " . SITE_PATH . "/logout/"); 127 | exit; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /user/index.php: -------------------------------------------------------------------------------- 1 | 2 | select('users', '*')[0]; 4 | $topics = $query->select('lessons', '*')[0]; 5 | $results = $query->select('results', '*'); 6 | 7 | $tests = count($query->select('test', '*')); 8 | $tru_falses = count($query->select('tru_false', '*')); 9 | $dropdowns = count($query->select('dropdown', '*')); 10 | $fill_in_the_blanks = count($query->select('fill_in_the_blank', '*')); 11 | $matchings = count($query->select('matching', '*')); 12 | $answers = count($query->select('answers', '*')); 13 | 14 | $question = $tests + $tru_falses + $dropdowns + $fill_in_the_blanks + $matchings + $answers; 15 | 16 | ?> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | AdminLTE 3 | Dashboard 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 | "Home", "url" => "./"], 39 | ["title" => "Dashboard", "url" => "#"], 40 | ); 41 | pagePath('Dashboard', $arr); 42 | ?> 43 | 44 |
45 |
46 | 47 |
48 |
49 | 50 |
51 |
52 |

53 | 54 |

55 |
56 |
57 | 58 |
59 | Edit User 60 |
61 |
62 | 63 |
64 | 65 |
66 |
67 |

68 | 69 |

Available in the system

70 |
71 |
72 | 73 |
74 | Add Topics 75 |
76 |
77 | 78 |
79 |
80 |
81 |

82 | 83 |

Total number of questions.

84 |
85 |
86 | 87 |
88 | See questions 89 |
90 |
91 | 92 |
93 | 94 |
95 |
96 |

97 | 98 |

People passed the test.

99 |
100 |
101 | 102 |
103 | View result 104 |
105 | 106 |
107 |
108 | 109 |
110 | 111 |
112 |
113 | 114 | 115 |
116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test Platform 8 | 9 | 10 | 11 | 125 | 126 | 127 | 128 |
129 | 130 |
131 |

Welcome to Test Platform

132 |

Create your own tests, improve your skills, and share them with others.

133 | 134 | 135 | 136 | 137 |
138 | 139 |
140 | 141 |
142 |

Test Platform provides a comprehensive environment where you can create 143 | personalized tests on various topics. Whether you're preparing for exams or enhancing your skills, you 144 | can design quizzes, share them with others, and track progress. Join us to create, share, and test your 145 | knowledge while helping others do the same!

146 |
147 | 148 |
149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 161 | 162 | 163 |
164 | 183 |
184 | 185 | -------------------------------------------------------------------------------- /user/user.php: -------------------------------------------------------------------------------- 1 | select('users', '*', "id = $user_id"); 15 | 16 | $user = $result[0]; 17 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 18 | $first_name = $_POST['first_name']; 19 | $last_name = $_POST['last_name']; 20 | $email = $_POST['email']; 21 | $username = $_POST['username']; 22 | $password = $_POST['password']; 23 | 24 | $_SESSION['first_name'] = $first_name; 25 | $_SESSION['last_name'] = $last_name; 26 | 27 | if (!empty($password)) { 28 | $password = $query->hashPassword($password); 29 | $query->update('users', [ 30 | 'first_name' => $first_name, 31 | 'last_name' => $last_name, 32 | 'email' => $email, 33 | 'username' => $username, 34 | 'password' => $password 35 | ], "id = $user_id"); 36 | } else { 37 | $query->update('users', [ 38 | 'first_name' => $first_name, 39 | 'last_name' => $last_name, 40 | 'email' => $email, 41 | 'username' => $username 42 | ], "id = $user_id"); 43 | } 44 | 45 | header("Location: " . $_SERVER['HTTP_REFERER']); 46 | exit; 47 | } 48 | ?> 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | AdminLTE 3 | User settings 60 | 61 | 62 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | "Home", "url" => "./"], 109 | ["title" => "User settings", "url" => "#"], 110 | ); 111 | pagePath('User settings', $arr); 112 | ?> 113 | 114 |
115 |
116 | 117 |
118 |
119 |
120 |

User Settings

121 |
122 |
123 | 124 | 125 |
126 |
127 | 128 | 129 |
130 |
131 | 132 | 133 |
134 |
135 | 136 | 137 |
138 |
139 | 140 | 141 | Leave blank to keep the current password. 142 |
143 | 144 |
145 |
146 |
147 |
148 | 149 |
150 | 151 |
152 |
153 | 154 | 155 |
156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /user/results.php: -------------------------------------------------------------------------------- 1 | 2 | 0) { 7 | $results = $query->select('results', '*', "lesson_id = $lesson_id"); 8 | } else { 9 | $lessons = $query->select('lessons', '*', '1'); 10 | } 11 | ?> 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Results 22 | 23 | 24 | 25 | 26 |
27 | 28 |
29 | 30 | "Home", "url" => "./"], 33 | ["title" => "Results", "url" => "#"], 34 | ); 35 | pagePath('Results', $arr); 36 | ?> 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |

Lessons

45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | $lesson): ?> 58 | 59 | 60 | 63 | 66 | 67 | 68 | 69 |
Lesson NameActions
61 | 62 | 64 | View Results 65 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | $result): ?> 83 | 84 | 85 | 86 | 87 | 88 | 98 | 99 | 100 | 101 | 102 |
Participant NameTotal QuestionsAnswered QuestionsPercentage
89 | 97 |
103 |
104 | Back to Lessons 105 | 106 |

No data available.

107 | 108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | 116 | 117 |
118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /user/active_sessions.php: -------------------------------------------------------------------------------- 1 | checkUserSession('user'); 7 | 8 | $sessions = $query->select('active_sessions', '*', 'user_id = ?', [$_SESSION['user_id']], 'i'); 9 | 10 | if (isset($_GET['token'])) { 11 | $query->delete('active_sessions', 'user_id = ? AND session_token = ?', [$_SESSION['user_id'], $_GET['token']], 'is'); 12 | header('Location: ' . $_SERVER['PHP_SELF']); 13 | exit; 14 | } 15 | 16 | if (isset($_POST['update_session'])) { 17 | $device_name = $_POST['device_name']; 18 | 19 | $query->update( 20 | 'active_sessions', 21 | ['device_name' => $device_name], 22 | 'session_token = ? AND user_id = ?', 23 | [session_id(), $_SESSION['user_id']], 24 | 'si' 25 | ); 26 | 27 | header('Location: ' . $_SERVER['PHP_SELF']); 28 | exit; 29 | } 30 | ?> 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 |
48 | 49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | $session): ?> 64 | 65 | 66 | 67 | 68 | 69 | 81 | 82 | 83 | 84 |
Device Name IP Address Last Activity Action
70 | 71 | 75 | 76 | 80 |
85 | 86 | 87 | 112 | 113 |
114 |
115 | 116 |
117 | 118 |
119 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /database.sql: -------------------------------------------------------------------------------- 1 | DROP DATABASE IF EXISTS test_platform; 2 | 3 | CREATE DATABASE IF NOT EXISTS test_platform; 4 | 5 | USE test_platform; 6 | 7 | CREATE TABLE IF NOT EXISTS users ( 8 | id INT PRIMARY KEY AUTO_INCREMENT, 9 | first_name VARCHAR(30) NOT NULL, 10 | last_name VARCHAR(30) NOT NULL, 11 | email VARCHAR(100) NOT NULL UNIQUE, 12 | username VARCHAR(30) NOT NULL UNIQUE, 13 | password VARCHAR(255) NOT NULL, 14 | profile_picture VARCHAR(255) DEFAULT 'default.png', 15 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 16 | ); 17 | 18 | CREATE TABLE IF NOT EXISTS subjects ( 19 | id INT PRIMARY KEY AUTO_INCREMENT, 20 | user_id INT, 21 | title VARCHAR(100) NOT NULL, 22 | description VARCHAR(255) NOT NULL, 23 | url VARCHAR(255) NOT NULL, 24 | FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE 25 | ); 26 | 27 | CREATE TABLE IF NOT EXISTS test ( 28 | id INT PRIMARY KEY AUTO_INCREMENT, 29 | subject_id INT, 30 | question TEXT NOT NULL, 31 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 32 | ); 33 | 34 | CREATE TABLE IF NOT EXISTS test_options ( 35 | id INT PRIMARY KEY AUTO_INCREMENT, 36 | test_id INT NOT NULL, 37 | option_text VARCHAR(255) NOT NULL, 38 | is_correct BOOLEAN DEFAULT FALSE, 39 | FOREIGN KEY (test_id) REFERENCES test(id) ON DELETE CASCADE 40 | ); 41 | 42 | CREATE TABLE IF NOT EXISTS tru_false ( 43 | id INT PRIMARY KEY AUTO_INCREMENT, 44 | subject_id INT, 45 | statement TEXT NOT NULL, 46 | is_true BOOLEAN NOT NULL, 47 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 48 | ); 49 | 50 | CREATE TABLE IF NOT EXISTS dropdown ( 51 | id INT PRIMARY KEY AUTO_INCREMENT, 52 | subject_id INT, 53 | question TEXT NOT NULL, 54 | correct_answer VARCHAR(255) NOT NULL, 55 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 56 | ); 57 | 58 | CREATE TABLE IF NOT EXISTS fill_in_the_blank ( 59 | id INT PRIMARY KEY AUTO_INCREMENT, 60 | subject_id INT, 61 | sentence TEXT NOT NULL, 62 | correct_answer VARCHAR(255) NOT NULL, 63 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 64 | ); 65 | 66 | CREATE TABLE IF NOT EXISTS matching ( 67 | id INT PRIMARY KEY AUTO_INCREMENT, 68 | subject_id INT, 69 | left_side TEXT NOT NULL, 70 | right_side TEXT NOT NULL, 71 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 72 | ); 73 | 74 | CREATE TABLE IF NOT EXISTS results ( 75 | id INT PRIMARY KEY AUTO_INCREMENT, 76 | subject_id INT, 77 | participant_name VARCHAR(255) NOT NULL, 78 | total_questions INT NOT NULL, 79 | answered_questions INT NOT NULL, 80 | FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE 81 | ); 82 | 83 | -- Login: iqbolshoh 84 | -- Password: Iqbolshoh$7 85 | INSERT INTO 86 | users ( 87 | first_name, 88 | last_name, 89 | email, 90 | username, 91 | password 92 | ) 93 | VALUES 94 | ( 95 | 'Iqbolshoh', 96 | 'Ilhomjonov', 97 | 'iilhomjonov777@gmail.com', 98 | 'iqbolshoh', 99 | '1f254bb82e64bde20137a2922989f6f57529c98e34d146b523a47898702b7231' 100 | ); 101 | 102 | INSERT INTO 103 | subjects (user_id, title, description, url) 104 | VALUES 105 | ( 106 | 1, 107 | 'Mathematics', 108 | 'Learn advanced mathematics including calculus, algebra, and geometry.', 109 | 'mathematics' 110 | ), 111 | ( 112 | 1, 113 | 'Physics', 114 | 'Explore the fundamentals of physics, including mechanics, thermodynamics, and optics.', 115 | 'physics' 116 | ), 117 | ( 118 | 1, 119 | 'Computer Science', 120 | 'Study programming, data structures, algorithms, and web development.', 121 | 'computer-science' 122 | ), 123 | ( 124 | 1, 125 | 'Chemistry', 126 | 'Dive into organic, inorganic, and physical chemistry with hands-on experiments.', 127 | 'chemistry' 128 | ), 129 | ( 130 | 1, 131 | 'History', 132 | 'Learn about world history from ancient civilizations to modern times.', 133 | 'history' 134 | ); 135 | 136 | -- Inserting test questions into the 'test' table 137 | INSERT INTO 138 | test (subject_id, question) 139 | VALUES 140 | (1, 'What is the derivative of x^2?'), 141 | (2, 'What is Newtons Second Law of Motion?'), 142 | ( 143 | 3, 144 | 'What is the time complexity of a binary search?' 145 | ), 146 | (4, 'What is the chemical formula of water?'), 147 | ( 148 | 5, 149 | 'Who was the first president of the United States?' 150 | ); 151 | 152 | INSERT INTO 153 | test_options (test_id, option_text, is_correct) 154 | VALUES 155 | (1, '2x', TRUE), 156 | (1, 'x^2', FALSE), 157 | (1, 'x', FALSE), 158 | (1, '1/x', FALSE), 159 | (2, 'F = ma', TRUE), 160 | (2, 'F = m/v', FALSE), 161 | (2, 'F = mv', FALSE), 162 | (2, 'F = m^2', FALSE), 163 | (3, 'O(log n)', TRUE), 164 | (3, 'O(n)', FALSE), 165 | (3, 'O(n^2)', FALSE), 166 | (3, 'O(1)', FALSE), 167 | (4, 'H2O', TRUE), 168 | (4, 'CO2', FALSE), 169 | (4, 'O2', FALSE), 170 | (4, 'CH4', FALSE), 171 | (5, 'George Washington', TRUE), 172 | (5, 'Abraham Lincoln', FALSE), 173 | (5, 'Thomas Jefferson', FALSE), 174 | (5, 'Franklin Pierce', FALSE); 175 | 176 | INSERT INTO 177 | tru_false (subject_id, statement, is_true) 178 | VALUES 179 | ( 180 | 1, 181 | 'The sum of angles in a triangle is always 180 degrees.', 182 | TRUE 183 | ), 184 | ( 185 | 2, 186 | 'Einstein developed the theory of relativity after Newton.', 187 | FALSE 188 | ), 189 | ( 190 | 3, 191 | 'The binary search algorithm works on unsorted arrays.', 192 | FALSE 193 | ), 194 | (4, 'Water expands when it freezes.', TRUE), 195 | ( 196 | 5, 197 | 'The Roman Empire was founded in 27 BC.', 198 | TRUE 199 | ); 200 | 201 | -- Inserting dropdown questions into the 'dropdown' table 202 | INSERT INTO 203 | dropdown (subject_id, question, correct_answer) 204 | VALUES 205 | (1, 'What is the integral of 1/x?', 'ln(x)'), 206 | (2, 'What is the unit of force?', 'Newton'), 207 | ( 208 | 3, 209 | 'What is the main feature of object-oriented programming?', 210 | 'Encapsulation' 211 | ), 212 | ( 213 | 4, 214 | 'What is the symbol for gold in the periodic table?', 215 | 'Au' 216 | ), 217 | (5, 'When did World War II end?', '1945'); 218 | 219 | -- Inserting fill-in-the-blank questions into the 'fill_in_the_blank' table 220 | INSERT INTO 221 | fill_in_the_blank (subject_id, sentence, correct_answer) 222 | VALUES 223 | ( 224 | 1, 225 | 'The area of a circle is calculated using the formula ___.', 226 | 'πr^2' 227 | ), 228 | ( 229 | 2, 230 | 'Einstein\'s famous equation is E = ___.', 231 | 'mc^2' 232 | ), 233 | ( 234 | 3, 235 | 'The best programming language for web development is ___.', 236 | 'JavaScript' 237 | ), 238 | ( 239 | 4, 240 | 'The chemical element with the atomic number 6 is ___.', 241 | 'Carbon' 242 | ), 243 | ( 244 | 5, 245 | 'The Declaration of Independence was signed in the year ___.', 246 | '1776' 247 | ); 248 | 249 | -- Inserting matching questions into the 'matching' table 250 | INSERT INTO 251 | matching (subject_id, left_side, right_side) 252 | VALUES 253 | (1, 'Pythagoras Theorem', 'a^2 + b^2 = c^2'), 254 | ( 255 | 2, 256 | 'Law of Inertia', 257 | 'An object will remain at rest or in motion unless acted upon by an external force' 258 | ), 259 | ( 260 | 3, 261 | 'Sorting Algorithm', 262 | 'O(n log n) time complexity' 263 | ), 264 | (4, 'Element H', 'Hydrogen'), 265 | (5, 'Ancient Egypt', 'Pyramids'); -------------------------------------------------------------------------------- /user/dropdown.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $dropdowns = []; 13 | if ($lessonid) { 14 | $dropdowns = $query->select('dropdown', '*', "lesson_id = '$lessonid'"); 15 | } 16 | 17 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 18 | if (isset($_POST['add_dropdown'])) { 19 | $question = $_POST['question']; 20 | $correct_answer = $_POST['correct_answer']; 21 | $lesson_id = intval($_POST['lesson_id']); 22 | 23 | $query->insert('dropdown', [ 24 | 'lesson_id' => $lesson_id, 25 | 'question' => $question, 26 | 'correct_answer' => $correct_answer 27 | ]); 28 | } 29 | 30 | if (isset($_POST['update_dropdown'])) { 31 | foreach ($_POST['id'] as $id) { 32 | $id = intval($id); 33 | $question = $_POST['question'][$id]; 34 | $correct_answer = $_POST['correct_answer'][$id]; 35 | 36 | $query->update('dropdown', [ 37 | 'question' => $question, 38 | 'correct_answer' => $correct_answer 39 | ], "id = '$id'"); 40 | } 41 | } 42 | 43 | header("Location: " . $_SERVER['PHP_SELF'] . "?lessonid=$lessonid"); 44 | exit; 45 | } 46 | 47 | if (isset($_GET['delete_id'])) { 48 | $delete_id = intval($_GET['delete_id']); 49 | $query->delete('dropdown', "id = '$delete_id'"); 50 | header("Location: " . $_SERVER['PHP_SELF'] . "?lessonid=$lessonid"); 51 | exit; 52 | } 53 | ?> 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Dropdown 63 | 64 | 94 | 95 | 96 | 97 |
98 | 99 |
100 | "Home", "url" => "./"], ["title" => "Dropdown", "url" => "#"]]; 102 | pagePath('Dropdown', $arr); 103 | ?> 104 | 105 |
106 |
107 |
108 | 109 |
110 | 125 | 126 |
127 | 145 |
146 |
147 | 148 |
149 | select('lessons', '*'); ?> 150 | 151 |
152 | 153 | 161 |
162 | 163 |
164 | 165 |
166 |
167 | 168 | 169 | 170 |
171 |
172 |
173 |
174 | 175 | 176 |
177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /user/src/css/toastr.min.css: -------------------------------------------------------------------------------- 1 | .toast-title { 2 | font-weight: 700 3 | } 4 | 5 | .toast-message { 6 | -ms-word-wrap: break-word; 7 | word-wrap: break-word 8 | } 9 | 10 | .toast-message a, 11 | .toast-message label { 12 | color: #FFF 13 | } 14 | 15 | .toast-message a:hover { 16 | color: #CCC; 17 | text-decoration: none 18 | } 19 | 20 | .toast-close-button { 21 | position: relative; 22 | right: -.3em; 23 | top: -.3em; 24 | float: right; 25 | font-size: 20px; 26 | font-weight: 700; 27 | color: #FFF; 28 | -webkit-text-shadow: 0 1px 0 #fff; 29 | text-shadow: 0 1px 0 #fff; 30 | opacity: .8; 31 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); 32 | filter: alpha(opacity=80); 33 | line-height: 1 34 | } 35 | 36 | .toast-close-button:focus, 37 | .toast-close-button:hover { 38 | color: #000; 39 | text-decoration: none; 40 | cursor: pointer; 41 | opacity: .4; 42 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); 43 | filter: alpha(opacity=40) 44 | } 45 | 46 | .rtl .toast-close-button { 47 | left: -.3em; 48 | float: left; 49 | right: .3em 50 | } 51 | 52 | button.toast-close-button { 53 | padding: 0; 54 | cursor: pointer; 55 | background: 0 0; 56 | border: 0; 57 | -webkit-appearance: none 58 | } 59 | 60 | .toast-top-center { 61 | top: 0; 62 | right: 0; 63 | width: 100% 64 | } 65 | 66 | .toast-bottom-center { 67 | bottom: 0; 68 | right: 0; 69 | width: 100% 70 | } 71 | 72 | .toast-top-full-width { 73 | top: 0; 74 | right: 0; 75 | width: 100% 76 | } 77 | 78 | .toast-bottom-full-width { 79 | bottom: 0; 80 | right: 0; 81 | width: 100% 82 | } 83 | 84 | .toast-top-left { 85 | top: 12px; 86 | left: 12px 87 | } 88 | 89 | .toast-top-right { 90 | top: 12px; 91 | right: 12px 92 | } 93 | 94 | .toast-bottom-right { 95 | right: 12px; 96 | bottom: 12px 97 | } 98 | 99 | .toast-bottom-left { 100 | bottom: 12px; 101 | left: 12px 102 | } 103 | 104 | #toast-container { 105 | position: fixed; 106 | z-index: 999999; 107 | pointer-events: none 108 | } 109 | 110 | #toast-container * { 111 | -moz-box-sizing: border-box; 112 | -webkit-box-sizing: border-box; 113 | box-sizing: border-box 114 | } 115 | 116 | #toast-container>div { 117 | position: relative; 118 | pointer-events: auto; 119 | overflow: hidden; 120 | margin: 0 0 6px; 121 | padding: 15px 15px 15px 50px; 122 | width: 300px; 123 | -moz-border-radius: 3px; 124 | -webkit-border-radius: 3px; 125 | border-radius: 3px; 126 | background-position: 15px center; 127 | background-repeat: no-repeat; 128 | -moz-box-shadow: 0 0 12px #999; 129 | -webkit-box-shadow: 0 0 12px #999; 130 | box-shadow: 0 0 12px #999; 131 | color: #FFF; 132 | opacity: .8; 133 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); 134 | filter: alpha(opacity=80) 135 | } 136 | 137 | #toast-container>div.rtl { 138 | direction: rtl; 139 | padding: 15px 50px 15px 15px; 140 | background-position: right 15px center 141 | } 142 | 143 | #toast-container>div:hover { 144 | -moz-box-shadow: 0 0 12px #000; 145 | -webkit-box-shadow: 0 0 12px #000; 146 | box-shadow: 0 0 12px #000; 147 | opacity: 1; 148 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); 149 | filter: alpha(opacity=100); 150 | cursor: pointer 151 | } 152 | 153 | #toast-container>.toast-info { 154 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=) !important 155 | } 156 | 157 | #toast-container>.toast-error { 158 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=) !important 159 | } 160 | 161 | #toast-container>.toast-success { 162 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==) !important 163 | } 164 | 165 | #toast-container>.toast-warning { 166 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=) !important 167 | } 168 | 169 | #toast-container.toast-bottom-center>div, 170 | #toast-container.toast-top-center>div { 171 | width: 300px; 172 | margin-left: auto; 173 | margin-right: auto 174 | } 175 | 176 | #toast-container.toast-bottom-full-width>div, 177 | #toast-container.toast-top-full-width>div { 178 | width: 96%; 179 | margin-left: auto; 180 | margin-right: auto 181 | } 182 | 183 | .toast { 184 | background-color: #030303 185 | } 186 | 187 | .toast-success { 188 | background-color: #51A351 189 | } 190 | 191 | .toast-error { 192 | background-color: #BD362F 193 | } 194 | 195 | .toast-info { 196 | background-color: #2F96B4 197 | } 198 | 199 | .toast-warning { 200 | background-color: #F89406 201 | } 202 | 203 | .toast-progress { 204 | position: absolute; 205 | left: 0; 206 | bottom: 0; 207 | height: 4px; 208 | background-color: #000; 209 | opacity: .4; 210 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); 211 | filter: alpha(opacity=40) 212 | } 213 | 214 | @media all and (max-width:240px) { 215 | #toast-container>div { 216 | padding: 8px 8px 8px 50px; 217 | width: 11em 218 | } 219 | 220 | #toast-container>div.rtl { 221 | padding: 8px 50px 8px 8px 222 | } 223 | 224 | #toast-container .toast-close-button { 225 | right: -.2em; 226 | top: -.2em 227 | } 228 | 229 | #toast-container .rtl .toast-close-button { 230 | left: -.2em; 231 | right: .2em 232 | } 233 | } 234 | 235 | @media all and (min-width:241px) and (max-width:480px) { 236 | #toast-container>div { 237 | padding: 8px 8px 8px 50px; 238 | width: 18em 239 | } 240 | 241 | #toast-container>div.rtl { 242 | padding: 8px 50px 8px 8px 243 | } 244 | 245 | #toast-container .toast-close-button { 246 | right: -.2em; 247 | top: -.2em 248 | } 249 | 250 | #toast-container .rtl .toast-close-button { 251 | left: -.2em; 252 | right: .2em 253 | } 254 | } 255 | 256 | @media all and (min-width:481px) and (max-width:768px) { 257 | #toast-container>div { 258 | padding: 15px 15px 15px 50px; 259 | width: 25em 260 | } 261 | 262 | #toast-container>div.rtl { 263 | padding: 15px 50px 15px 15px 264 | } 265 | } -------------------------------------------------------------------------------- /user/fill_in_the_blank.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $edit_blank_id = isset($_GET['edit_blank_id']) ? intval($_GET['edit_blank_id']) : null; 13 | 14 | $blanks = []; 15 | if ($lessonid !== null) { 16 | $blanks = $query->select('fill_in_the_blank', '*', "lesson_id = '$lessonid'"); 17 | } 18 | 19 | $edit_blank = null; 20 | if ($edit_blank_id !== null) { 21 | $edit_blank = $query->select('fill_in_the_blank', '*', "id = $edit_blank_id")[0] ?? null; 22 | } 23 | 24 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 25 | if (isset($_POST['add_blank'])) { 26 | $sentence = $_POST['sentence']; 27 | $correct_answer = $_POST['correct_answer']; 28 | 29 | $blank_id = $query->insert('fill_in_the_blank', [ 30 | 'lesson_id' => $lessonid, 31 | 'sentence' => $sentence, 32 | 'correct_answer' => $correct_answer 33 | ]); 34 | } elseif (isset($_POST['update_blank'])) { 35 | $blank_id = $_POST['blank_id']; 36 | $sentence = $_POST['sentence']; 37 | $correct_answer = $_POST['correct_answer']; 38 | 39 | $query->update('fill_in_the_blank', [ 40 | 'sentence' => $sentence, 41 | 'correct_answer' => $correct_answer 42 | ], "id = $blank_id"); 43 | } 44 | header("Location: ?lessonid=$lessonid"); 45 | exit; 46 | } 47 | 48 | if (isset($_GET['delete_id'])) { 49 | $delete_id = $_GET['delete_id']; 50 | $query->delete('fill_in_the_blank', "id = '$delete_id'"); 51 | header("Location: ?lessonid=$lessonid"); 52 | exit; 53 | } 54 | ?> 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | AdminLTE 3 | Fill in the Blank 65 | 66 | 67 | 68 | 112 | 113 | 114 |
115 | 116 |
117 | 118 | "Home", "url" => "./"], 121 | ["title" => "Fill in the Blank", "url" => "#"], 122 | ); 123 | pagePath('Fill in the Blank', $arr); 124 | ?> 125 | 126 |
127 |
128 |
129 | 130 | 131 | 132 |
133 |

134 | 135 |
136 | 137 | 138 |
139 |
140 | 141 | 142 |
143 | 144 |
145 | 146 |
147 |
148 | 149 |
150 |
151 |

Blanks List

152 |
153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | $blank): ?> 163 | 164 | 165 | 168 | 172 | 173 | 174 | 175 |
SentenceActions
166 |

167 |
169 | Edit 170 | Delete 171 |
176 |
177 | 178 | 179 |
180 | select('lessons', '*'); ?> 181 | 182 |
183 | 184 | 192 |
193 | 194 |
195 | 196 |
197 |
198 | 199 | 200 | 201 |
202 |
203 |
204 |
205 |
206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /login/index.php: -------------------------------------------------------------------------------- 1 | select('users', 'id, role', "username = ?", [$username], 's')[0] ?? null; 21 | 22 | if (!empty($user)) { 23 | $_SESSION['loggedin'] = true; 24 | $_SESSION['user_id'] = $user['id']; 25 | $_SESSION['username'] = $username; 26 | $_SESSION['role'] = $user['role']; 27 | 28 | $active_sessions = $query->select("active_sessions", "*", "session_token = ?", [session_id()], "s"); 29 | 30 | if (!empty($active_sessions)) { 31 | $query->update( 32 | "active_sessions", 33 | ['last_activity' => date('Y-m-d H:i:s')], 34 | "session_token = ?", 35 | [session_id()], 36 | "s" 37 | ); 38 | } 39 | 40 | if (isset(ROLES[$user['role']])) { 41 | header("Location: " . SITE_PATH . ROLES[$_SESSION['role']]); 42 | exit; 43 | } 44 | } 45 | } 46 | 47 | $_SESSION['csrf_token'] ??= bin2hex(random_bytes(32)); 48 | 49 | function get_user_info() 50 | { 51 | $user_agent = $_SERVER['HTTP_USER_AGENT']; 52 | 53 | $devices = [ 54 | 'iPhone' => 'iPhone', 55 | 'iPad' => 'iPad', 56 | 'Macintosh|Mac OS X' => 'Mac', 57 | 'Windows NT 10.0' => 'Windows 10 PC', 58 | 'Windows NT 6.3' => 'Windows 8.1 PC', 59 | 'Windows NT 6.2' => 'Windows 8 PC', 60 | 'Windows NT 6.1' => 'Windows 7 PC', 61 | 'Android' => 'Android Phone', 62 | 'Linux' => 'Linux Device', 63 | ]; 64 | 65 | foreach ($devices as $regex => $device) { 66 | if (preg_match("/$regex/i", $user_agent)) { 67 | return $device; 68 | } 69 | } 70 | 71 | return "Unknown Device"; 72 | } 73 | 74 | if ( 75 | $_SERVER["REQUEST_METHOD"] === "POST" && 76 | isset($_POST['submit']) && 77 | isset($_POST['csrf_token']) && 78 | isset($_SESSION['csrf_token']) && 79 | hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']) 80 | ) { 81 | 82 | $username = strtolower(trim($_POST['username'])); 83 | $password = $query->hashPassword($_POST['password']); 84 | $user = $query->select('users', '*', "username = ? AND password = ?", [$username, $password], 'ss')[0] ?? null; 85 | 86 | if (!empty($user)) { 87 | $_SESSION['loggedin'] = true; 88 | $_SESSION['user_id'] = $user['id']; 89 | $_SESSION['username'] = $user['username']; 90 | $_SESSION['role'] = $user['role']; 91 | 92 | $cookies = [ 93 | 'username' => $username, 94 | 'session_token' => session_id() 95 | ]; 96 | 97 | foreach ($cookies as $name => $value) { 98 | setcookie($name, $value, [ 99 | 'expires' => time() + (86400 * 30), 100 | 'path' => '/', 101 | 'secure' => true, 102 | 'httponly' => true, 103 | 'samesite' => 'Strict' 104 | ]); 105 | } 106 | 107 | $query->insert('active_sessions', [ 108 | 'user_id' => $user['id'], 109 | 'device_name' => get_user_info(), 110 | 'ip_address' => $_SERVER['REMOTE_ADDR'], 111 | 'last_activity' => date('Y-m-d H:i:s'), 112 | 'session_token' => session_id() 113 | ]); 114 | 115 | $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); 116 | 117 | $redirectPath = SITE_PATH . ROLES[$_SESSION['role']]; 118 | ?> 119 | 122 | 125 | 128 | 132 | 135 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | Login 147 | 148 | 149 | 150 | 151 | 152 |
153 |

Login

154 |
155 |
156 | 157 | 158 | 159 |
160 |
161 | 162 |
163 | 164 | 167 |
168 | 169 |
170 |
171 | 172 |
173 |
174 | 175 |
176 |
177 |
178 |

Don't have an account? Sign Up

179 |
180 |
181 | 182 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /user/matching.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $edit_matching_id = isset($_GET['edit_matching_id']) ? intval($_GET['edit_matching_id']) : null; 13 | 14 | $matchings = []; 15 | if ($lessonid !== null) { 16 | $matchings = $query->select('matching', '*', "lesson_id = '$lessonid'"); 17 | } 18 | 19 | $edit_matching = null; 20 | if ($edit_matching_id !== null) { 21 | $edit_matching = $query->select('matching', '*', "id = $edit_matching_id")[0] ?? null; 22 | } 23 | 24 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 25 | if (isset($_POST['add_matching'])) { 26 | $left_side = $_POST['left_side']; 27 | $right_side = $_POST['right_side']; 28 | 29 | $matching_id = $query->insert('matching', [ 30 | 'lesson_id' => $lessonid, 31 | 'left_side' => $left_side, 32 | 'right_side' => $right_side 33 | ]); 34 | } elseif (isset($_POST['update_matching'])) { 35 | $matching_id = $_POST['matching_id']; 36 | $left_side = $_POST['left_side']; 37 | $right_side = $_POST['right_side']; 38 | 39 | $query->update('matching', [ 40 | 'left_side' => $left_side, 41 | 'right_side' => $right_side 42 | ], "id = $matching_id"); 43 | } 44 | header("Location: ?lessonid=$lessonid"); 45 | exit; 46 | } 47 | 48 | if (isset($_GET['delete_id'])) { 49 | $delete_id = $_GET['delete_id']; 50 | $query->delete('matching', "id = '$delete_id'"); 51 | header("Location: ?lessonid=$lessonid"); 52 | exit; 53 | } 54 | ?> 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | AdminLTE 3 | Matching 65 | 66 | 67 | 68 | 112 | 113 | 114 |
115 | 116 |
117 | 118 | "Home", "url" => "./"], 121 | ["title" => "Matching", "url" => "#"], 122 | ); 123 | pagePath('Matching', $arr); 124 | ?> 125 | 126 |
127 |
128 |
129 | 130 | 131 | 132 |
133 |

134 | 135 |
136 | 137 | 138 |
139 |
140 | 141 | 142 |
143 | 144 |
145 | 146 |
147 |
148 | 149 |
150 |
151 |

Matchings List

152 |
153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | $matching): ?> 164 | 165 | 166 | 169 | 170 | 174 | 175 | 176 | 177 |
Left SideRight SideActions
167 |

168 |
171 | Edit 172 | Delete 173 |
178 |
179 | 180 | 181 |
182 | select('lessons', '*'); ?> 183 | 184 |
185 | 186 | 194 |
195 | 196 |
197 | 198 |
199 |
200 | 201 | 202 | 203 |
204 |
205 |
206 |
207 |
208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /user/topics.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*'); 5 | 6 | if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['insert'])) { 7 | $title = $_POST['title']; 8 | $description = $_POST['description']; 9 | 10 | $insert = $query->insert('lessons', [ 11 | 'title' => $title, 12 | 'description' => $description 13 | ]); 14 | 15 | if ($insert) { 16 | header("Location: ./topics.php"); 17 | } 18 | } 19 | 20 | if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['delete'])) { 21 | $id = $_POST['id']; 22 | $delete = $query->delete('lessons', "id = $id"); 23 | 24 | if ($delete) { 25 | header("Location: ./topics.php"); 26 | } 27 | } 28 | 29 | if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['id'])) { 30 | $id = $_POST['id'] ?? null; 31 | $title = $_POST['title'] ?? null; 32 | $description = $_POST['description'] ?? null; 33 | 34 | $update = $query->update('lessons', [ 35 | 'title' => $title, 36 | 'description' => $description 37 | ], "id = $id"); 38 | 39 | if ($update) { 40 | header("Location: ./topics.php"); 41 | } 42 | } 43 | ?> 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | AdminLTE 3 | Topics 53 | 54 | 55 | 60 | 61 | 62 |
63 | 64 |
65 | 66 | "Home", "url" => "./"], 69 | ["title" => "Topics", "url" => "#"], 70 | ); 71 | pagePath('Topics', $arr); 72 | ?> 73 | 74 |
75 |
76 |
77 |
78 |
79 |
80 |

Insert New Topic

81 |
82 |
83 |
84 |
85 | 86 | 87 |
88 |
89 | 90 | 91 |
92 | 93 |
94 |
95 |
96 | 97 |
98 |
99 |

Topics List

100 |
101 |
102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | "; 117 | echo ""; 118 | echo ""; 119 | echo ""; 120 | echo ""; 134 | echo ""; 135 | $count++; 136 | } 137 | } else { 138 | echo ""; 139 | } 140 | ?> 141 | 142 |
TitleDescriptionActions
{$count}{$topic['title']}{$topic['description']} 121 | 129 |
130 | 131 | 132 |
133 |
No topics found.
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | 151 | 152 |
153 | 154 | 180 | 181 | 182 | 183 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /user/true_false.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $true_false = []; 13 | if ($lessonid !== null) { 14 | $true_false = $query->select('tru_false', '*', "lesson_id = '$lessonid'"); 15 | } 16 | 17 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 18 | if (isset($_POST['add_true_false'])) { 19 | $statement = ($_POST['statement']); 20 | $is_true = isset($_POST['is_true']) ? 1 : 0; 21 | 22 | $query->insert('tru_false', [ 23 | 'lesson_id' => $lessonid, 24 | 'statement' => $statement, 25 | 'is_true' => $is_true 26 | ]); 27 | 28 | header("Location: true_false.php?lessonid=$lessonid"); 29 | exit; 30 | } 31 | 32 | if (isset($_POST['update_true_false'])) { 33 | foreach ($_POST['statement'] as $id => $statement) { 34 | $statement = ($statement); 35 | $is_true = isset($_POST['is_true'][$id]) ? 1 : 0; 36 | 37 | $query->update('tru_false', [ 38 | 'statement' => $statement, 39 | 'is_true' => $is_true 40 | ], "id = '$id'"); 41 | } 42 | header("Location: true_false.php?lessonid=$lessonid"); 43 | exit; 44 | } 45 | } 46 | 47 | 48 | if (isset($_GET['delete_id'])) { 49 | $delete_id = $_GET['delete_id']; 50 | $query->delete('tru_false', "id = '$delete_id'"); 51 | header("Location: true_false.php?lessonid=$lessonid"); 52 | exit; 53 | } 54 | ?> 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Admin | True/False 65 | 66 | 67 | 68 | 140 | 141 | 142 |
143 | 144 |
145 | 146 | "Home", "url" => "./"], 149 | ["title" => "True/False", "url" => "#"], 150 | ); 151 | pagePath('True/False', $arr); 152 | ?> 153 | 154 |
155 |
156 |
157 | 158 | 159 |
160 |
161 |
162 |

Add New True/False Question

163 |
164 | 165 | 166 |
167 | 168 | 169 |
170 | 171 |
172 | 173 | Yes 174 |
175 | 176 | 177 |
178 |
179 |
180 | 181 |
182 |
183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | $question): ?> 194 | 195 | 196 | 199 | 202 | 205 | 206 | 207 | 208 |
StatementAnswerActions
197 | 198 | 200 | > 201 | 203 | Delete 204 |
209 | 210 | 211 |
212 |
213 |
214 |
215 |
216 |
217 | 218 |
219 | select('lessons', '*'); ?> 220 | 221 |
222 | 223 | 231 |
232 | 233 |
234 | 235 |
236 |
237 | 238 | 239 | 240 |
241 |
242 |
243 | 244 |
245 | 246 | 247 |
248 | 249 | 250 | 251 | 252 | 253 | -------------------------------------------------------------------------------- /user/includes/navbar.php: -------------------------------------------------------------------------------- 1 | 5 |
6 |
7 |
8 |
9 |

10 | 11 |

12 |
13 |
14 | 24 |
25 |
26 |
27 |
28 | 31 | 32 | 33 | 34 | 79 | 80 | -------------------------------------------------------------------------------- /user/src/js/toastr.min.js: -------------------------------------------------------------------------------- 1 | ! function (e) { 2 | e(["jquery"], function (e) { 3 | return function () { 4 | function t(e, t, n) { 5 | return g({ 6 | type: O.error, 7 | iconClass: m().iconClasses.error, 8 | message: e, 9 | optionsOverride: n, 10 | title: t 11 | }) 12 | } 13 | 14 | function n(t, n) { 15 | return t || (t = m()), v = e("#" + t.containerId), v.length ? v : (n && (v = d(t)), v) 16 | } 17 | 18 | function o(e, t, n) { 19 | return g({ 20 | type: O.info, 21 | iconClass: m().iconClasses.info, 22 | message: e, 23 | optionsOverride: n, 24 | title: t 25 | }) 26 | } 27 | 28 | function s(e) { 29 | C = e 30 | } 31 | 32 | function i(e, t, n) { 33 | return g({ 34 | type: O.success, 35 | iconClass: m().iconClasses.success, 36 | message: e, 37 | optionsOverride: n, 38 | title: t 39 | }) 40 | } 41 | 42 | function a(e, t, n) { 43 | return g({ 44 | type: O.warning, 45 | iconClass: m().iconClasses.warning, 46 | message: e, 47 | optionsOverride: n, 48 | title: t 49 | }) 50 | } 51 | 52 | function r(e, t) { 53 | var o = m(); 54 | v || n(o), u(e, o, t) || l(o) 55 | } 56 | 57 | function c(t) { 58 | var o = m(); 59 | return v || n(o), t && 0 === e(":focus", t).length ? void h(t) : void(v.children().length && v.remove()) 60 | } 61 | 62 | function l(t) { 63 | for (var n = v.children(), o = n.length - 1; o >= 0; o--) u(e(n[o]), t) 64 | } 65 | 66 | function u(t, n, o) { 67 | var s = !(!o || !o.force) && o.force; 68 | return !(!t || !s && 0 !== e(":focus", t).length) && (t[n.hideMethod]({ 69 | duration: n.hideDuration, 70 | easing: n.hideEasing, 71 | complete: function () { 72 | h(t) 73 | } 74 | }), !0) 75 | } 76 | 77 | function d(t) { 78 | return v = e("
").attr("id", t.containerId).addClass(t.positionClass), v.appendTo(e(t.target)), v 79 | } 80 | 81 | function p() { 82 | return { 83 | tapToDismiss: !0, 84 | toastClass: "toast", 85 | containerId: "toast-container", 86 | debug: !1, 87 | showMethod: "fadeIn", 88 | showDuration: 300, 89 | showEasing: "swing", 90 | onShown: void 0, 91 | hideMethod: "fadeOut", 92 | hideDuration: 1e3, 93 | hideEasing: "swing", 94 | onHidden: void 0, 95 | closeMethod: !1, 96 | closeDuration: !1, 97 | closeEasing: !1, 98 | closeOnHover: !0, 99 | extendedTimeOut: 1e3, 100 | iconClasses: { 101 | error: "toast-error", 102 | info: "toast-info", 103 | success: "toast-success", 104 | warning: "toast-warning" 105 | }, 106 | iconClass: "toast-info", 107 | positionClass: "toast-top-right", 108 | timeOut: 5e3, 109 | titleClass: "toast-title", 110 | messageClass: "toast-message", 111 | escapeHtml: !1, 112 | target: "body", 113 | closeHtml: '', 114 | closeClass: "toast-close-button", 115 | newestOnTop: !0, 116 | preventDuplicates: !1, 117 | progressBar: !1, 118 | progressClass: "toast-progress", 119 | rtl: !1 120 | } 121 | } 122 | 123 | function f(e) { 124 | C && C(e) 125 | } 126 | 127 | function g(t) { 128 | function o(e) { 129 | return null == e && (e = ""), e.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(//g, ">") 130 | } 131 | 132 | function s() { 133 | c(), u(), d(), p(), g(), C(), l(), i() 134 | } 135 | 136 | function i() { 137 | var e = ""; 138 | switch (t.iconClass) { 139 | case "toast-success": 140 | case "toast-info": 141 | e = "polite"; 142 | break; 143 | default: 144 | e = "assertive" 145 | } 146 | I.attr("aria-live", e) 147 | } 148 | 149 | function a() { 150 | E.closeOnHover && I.hover(H, D), !E.onclick && E.tapToDismiss && I.click(b), E.closeButton && j && j.click(function (e) { 151 | e.stopPropagation ? e.stopPropagation() : void 0 !== e.cancelBubble && e.cancelBubble !== !0 && (e.cancelBubble = !0), E.onCloseClick && E.onCloseClick(e), b(!0) 152 | }), E.onclick && I.click(function (e) { 153 | E.onclick(e), b() 154 | }) 155 | } 156 | 157 | function r() { 158 | I.hide(), I[E.showMethod]({ 159 | duration: E.showDuration, 160 | easing: E.showEasing, 161 | complete: E.onShown 162 | }), E.timeOut > 0 && (k = setTimeout(b, E.timeOut), F.maxHideTime = parseFloat(E.timeOut), F.hideEta = (new Date).getTime() + F.maxHideTime, E.progressBar && (F.intervalId = setInterval(x, 10))) 163 | } 164 | 165 | function c() { 166 | t.iconClass && I.addClass(E.toastClass).addClass(y) 167 | } 168 | 169 | function l() { 170 | E.newestOnTop ? v.prepend(I) : v.append(I) 171 | } 172 | 173 | function u() { 174 | if (t.title) { 175 | var e = t.title; 176 | E.escapeHtml && (e = o(t.title)), M.append(e).addClass(E.titleClass), I.append(M) 177 | } 178 | } 179 | 180 | function d() { 181 | if (t.message) { 182 | var e = t.message; 183 | E.escapeHtml && (e = o(t.message)), B.append(e).addClass(E.messageClass), I.append(B) 184 | } 185 | } 186 | 187 | function p() { 188 | E.closeButton && (j.addClass(E.closeClass).attr("role", "button"), I.prepend(j)) 189 | } 190 | 191 | function g() { 192 | E.progressBar && (q.addClass(E.progressClass), I.prepend(q)) 193 | } 194 | 195 | function C() { 196 | E.rtl && I.addClass("rtl") 197 | } 198 | 199 | function O(e, t) { 200 | if (e.preventDuplicates) { 201 | if (t.message === w) return !0; 202 | w = t.message 203 | } 204 | return !1 205 | } 206 | 207 | function b(t) { 208 | var n = t && E.closeMethod !== !1 ? E.closeMethod : E.hideMethod, 209 | o = t && E.closeDuration !== !1 ? E.closeDuration : E.hideDuration, 210 | s = t && E.closeEasing !== !1 ? E.closeEasing : E.hideEasing; 211 | if (!e(":focus", I).length || t) return clearTimeout(F.intervalId), I[n]({ 212 | duration: o, 213 | easing: s, 214 | complete: function () { 215 | h(I), clearTimeout(k), E.onHidden && "hidden" !== P.state && E.onHidden(), P.state = "hidden", P.endTime = new Date, f(P) 216 | } 217 | }) 218 | } 219 | 220 | function D() { 221 | (E.timeOut > 0 || E.extendedTimeOut > 0) && (k = setTimeout(b, E.extendedTimeOut), F.maxHideTime = parseFloat(E.extendedTimeOut), F.hideEta = (new Date).getTime() + F.maxHideTime) 222 | } 223 | 224 | function H() { 225 | clearTimeout(k), F.hideEta = 0, I.stop(!0, !0)[E.showMethod]({ 226 | duration: E.showDuration, 227 | easing: E.showEasing 228 | }) 229 | } 230 | 231 | function x() { 232 | var e = (F.hideEta - (new Date).getTime()) / F.maxHideTime * 100; 233 | q.width(e + "%") 234 | } 235 | var E = m(), 236 | y = t.iconClass || E.iconClass; 237 | if ("undefined" != typeof t.optionsOverride && (E = e.extend(E, t.optionsOverride), y = t.optionsOverride.iconClass || y), !O(E, t)) { 238 | T++, v = n(E, !0); 239 | var k = null, 240 | I = e("
"), 241 | M = e("
"), 242 | B = e("
"), 243 | q = e("
"), 244 | j = e(E.closeHtml), 245 | F = { 246 | intervalId: null, 247 | hideEta: null, 248 | maxHideTime: null 249 | }, 250 | P = { 251 | toastId: T, 252 | state: "visible", 253 | startTime: new Date, 254 | options: E, 255 | map: t 256 | }; 257 | return s(), r(), a(), f(P), E.debug && console && console.log(P), I 258 | } 259 | } 260 | 261 | function m() { 262 | return e.extend({}, p(), b.options) 263 | } 264 | 265 | function h(e) { 266 | v || (v = n()), e.is(":visible") || (e.remove(), e = null, 0 === v.children().length && (v.remove(), w = void 0)) 267 | } 268 | var v, C, w, T = 0, 269 | O = { 270 | error: "error", 271 | info: "info", 272 | success: "success", 273 | warning: "warning" 274 | }, 275 | b = { 276 | clear: r, 277 | remove: c, 278 | error: t, 279 | getContainer: n, 280 | info: o, 281 | options: {}, 282 | subscribe: s, 283 | success: i, 284 | version: "2.1.4", 285 | warning: a 286 | }; 287 | return b 288 | }() 289 | }) 290 | }("function" == typeof define && define.amd ? define : function (e, t) { 291 | "undefined" != typeof module && module.exports ? module.exports = t(require("jquery")) : window.toastr = t(window.jQuery) 292 | }); 293 | //# sourceMappingURL=toastr.js.map -------------------------------------------------------------------------------- /user/test.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $edit_test_id = isset($_GET['edit_test_id']) ? intval($_GET['edit_test_id']) : null; 13 | 14 | 15 | 16 | $tests = []; 17 | if ($lessonid !== null) { 18 | $tests = $query->select('test', '*', "lesson_id = '$lessonid'"); 19 | } 20 | 21 | $edit_test = null; 22 | if ($edit_test_id !== null) { 23 | $edit_test = $query->select('test', '*', "id = $edit_test_id")[0] ?? null; 24 | $edit_test_options = $query->select('test_options', '*', "test_id = $edit_test_id"); 25 | } 26 | 27 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 28 | if (isset($_POST['add_test'])) { 29 | $question = $_POST['question']; 30 | $options = $_POST['options']; 31 | $correct_option = $_POST['correct_option']; 32 | 33 | $test_id = $query->insert('test', [ 34 | 'lesson_id' => $lessonid, 35 | 'question' => $question 36 | ]); 37 | 38 | foreach ($options as $index => $option) { 39 | $query->insert('test_options', [ 40 | 'test_id' => $test_id, 41 | 'option_text' => $option, 42 | 'is_correct' => ($correct_option == $index) ? 1 : 0 43 | ]); 44 | } 45 | } elseif (isset($_POST['update_test'])) { 46 | $test_id = $_POST['test_id']; 47 | $question = $_POST['question']; 48 | $options = $_POST['options']; 49 | $correct_option = $_POST['correct_option']; 50 | 51 | $query->update('test', ['question' => $question], "id = $test_id"); 52 | $query->delete('test_options', "test_id = $test_id"); 53 | 54 | foreach ($options as $index => $option) { 55 | $query->insert('test_options', [ 56 | 'test_id' => $test_id, 57 | 'option_text' => $option, 58 | 'is_correct' => ($correct_option == $index) ? 1 : 0 59 | ]); 60 | } 61 | } 62 | header("Location: ?lessonid=$lessonid"); 63 | exit; 64 | } 65 | 66 | if (isset($_GET['delete_id'])) { 67 | $delete_id = $_GET['delete_id']; 68 | $query->delete('test', "id = '$delete_id'"); 69 | header("Location: ?lessonid=$lessonid"); 70 | exit; 71 | } 72 | ?> 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | AdminLTE 3 | Test 83 | 84 | 85 | 86 | 130 | 131 | 132 |
133 | 134 |
135 | 136 | "Home", "url" => "./"], 139 | ["title" => "Worksheet", "url" => "#"], 140 | ); 141 | pagePath('Worksheet', $arr); 142 | ?> 143 | 144 |
145 |
146 |
147 | 148 | 149 | 150 |
151 |

152 | 153 |
154 | 155 | 156 |
157 | 158 |
159 | 160 | 161 | $option): ?> 162 |
163 | 164 | > Correct 165 | 166 |
167 | 168 | 169 |
170 | 171 | Correct 172 |
173 | 174 |
175 | 176 | 177 | 178 |
179 | 180 |
181 |
182 | 183 |
184 |
185 |

Topics List

186 |
187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | $test): ?> 197 | 198 | 199 | 202 | 206 | 207 | 208 | 209 |
QuestionActions
200 |

201 |
203 | Edit 204 | Delete 205 |
210 |
211 | 212 | 213 |
214 | select('lessons', '*'); ?> 215 | 216 |
217 | 218 | 226 |
227 | 228 |
229 | 230 |
231 |
232 | 233 | 234 | 235 |
236 |
237 |
238 | 239 |
240 | 241 | 242 |
243 | 244 | 245 | 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /user/question.php: -------------------------------------------------------------------------------- 1 | 2 | select('lessons', '*', "id = '$lessonid'"); 8 | } else { 9 | $lessons_test = []; 10 | } 11 | 12 | $edit_question_id = isset($_GET['edit_question_id']) ? intval($_GET['edit_question_id']) : null; 13 | 14 | $questions = []; 15 | if ($lessonid !== null) { 16 | $questions = $query->select('questions', '*', "lesson_id = '$lessonid'"); 17 | } 18 | 19 | $edit_question = null; 20 | if ($edit_question_id !== null) { 21 | $edit_question = $query->select('questions', '*', "id = $edit_question_id")[0] ?? null; 22 | $edit_answers = $query->select('answers', '*', "question_id = $edit_question_id"); 23 | } 24 | 25 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 26 | if (isset($_POST['add_question'])) { 27 | $question_text = $_POST['question_text']; 28 | $question_id = $query->insert('questions', [ 29 | 'lesson_id' => $lessonid, 30 | 'question_text' => $question_text 31 | ]); 32 | 33 | $answers = $_POST['answers']; 34 | 35 | foreach ($answers as $index => $answer) { 36 | $query->insert('answers', [ 37 | 'question_id' => $question_id, 38 | 'answer_text' => $answer, 39 | ]); 40 | } 41 | } elseif (isset($_POST['update_question'])) { 42 | $question_id = $_POST['question_id']; 43 | $question_text = $_POST['question_text']; 44 | $query->update('questions', ['question_text' => $question_text], "id = $question_id"); 45 | 46 | $query->delete('answers', "question_id = $question_id"); 47 | 48 | $answers = $_POST['answers']; 49 | 50 | foreach ($answers as $index => $answer) { 51 | $query->insert('answers', [ 52 | 'question_id' => $question_id, 53 | 'answer_text' => $answer 54 | ]); 55 | } 56 | } 57 | header("Location: ?lessonid=$lessonid"); 58 | exit; 59 | } 60 | 61 | if (isset($_GET['delete_question_id'])) { 62 | $delete_question_id = $_GET['delete_question_id']; 63 | $query->delete('answers', "question_id = '$delete_question_id'"); 64 | $query->delete('questions', "id = '$delete_question_id'"); 65 | header("Location: ?lessonid=$lessonid"); 66 | exit; 67 | } 68 | ?> 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | AdminLTE 3 | Test 79 | 80 | 81 | 82 | 126 | 127 | 128 |
129 | 130 |
131 | 132 | "Home", "url" => "./"], 135 | ["title" => "Questions", "url" => "#"], 136 | ); 137 | pagePath('Questions', $arr); 138 | ?> 139 | 140 |
141 |
142 |
143 | 144 | 145 | 146 |
147 |

148 | 149 |
150 | 151 | 152 |
153 | 154 |
155 | 156 | 157 | $answer): ?> 158 |
159 | 160 | 161 |
162 | 163 | 164 |
165 | 166 |
167 | 168 |
169 | 170 | 171 | 172 |
173 | 174 |
175 |
176 | 177 |
178 |
179 |

Questions List

180 |
181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | $question): ?> 191 | 192 | 193 | 196 | 200 | 201 | 202 | 203 |
QuestionActions
194 | 195 | 197 | Edit 198 | Delete 199 |
204 |
205 | 206 | 207 |
208 | select('lessons', '*'); ?> 209 | 210 |
211 | 212 | 220 |
221 | 222 |
223 | 224 |
225 |
226 | 227 | 228 | 229 |
230 |
231 |
232 |
233 | 234 |
235 | 236 | 237 | 238 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /signup/index.php: -------------------------------------------------------------------------------- 1 | select('users', 'id, role', "username = ?", [$username], 's')[0] ?? null; 21 | 22 | if (!empty($user)) { 23 | $_SESSION['loggedin'] = true; 24 | $_SESSION['user_id'] = $user['id']; 25 | $_SESSION['username'] = $username; 26 | $_SESSION['role'] = $user['role']; 27 | 28 | $active_sessions = $query->select("active_sessions", "*", "session_token = ?", [session_id()], "s"); 29 | 30 | if (!empty($active_sessions)) { 31 | $query->update( 32 | "active_sessions", 33 | ['last_activity' => date('Y-m-d H:i:s')], 34 | "session_token = ?", 35 | [session_id()], 36 | "s" 37 | ); 38 | } 39 | 40 | if (isset(ROLES[$user['role']])) { 41 | header("Location: " . SITE_PATH . ROLES[$_SESSION['role']]); 42 | exit; 43 | } 44 | } 45 | } 46 | 47 | $_SESSION['csrf_token'] ??= bin2hex(random_bytes(32)); 48 | 49 | function get_user_info() 50 | { 51 | $user_agent = $_SERVER['HTTP_USER_AGENT']; 52 | 53 | $devices = [ 54 | 'iPhone' => 'iPhone', 55 | 'iPad' => 'iPad', 56 | 'Macintosh|Mac OS X' => 'Mac', 57 | 'Windows NT 10.0' => 'Windows 10 PC', 58 | 'Windows NT 6.3' => 'Windows 8.1 PC', 59 | 'Windows NT 6.2' => 'Windows 8 PC', 60 | 'Windows NT 6.1' => 'Windows 7 PC', 61 | 'Android' => 'Android Phone', 62 | 'Linux' => 'Linux Device', 63 | ]; 64 | 65 | foreach ($devices as $regex => $device) { 66 | if (preg_match("/$regex/i", $user_agent)) { 67 | return $device; 68 | } 69 | } 70 | 71 | return "Unknown Device"; 72 | } 73 | 74 | if ( 75 | $_SERVER["REQUEST_METHOD"] === "POST" && 76 | isset($_POST['submit']) && 77 | isset($_POST['csrf_token']) && 78 | isset($_SESSION['csrf_token']) && 79 | hash_equals($_SESSION['csrf_token'], $_POST['csrf_token']) 80 | ) { 81 | 82 | $first_name = $query->validate($_POST['first_name']); 83 | $last_name = $query->validate($_POST['last_name']); 84 | $email = $query->validate(strtolower($_POST['email'])); 85 | $username = $query->validate(strtolower($_POST['username'])); 86 | $password = $query->hashPassword($_POST['password']); 87 | $role = 'user'; // default role is 'user' 88 | 89 | $data = [ 90 | 'first_name' => $first_name, 91 | 'last_name' => $last_name, 92 | 'email' => $email, 93 | 'username' => $username, 94 | 'password' => $password, 95 | 'role' => $role, 96 | 'created_at' => date('Y-m-d H:i:s'), 97 | 'updated_at' => date('Y-m-d H:i:s') 98 | ]; 99 | 100 | $user = $query->insert('users', $data); 101 | 102 | if (!empty($user)) { 103 | $user_id = $query->select('users', 'id', 'username = ?', [$username], 's')[0]['id']; 104 | 105 | $_SESSION['loggedin'] = true; 106 | $_SESSION['user_id'] = $user_id; 107 | $_SESSION['username'] = $username; 108 | $_SESSION['role'] = $role; 109 | 110 | $cookies = [ 111 | 'username' => $username, 112 | 'session_token' => session_id() 113 | ]; 114 | 115 | foreach ($cookies as $name => $value) { 116 | setcookie($name, $value, [ 117 | 'expires' => time() + (86400 * 30), 118 | 'path' => '/', 119 | 'secure' => true, 120 | 'httponly' => true, 121 | 'samesite' => 'Strict' 122 | ]); 123 | } 124 | 125 | $query->insert('active_sessions', [ 126 | 'user_id' => $user_id, 127 | 'device_name' => get_user_info(), 128 | 'ip_address' => $_SERVER['REMOTE_ADDR'], 129 | 'last_activity' => date('Y-m-d H:i:s'), 130 | 'session_token' => session_id() 131 | ]); 132 | 133 | $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); 134 | 135 | $redirectPath = SITE_PATH . ROLES[$_SESSION['role']]; 136 | ?> 137 | 140 | 143 | 146 | 150 | 153 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | Sign Up 165 | 166 | 167 | 168 | 169 | 170 |
171 |

Sign Up

172 |
173 |
174 | 175 | 176 |
177 |
178 | 179 | 180 |
181 |
182 | 183 | 184 | 185 |
186 |
187 | 188 | 189 | 190 |
191 |
192 | 193 |
194 | 195 | 198 |
199 | 200 |
201 |
202 | 203 |
204 |
205 | 206 |
207 |
208 |
209 |

Already have an account? Login

210 |
211 |
212 | 213 | 305 | 306 | 307 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | select('subjects', '*', "url = ?", [$url], 's'); 9 | 10 | if (empty($subject)) { 11 | header('Location: ./'); 12 | exit(); 13 | } 14 | 15 | $subjectid = $subject[0]['id']; 16 | 17 | $tests = $query->select('test', '*', "subject_id = ?", [$subjectid], 'i'); 18 | $tru_falses = $query->select('tru_false', '*', "subject_id = ?", [$subjectid], 'i'); 19 | $dropdowns = $query->select('dropdown', '*', "subject_id = ?", [$subjectid], 'i'); 20 | $fill_in_the_blanks = $query->select('fill_in_the_blank', '*', "subject_id = ?", [$subjectid], 'i'); 21 | 22 | shuffle($tests); 23 | shuffle($tru_falses); 24 | shuffle($dropdowns); 25 | shuffle($fill_in_the_blanks); 26 | 27 | if ($_SERVER['REQUEST_METHOD'] == 'POST') { 28 | $correctAnswersCount = 0; 29 | 30 | foreach ($tests as $test) { 31 | $testid = $test['id']; 32 | $correctOption = $query->select('test_options', 'id', "test_id = $testid AND is_correct = 1"); 33 | 34 | $correctAnswerId = $correctOption[0]['id']; 35 | 36 | if (isset($_POST["test_answer_$testid"]) && $_POST["test_answer_$testid"] == $correctAnswerId) { 37 | $correctAnswersCount++; 38 | } 39 | } 40 | 41 | foreach ($tru_falses as $tru_false) { 42 | $correctAnswer = $tru_false['is_true']; 43 | if (isset($_POST["tru_false_answer_{$tru_false['id']}"]) && $_POST["tru_false_answer_{$tru_false['id']}"] == $correctAnswer) { 44 | $correctAnswersCount++; 45 | } 46 | } 47 | 48 | foreach ($dropdowns as $dropdown) { 49 | $correctAnswer = $dropdown['correct_answer']; 50 | if (isset($_POST["dropdown_answer_{$dropdown['id']}"]) && $_POST["dropdown_answer_{$dropdown['id']}"] == $correctAnswer) { 51 | $correctAnswersCount++; 52 | } 53 | } 54 | 55 | foreach ($fill_in_the_blanks as $blank) { 56 | $correctAnswer = $blank['correct_answer']; 57 | if (isset($_POST["fill_in_the_blank_answer_{$blank['id']}"]) && strtolower(trim($_POST["fill_in_the_blank_answer_{$blank['id']}"])) == strtolower(trim($correctAnswer))) { 58 | $correctAnswersCount++; 59 | } 60 | } 61 | 62 | $totalQuestions = count($tests) + count($tru_falses) + count($dropdowns) + count($fill_in_the_blanks); 63 | $percentage = ($correctAnswersCount / $totalQuestions) * 100; 64 | 65 | // $query->insert('results', [ 66 | // 'subject_id' => $subjectid, 67 | // // 'participant_name' => $participant_name, 68 | // 'answered_questions' => $correctAnswersCount, 69 | // 'total_questions' => $totalQuestions 70 | // ]); 71 | ?> 72 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Test | <?= $subject[0]['title'] ?> 102 | 103 | 104 | 105 | 359 | 360 | 361 | 362 |
363 | 364 | 365 | 366 | 367 | 368 |
369 |

370 |

371 |
372 | 373 |
374 | 375 | 376 |
377 | 378 |
379 | 380 |

Test Questions

381 |
382 | select('test_options', '*', "test_id = $testid"); 385 | shuffle($options); 386 | ?> 387 |
388 |
391 | 392 |
393 | 394 |
399 | 400 |
401 |
402 |
403 | 404 |
405 | 406 |
407 | 408 |
409 | 410 |

True/False Questions

411 |
412 | 413 |
414 |
418 |
419 |
423 |
427 |
428 |
429 |
430 | 431 | 432 |
433 | 434 |
435 | 436 |
437 | 438 |

Dropdown Question

439 |
440 | $dropdown): ?> 441 | 442 | 443 | 444 | 445 |
446 | 447 |
451 |
458 |
459 |
460 | 461 |
462 | 463 |
464 | 465 |
466 | 467 |

Fill in the Blank Questions

468 |
469 | 470 |
471 |
474 |
476 |
477 |
478 | 479 |
480 | 481 |
482 | 483 |
484 | 485 |
486 |
487 | 488 | 489 |
490 | 491 | 492 | 493 | 494 | -------------------------------------------------------------------------------- /src/js/adminlte.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * AdminLTE v3.0.4 (https://adminlte.io) 3 | * Copyright 2014-2020 Colorlib 4 | * Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE) 5 | */ 6 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).adminlte={})}(this,(function(t){"use strict";var e=function(t){var e="ControlSidebar",i="lte.controlsidebar",n=t.fn[e],s={COLLAPSED:"collapsed.lte.controlsidebar",EXPANDED:"expanded.lte.controlsidebar"},o=".control-sidebar",a=".control-sidebar-content",r='[data-widget="control-sidebar"]',l=".main-header",c=".main-footer",d="control-sidebar-animate",h="control-sidebar-open",f="control-sidebar-slide-open",u="layout-fixed",g="layout-navbar-fixed",p="layout-sm-navbar-fixed",_="layout-md-navbar-fixed",m="layout-lg-navbar-fixed",v="layout-xl-navbar-fixed",C="layout-footer-fixed",y="layout-sm-footer-fixed",b="layout-md-footer-fixed",w="layout-lg-footer-fixed",x="layout-xl-footer-fixed",E={controlsidebarSlide:!0,scrollbarTheme:"os-theme-light",scrollbarAutoHide:"l"},A=function(){function e(t,e){this._element=t,this._config=e,this._init()}var n=e.prototype;return n.collapse=function(){this._config.controlsidebarSlide?(t("html").addClass(d),t("body").removeClass(f).delay(300).queue((function(){t(o).hide(),t("html").removeClass(d),t(this).dequeue()}))):t("body").removeClass(h);var e=t.Event(s.COLLAPSED);t(this._element).trigger(e)},n.show=function(){this._config.controlsidebarSlide?(t("html").addClass(d),t(o).show().delay(10).queue((function(){t("body").addClass(f).delay(300).queue((function(){t("html").removeClass(d),t(this).dequeue()})),t(this).dequeue()}))):t("body").addClass(h);var e=t.Event(s.EXPANDED);t(this._element).trigger(e)},n.toggle=function(){t("body").hasClass(h)||t("body").hasClass(f)?this.collapse():this.show()},n._init=function(){var e=this;this._fixHeight(),this._fixScrollHeight(),t(window).resize((function(){e._fixHeight(),e._fixScrollHeight()})),t(window).scroll((function(){(t("body").hasClass(h)||t("body").hasClass(f))&&e._fixScrollHeight()}))},n._fixScrollHeight=function(){var e={scroll:t(document).height(),window:t(window).height(),header:t(l).outerHeight(),footer:t(c).outerHeight()},i=Math.abs(e.window+t(window).scrollTop()-e.scroll),n=t(window).scrollTop(),s=!1,r=!1;t("body").hasClass(u)&&((t("body").hasClass(g)||t("body").hasClass(p)||t("body").hasClass(_)||t("body").hasClass(m)||t("body").hasClass(v))&&"fixed"===t(l).css("position")&&(s=!0),(t("body").hasClass(C)||t("body").hasClass(y)||t("body").hasClass(b)||t("body").hasClass(w)||t("body").hasClass(x))&&"fixed"===t(c).css("position")&&(r=!0),0===n&&0===i?(t(o).css("bottom",e.footer),t(o).css("top",e.header),t(o+", "+o+" "+a).css("height",e.window-(e.header+e.footer))):i<=e.footer?!1===r?(t(o).css("bottom",e.footer-i),t(o+", "+o+" "+a).css("height",e.window-(e.footer-i))):t(o).css("bottom",e.footer):n<=e.header?!1===s?(t(o).css("top",e.header-n),t(o+", "+o+" "+a).css("height",e.window-(e.header-n))):t(o).css("top",e.header):!1===s?(t(o).css("top",0),t(o+", "+o+" "+a).css("height",e.window)):t(o).css("top",e.header))},n._fixHeight=function(){var e=t(window).height(),i=t(l).outerHeight(),n=t(c).outerHeight();if(t("body").hasClass(u)){var s=e-i;(t("body").hasClass(C)||t("body").hasClass(y)||t("body").hasClass(b)||t("body").hasClass(w)||t("body").hasClass(x))&&"fixed"===t(c).css("position")&&(s=e-i-n),t(o+" "+a).css("height",s),"undefined"!=typeof t.fn.overlayScrollbars&&t(o+" "+a).overlayScrollbars({className:this._config.scrollbarTheme,sizeAutoCapable:!0,scrollbars:{autoHide:this._config.scrollbarAutoHide,clickScrolling:!0}})}},e._jQueryInterface=function(n){return this.each((function(){var s=t(this).data(i),o=t.extend({},E,t(this).data());if(s||(s=new e(this,o),t(this).data(i,s)),"undefined"===s[n])throw new Error(n+" is not a function");s[n]()}))},e}();return t(document).on("click",r,(function(e){e.preventDefault(),A._jQueryInterface.call(t(this),"toggle")})),t.fn[e]=A._jQueryInterface,t.fn[e].Constructor=A,t.fn[e].noConflict=function(){return t.fn[e]=n,A._jQueryInterface},A}(jQuery),i=function(t){var e="Layout",i=t.fn[e],n=".main-header",s=".main-sidebar",o=".main-sidebar .sidebar",a=".content-wrapper",r=".control-sidebar-content",l='[data-widget="control-sidebar"]',c=".main-footer",d='[data-widget="pushmenu"]',h=".login-box",f=".register-box",u="sidebar-focused",g="layout-fixed",p="control-sidebar-slide-open",_="control-sidebar-open",m={scrollbarTheme:"os-theme-light",scrollbarAutoHide:"l",panelAutoHeight:!0,loginRegisterAutoHeight:!0},v=function(){function e(t,e){this._config=e,this._element=t,this._init()}var i=e.prototype;return i.fixLayoutHeight=function(e){void 0===e&&(e=null);var i=0;(t("body").hasClass(p)||t("body").hasClass(_)||"control_sidebar"==e)&&(i=t(r).height());var s={window:t(window).height(),header:0!==t(n).length?t(n).outerHeight():0,footer:0!==t(c).length?t(c).outerHeight():0,sidebar:0!==t(o).length?t(o).height():0,control_sidebar:i},l=this._max(s),d=this._config.panelAutoHeight;!0===d&&(d=0),!1!==d&&(l==s.control_sidebar?t(a).css("min-height",l+d):l==s.window?t(a).css("min-height",l+d-s.header-s.footer):t(a).css("min-height",l+d-s.header)),t("body").hasClass(g)&&(!1!==d&&t(a).css("min-height",l+d-s.header-s.footer),"undefined"!=typeof t.fn.overlayScrollbars&&t(o).overlayScrollbars({className:this._config.scrollbarTheme,sizeAutoCapable:!0,scrollbars:{autoHide:this._config.scrollbarAutoHide,clickScrolling:!0}}))},i.fixLoginRegisterHeight=function(){if(0===t(h+", "+f).length)t("body, html").css("height","auto");else if(0!==t(h+", "+f).length){var e=t(h+", "+f).height();t("body").css("min-height")!==e&&t("body").css("min-height",e)}},i._init=function(){var e=this;this.fixLayoutHeight(),!0===this._config.loginRegisterAutoHeight?this.fixLoginRegisterHeight():Number.isInteger(this._config.loginRegisterAutoHeight)&&setInterval(this.fixLoginRegisterHeight,this._config.loginRegisterAutoHeight),t(o).on("collapsed.lte.treeview expanded.lte.treeview",(function(){e.fixLayoutHeight()})),t(d).on("collapsed.lte.pushmenu shown.lte.pushmenu",(function(){e.fixLayoutHeight()})),t(l).on("collapsed.lte.controlsidebar",(function(){e.fixLayoutHeight()})).on("expanded.lte.controlsidebar",(function(){e.fixLayoutHeight("control_sidebar")})),t(window).resize((function(){e.fixLayoutHeight()})),t("body.hold-transition").removeClass("hold-transition")},i._max=function(t){var e=0;return Object.keys(t).forEach((function(i){t[i]>e&&(e=t[i])})),e},e._jQueryInterface=function(i){return void 0===i&&(i=""),this.each((function(){var n=t(this).data("lte.layout"),s=t.extend({},m,t(this).data());n||(n=new e(t(this),s),t(this).data("lte.layout",n)),"init"===i||""===i?n._init():"fixLayoutHeight"!==i&&"fixLoginRegisterHeight"!==i||n[i]()}))},e}();return t(window).on("load",(function(){v._jQueryInterface.call(t("body"))})),t(o+" a").on("focusin",(function(){t(s).addClass(u)})),t(o+" a").on("focusout",(function(){t(s).removeClass(u)})),t.fn[e]=v._jQueryInterface,t.fn[e].Constructor=v,t.fn[e].noConflict=function(){return t.fn[e]=i,v._jQueryInterface},v}(jQuery),n=function(t){var e="PushMenu",i=".lte.pushmenu",n=t.fn[e],s={COLLAPSED:"collapsed"+i,SHOWN:"shown"+i},o={autoCollapseSize:992,enableRemember:!1,noTransitionAfterReload:!0},a='[data-widget="pushmenu"]',r="body",l="#sidebar-overlay",c=".wrapper",d="sidebar-collapse",h="sidebar-open",f="sidebar-closed",u=function(){function e(e,i){this._element=e,this._options=t.extend({},o,i),t(l).length||this._addOverlay(),this._init()}var n=e.prototype;return n.expand=function(){this._options.autoCollapseSize&&t(window).width()<=this._options.autoCollapseSize&&t(r).addClass(h),t(r).removeClass(d).removeClass(f),this._options.enableRemember&&localStorage.setItem("remember"+i,h);var e=t.Event(s.SHOWN);t(this._element).trigger(e)},n.collapse=function(){this._options.autoCollapseSize&&t(window).width()<=this._options.autoCollapseSize&&t(r).removeClass(h).addClass(f),t(r).addClass(d),this._options.enableRemember&&localStorage.setItem("remember"+i,d);var e=t.Event(s.COLLAPSED);t(this._element).trigger(e)},n.toggle=function(){t(r).hasClass(d)?this.expand():this.collapse()},n.autoCollapse=function(e){void 0===e&&(e=!1),this._options.autoCollapseSize&&(t(window).width()<=this._options.autoCollapseSize?t(r).hasClass(h)||this.collapse():1==e&&(t(r).hasClass(h)?t(r).removeClass(h):t(r).hasClass(f)&&this.expand()))},n.remember=function(){this._options.enableRemember&&(localStorage.getItem("remember"+i)==d?this._options.noTransitionAfterReload?t("body").addClass("hold-transition").addClass(d).delay(50).queue((function(){t(this).removeClass("hold-transition"),t(this).dequeue()})):t("body").addClass(d):this._options.noTransitionAfterReload?t("body").addClass("hold-transition").removeClass(d).delay(50).queue((function(){t(this).removeClass("hold-transition"),t(this).dequeue()})):t("body").removeClass(d))},n._init=function(){var e=this;this.remember(),this.autoCollapse(),t(window).resize((function(){e.autoCollapse(!0)}))},n._addOverlay=function(){var e=this,i=t("
",{id:"sidebar-overlay"});i.on("click",(function(){e.collapse()})),t(c).append(i)},e._jQueryInterface=function(i){return this.each((function(){var n=t(this).data("lte.pushmenu"),s=t.extend({},o,t(this).data());n||(n=new e(this,s),t(this).data("lte.pushmenu",n)),"string"==typeof i&&i.match(/collapse|expand|toggle/)&&n[i]()}))},e}();return t(document).on("click",a,(function(e){e.preventDefault();var i=e.currentTarget;"pushmenu"!==t(i).data("widget")&&(i=t(i).closest(a)),u._jQueryInterface.call(t(i),"toggle")})),t(window).on("load",(function(){u._jQueryInterface.call(t(a))})),t.fn[e]=u._jQueryInterface,t.fn[e].Constructor=u,t.fn[e].noConflict=function(){return t.fn[e]=n,u._jQueryInterface},u}(jQuery),s=function(t){var e="Treeview",i=t.fn[e],n={SELECTED:"selected.lte.treeview",EXPANDED:"expanded.lte.treeview",COLLAPSED:"collapsed.lte.treeview",LOAD_DATA_API:"load.lte.treeview"},s=".nav-item",o=".nav-treeview",a=".menu-open",r='[data-widget="treeview"]',l="menu-open",c="sidebar-collapse",d={trigger:r+" "+".nav-link",animationSpeed:300,accordion:!0,expandSidebar:!1,sidebarButtonSelector:'[data-widget="pushmenu"]'},h=function(){function e(t,e){this._config=e,this._element=t}var i=e.prototype;return i.init=function(){this._setupListeners()},i.expand=function(e,i){var s=this,r=t.Event(n.EXPANDED);if(this._config.accordion){var c=i.siblings(a).first(),d=c.find(o).first();this.collapse(d,c)}e.stop().slideDown(this._config.animationSpeed,(function(){i.addClass(l),t(s._element).trigger(r)})),this._config.expandSidebar&&this._expandSidebar()},i.collapse=function(e,i){var s=this,r=t.Event(n.COLLAPSED);e.stop().slideUp(this._config.animationSpeed,(function(){i.removeClass(l),t(s._element).trigger(r),e.find(a+" > "+o).slideUp(),e.find(a).removeClass(l)}))},i.toggle=function(e){var i=t(e.currentTarget),n=i.parent(),a=n.find("> "+o);if(a.is(o)||(n.is(s)||(a=n.parent().find("> "+o)),a.is(o))){e.preventDefault();var r=i.parents(s).first();r.hasClass(l)?this.collapse(t(a),r):this.expand(t(a),r)}},i._setupListeners=function(){var e=this;t(document).on("click",this._config.trigger,(function(t){e.toggle(t)}))},i._expandSidebar=function(){t("body").hasClass(c)&&t(this._config.sidebarButtonSelector).PushMenu("expand")},e._jQueryInterface=function(i){return this.each((function(){var n=t(this).data("lte.treeview"),s=t.extend({},d,t(this).data());n||(n=new e(t(this),s),t(this).data("lte.treeview",n)),"init"===i&&n[i]()}))},e}();return t(window).on(n.LOAD_DATA_API,(function(){t(r).each((function(){h._jQueryInterface.call(t(this),"init")}))})),t.fn[e]=h._jQueryInterface,t.fn[e].Constructor=h,t.fn[e].noConflict=function(){return t.fn[e]=i,h._jQueryInterface},h}(jQuery),o=function(t){var e="DirectChat",i=t.fn[e],n="toggled{EVENT_KEY}",s='[data-widget="chat-pane-toggle"]',o=".direct-chat",a="direct-chat-contacts-open",r=function(){function e(t,e){this._element=t}return e.prototype.toggle=function(){t(this._element).parents(o).first().toggleClass(a);var e=t.Event(n);t(this._element).trigger(e)},e._jQueryInterface=function(i){return this.each((function(){var n=t(this).data("lte.directchat");n||(n=new e(t(this)),t(this).data("lte.directchat",n)),n[i]()}))},e}();return t(document).on("click",s,(function(e){e&&e.preventDefault(),r._jQueryInterface.call(t(this),"toggle")})),t.fn[e]=r._jQueryInterface,t.fn[e].Constructor=r,t.fn[e].noConflict=function(){return t.fn[e]=i,r._jQueryInterface},r}(jQuery),a=function(t){var e="TodoList",i=t.fn[e],n='[data-widget="todo-list"]',s="done",o={onCheck:function(t){return t},onUnCheck:function(t){return t}},a=function(){function e(t,e){this._config=e,this._element=t,this._init()}var i=e.prototype;return i.toggle=function(e){e.parents("li").toggleClass(s),t(e).prop("checked")?this.check(e):this.unCheck(t(e))},i.check=function(t){this._config.onCheck.call(t)},i.unCheck=function(t){this._config.onUnCheck.call(t)},i._init=function(){var e=this;t(n).find("input:checkbox:checked").parents("li").toggleClass(s),t(n).on("change","input:checkbox",(function(i){e.toggle(t(i.target))}))},e._jQueryInterface=function(i){return this.each((function(){var n=t(this).data("lte.todolist"),s=t.extend({},o,t(this).data());n||(n=new e(t(this),s),t(this).data("lte.todolist",n)),"init"===i&&n[i]()}))},e}();return t(window).on("load",(function(){a._jQueryInterface.call(t(n))})),t.fn[e]=a._jQueryInterface,t.fn[e].Constructor=a,t.fn[e].noConflict=function(){return t.fn[e]=i,a._jQueryInterface},a}(jQuery),r=function(t){var e="CardWidget",i=".lte.cardwidget",n=t.fn[e],s={EXPANDED:"expanded"+i,COLLAPSED:"collapsed"+i,MAXIMIZED:"maximized"+i,MINIMIZED:"minimized"+i,REMOVED:"removed"+i},o="card",a="collapsed-card",r="collapsing-card",l="expanding-card",c="was-collapsed",d="maximized-card",h={DATA_REMOVE:'[data-card-widget="remove"]',DATA_COLLAPSE:'[data-card-widget="collapse"]',DATA_MAXIMIZE:'[data-card-widget="maximize"]',CARD:"."+o,CARD_HEADER:".card-header",CARD_BODY:".card-body",CARD_FOOTER:".card-footer",COLLAPSED:"."+a},f={animationSpeed:"normal",collapseTrigger:h.DATA_COLLAPSE,removeTrigger:h.DATA_REMOVE,maximizeTrigger:h.DATA_MAXIMIZE,collapseIcon:"fa-minus",expandIcon:"fa-plus",maximizeIcon:"fa-expand",minimizeIcon:"fa-compress"},u=function(){function e(e,i){this._element=e,this._parent=e.parents(h.CARD).first(),e.hasClass(o)&&(this._parent=e),this._settings=t.extend({},f,i)}var i=e.prototype;return i.collapse=function(){var e=this;this._parent.addClass(r).children(h.CARD_BODY+", "+h.CARD_FOOTER).slideUp(this._settings.animationSpeed,(function(){e._parent.addClass(a).removeClass(r)})),this._parent.find("> "+h.CARD_HEADER+" "+this._settings.collapseTrigger+" ."+this._settings.collapseIcon).addClass(this._settings.expandIcon).removeClass(this._settings.collapseIcon);var i=t.Event(s.COLLAPSED);this._element.trigger(i,this._parent)},i.expand=function(){var e=this;this._parent.addClass(l).children(h.CARD_BODY+", "+h.CARD_FOOTER).slideDown(this._settings.animationSpeed,(function(){e._parent.removeClass(a).removeClass(l)})),this._parent.find("> "+h.CARD_HEADER+" "+this._settings.collapseTrigger+" ."+this._settings.expandIcon).addClass(this._settings.collapseIcon).removeClass(this._settings.expandIcon);var i=t.Event(s.EXPANDED);this._element.trigger(i,this._parent)},i.remove=function(){this._parent.slideUp();var e=t.Event(s.REMOVED);this._element.trigger(e,this._parent)},i.toggle=function(){this._parent.hasClass(a)?this.expand():this.collapse()},i.maximize=function(){this._parent.find(this._settings.maximizeTrigger+" ."+this._settings.maximizeIcon).addClass(this._settings.minimizeIcon).removeClass(this._settings.maximizeIcon),this._parent.css({height:this._parent.height(),width:this._parent.width(),transition:"all .15s"}).delay(150).queue((function(){t(this).addClass(d),t("html").addClass(d),t(this).hasClass(a)&&t(this).addClass(c),t(this).dequeue()}));var e=t.Event(s.MAXIMIZED);this._element.trigger(e,this._parent)},i.minimize=function(){this._parent.find(this._settings.maximizeTrigger+" ."+this._settings.minimizeIcon).addClass(this._settings.maximizeIcon).removeClass(this._settings.minimizeIcon),this._parent.css("cssText","height:"+this._parent[0].style.height+" !important;width:"+this._parent[0].style.width+" !important; transition: all .15s;").delay(10).queue((function(){t(this).removeClass(d),t("html").removeClass(d),t(this).css({height:"inherit",width:"inherit"}),t(this).hasClass(c)&&t(this).removeClass(c),t(this).dequeue()}));var e=t.Event(s.MINIMIZED);this._element.trigger(e,this._parent)},i.toggleMaximize=function(){this._parent.hasClass(d)?this.minimize():this.maximize()},i._init=function(e){var i=this;this._parent=e,t(this).find(this._settings.collapseTrigger).click((function(){i.toggle()})),t(this).find(this._settings.maximizeTrigger).click((function(){i.toggleMaximize()})),t(this).find(this._settings.removeTrigger).click((function(){i.remove()}))},e._jQueryInterface=function(i){var n=t(this).data("lte.cardwidget"),s=t.extend({},f,t(this).data());n||(n=new e(t(this),s),t(this).data("lte.cardwidget","string"==typeof i?n:i)),"string"==typeof i&&i.match(/collapse|expand|remove|toggle|maximize|minimize|toggleMaximize/)?n[i]():"object"==typeof i&&n._init(t(this))},e}();return t(document).on("click",h.DATA_COLLAPSE,(function(e){e&&e.preventDefault(),u._jQueryInterface.call(t(this),"toggle")})),t(document).on("click",h.DATA_REMOVE,(function(e){e&&e.preventDefault(),u._jQueryInterface.call(t(this),"remove")})),t(document).on("click",h.DATA_MAXIMIZE,(function(e){e&&e.preventDefault(),u._jQueryInterface.call(t(this),"toggleMaximize")})),t.fn[e]=u._jQueryInterface,t.fn[e].Constructor=u,t.fn[e].noConflict=function(){return t.fn[e]=n,u._jQueryInterface},u}(jQuery),l=function(t){var e="CardRefresh",i=t.fn[e],n={LOADED:"loaded.lte.cardrefresh",OVERLAY_ADDED:"overlay.added.lte.cardrefresh",OVERLAY_REMOVED:"overlay.removed.lte.cardrefresh"},s="card",o={CARD:"."+s,DATA_REFRESH:'[data-card-widget="card-refresh"]'},a={source:"",sourceSelector:"",params:{},trigger:o.DATA_REFRESH,content:".card-body",loadInContent:!0,loadOnInit:!0,responseType:"",overlayTemplate:'
',onLoadStart:function(){},onLoadDone:function(t){return t}},r=function(){function e(e,i){if(this._element=e,this._parent=e.parents(o.CARD).first(),this._settings=t.extend({},a,i),this._overlay=t(this._settings.overlayTemplate),e.hasClass(s)&&(this._parent=e),""===this._settings.source)throw new Error("Source url was not defined. Please specify a url in your CardRefresh source option.")}var i=e.prototype;return i.load=function(){this._addOverlay(),this._settings.onLoadStart.call(t(this)),t.get(this._settings.source,this._settings.params,function(e){this._settings.loadInContent&&(""!=this._settings.sourceSelector&&(e=t(e).find(this._settings.sourceSelector).html()),this._parent.find(this._settings.content).html(e)),this._settings.onLoadDone.call(t(this),e),this._removeOverlay()}.bind(this),""!==this._settings.responseType&&this._settings.responseType);var e=t.Event(n.LOADED);t(this._element).trigger(e)},i._addOverlay=function(){this._parent.append(this._overlay);var e=t.Event(n.OVERLAY_ADDED);t(this._element).trigger(e)},i._removeOverlay=function(){this._parent.find(this._overlay).remove();var e=t.Event(n.OVERLAY_REMOVED);t(this._element).trigger(e)},i._init=function(e){var i=this;t(this).find(this._settings.trigger).on("click",(function(){i.load()})),this._settings.loadOnInit&&this.load()},e._jQueryInterface=function(i){var n=t(this).data("lte.cardrefresh"),s=t.extend({},a,t(this).data());n||(n=new e(t(this),s),t(this).data("lte.cardrefresh","string"==typeof i?n:i)),"string"==typeof i&&i.match(/load/)?n[i]():n._init(t(this))},e}();return t(document).on("click",o.DATA_REFRESH,(function(e){e&&e.preventDefault(),r._jQueryInterface.call(t(this),"load")})),t(document).ready((function(){t(o.DATA_REFRESH).each((function(){r._jQueryInterface.call(t(this))}))})),t.fn[e]=r._jQueryInterface,t.fn[e].Constructor=r,t.fn[e].noConflict=function(){return t.fn[e]=i,r._jQueryInterface},r}(jQuery),c=function(t){var e="Dropdown",i=t.fn[e],n=".navbar",s=".dropdown-menu",o=".dropdown-menu.show",a='[data-toggle="dropdown"]',r="dropdown-menu-right",l={},c=function(){function e(t,e){this._config=e,this._element=t}var i=e.prototype;return i.toggleSubmenu=function(){this._element.siblings().show().toggleClass("show"),this._element.next().hasClass("show")||this._element.parents(".dropdown-menu").first().find(".show").removeClass("show").hide(),this._element.parents("li.nav-item.dropdown.show").on("hidden.bs.dropdown",(function(e){t(".dropdown-submenu .show").removeClass("show").hide()}))},i.fixPosition=function(){var e=t(o);if(0!==e.length){e.hasClass(r)?(e.css("left","inherit"),e.css("right",0)):(e.css("left",0),e.css("right","inherit"));var i=e.offset(),n=e.width(),s=t(window).width()-i.left;i.left<0?(e.css("left","inherit"),e.css("right",i.left-5)):s');e.data("autohide",this._config.autohide),e.data("animation",this._config.fade),this._config.class&&e.addClass(this._config.class),this._config.delay&&500!=this._config.delay&&e.data("delay",this._config.delay);var i=t('
');if(null!=this._config.image){var s=t("").addClass("rounded mr-2").attr("src",this._config.image).attr("alt",this._config.imageAlt);null!=this._config.imageHeight&&s.height(this._config.imageHeight).width("auto"),i.append(s)}if(null!=this._config.icon&&i.append(t("").addClass("mr-2").addClass(this._config.icon)),null!=this._config.title&&i.append(t("").addClass("mr-auto").html(this._config.title)),null!=this._config.subtitle&&i.append(t("").html(this._config.subtitle)),1==this._config.close){var o=t('