hanze/iwa-panda2

user management (90f1a83a9b95b553791fdea99f069ffdaafc529f)
Repositories | README.md

commit 90f1a83a9b95b553791fdea99f069ffdaafc529f
parent 900f8c0467409af4175419c1ac70a9e6af2495ad
Author: Gerco van Woudenbergh <[email protected]>
Date:   Mon,  3 Jul 2023 15:45:21 +0200

user management

Diffstat:
AController/Templates.php162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MLollipop/DatabaseObject.php3+++
MModel/Permission.php23+++++++++++++++++++++--
MModel/PermissionUser.php31+++++++++++++++++++++++++++++++
MModel/User.php136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mindex.php20++++++++++++++++++++
Arouting/user.php121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mviews/dashboard.html1+
Mviews/hdata.html1+
Mviews/map.html1+
Aviews/user.html32++++++++++++++++++++++++++++++++
11 files changed, 529 insertions(+), 2 deletions(-)

diff --git a/Controller/Templates.php b/Controller/Templates.php @@ -0,0 +1,162 @@ +<?php + +namespace Controller { + + /// Controller\Templates is a utility class for creating HTML-forms and other constructs + class Templates + { + private \Lollipop\SQLDatabase $db; + private \Lollipop\DatabaseObject $table; + private string $schema = 'panda'; + private string $table_name; + + public function __construct(\Lollipop\SQLDatabase $db, \Lollipop\DatabaseObject $table) + { + $this->db = $db; + $this->table = $table; + $this->table_name = $table::class; + } + + public function form(string $action, array $data = [], array $response = []): string + { + /*auto-increment fields are automatically hidden*/ + $form_type = "Add"; + $form = '<form method="POST" action="'. $action . '">'; + foreach($this->table->get_col_names_ai() as $col) { + if($data == []) { + $value = '-1'; + } else { + if(in_array($col, array_keys($data))) { + $value = $data[$col]; + } + $form_type = "Update"; + } + $form .= '<input type="hidden" name="' . $col . '" value="' . $value . '">'; + } + $form .= '<input type="hidden" name="form_type" value="' . $form_type . '">'; + foreach($this->table->get_col_names_no_ai() as $col) { + if($data == []) { + $value = ''; + } else { + if(in_array($col, array_keys($data))) { + $value = $data[$col]; + } + } + $form .= '<input type="text" name="' . $col . '" placeholder="' . $col . '" value="' . $value . '">'; + $miss_key = 'missing_'.$col; + if(array_key_exists($miss_key, $response)) { + $form .= '<div class="form-response"><p style="color:red;"> col: '. $col . ' cannot be empty</p></div>'; + } + } + $form .=' + <input type="submit" value="'. $form_type .'"> + </form>'; + + return $form; + } + + public function form_v2(string $action, array $values = [], array $extra = [], array $response = []): string + { + /*auto-increment fields are automatically hidden*/ + if(sizeof($values) == 0) { + $form_type = "Add"; + } else { + $form_type = "Update"; + } + $form = '<h1>'. $form_type .' '. $this->table->get_table() .'</h1> + <a href="/'. $this->table->get_table() .'">New</a>'; + $form .= '<form method="POST" action="'. $action . '">'; + foreach($this->table->get_col_info() as $col => $info) { + if(isset($info["extra"]) && $info["extra"] == "auto_increment") { + $form .= '<input type="hidden" name="' . $col . '" placeholder="' . $col . '" value="'; + if(isset($values[$col])) { + $form .= $values[$col]; + } + $form .= '">'; + } elseif(isset($info["extra"]) && $info["extra"] == "password") { + $form .= '<input type="password" name="' . $col . '" placeholder="' . $col . '">'; + } elseif(isset($info["input_type"])) { + $form .= '<input type="'. $info["input_type"] .'" name="' . $col . '" placeholder="' . $col . '" value="'; + if(isset($values[$col])) { + $form .= $values[$col]; + } + $form .= '">'; + } + $miss_key = 'missing_'.$col; + if(array_key_exists($miss_key, $response)) { + $form .= '<div class="form-response"><p style="color:red;"> col: '. $col . ' cannot be empty</p></div>'; + } + } + foreach($extra as $html) { + $form.= $html; + } + $form .= '<input type="hidden" name="form_type" " value="' . $form_type . '">'; + $form .=' + <input type="submit" value="'. $form_type .'"> + </form>'; + return $form; + } + + public function search_form(string $action): string + { + return ' + <form method="POST" action="'. $action . '"> + <input type="text" name="search" placeholder="Search..."> + <input type="submit" value="Search"> + </form>'; + } + + public function crud_table(string $action, string $search = "", string $search_key = "", \Model\PermissionUser $permissionUser = null): string + { + if($search == "") { + $search = "%"; + } else { + $search = "%$search%"; + } + $table = "<table> <thead> <tr>"; + foreach($this->table->get_column_names() as $column) { + $table .= "<th>$column</th>"; + } + $table .= "<th>Alter</th> <th>Delete</th>"; + if($permissionUser != null) { + $table .= "<th>user permissions</th>"; + } + $table .= "</tr> </thead>"; + + $objs = $this->db->all_where($this->table_name, [$search_key => $search]); + $table .= "<tbody>"; + foreach($objs as $obj) { + $table .= "<tr>"; + $col_names = $obj->get_column_names(); + foreach($col_names as $col) { + $table .= '<td>'; + if($col == "email" || $col == "name" || $col == "course" || $col == "exam") { + $table .= '<a href="/'.$this->table->get_table().'/' .$obj->{$col}.'">'. $obj->{$col} . '</a></td>'; + } else { + $table .= $obj->{$col} . '</td>'; + } + } + $table .= ' + <td> + <a class="edit" href="' . $action . '/'. $obj->{$this->table->get_primary()} .'/edit/">Edit</a> + </td> + <td> + <a class="delete" href="' . $action . '/'. $obj->{$this->table->get_primary()} .'/delete/">Delete</a> + </td> + <td>'; + if($permissionUser != null) { + foreach($this->db->all_where(\Model\PermissionUser::class, [$permissionUser->get_primary() => $obj->{$this->table->get_primary()}]) as $perm) { + $table .= $perm->id . ' '; + } + } + $table .= '</td> </tr>'; + } + + $table .= " + </tbody> + </table>"; + return $table; + } + + } +} diff --git a/Lollipop/DatabaseObject.php b/Lollipop/DatabaseObject.php @@ -13,16 +13,19 @@ namespace Lollipop { protected SQLDatabase $db; protected array $data = []; protected array $changed_keys = []; + private string $schema; public function __construct(SQLDatabase $db) { $this->db = $db; $this->primary = $this->get_primary(); $this->table = $this->get_table(); + $this->schema = $this->get_schema(); } abstract public static function get_primary(): string; abstract public static function get_table(): string; + abstract public static function get_schema(): string; /// setData is to bulk-set the row instead of one-for-one public function setData($data) diff --git a/Model/Permission.php b/Model/Permission.php @@ -1,6 +1,6 @@ <?php -namespace Model{ +namespace Model { class Permission extends \Lollipop\DatabaseObject { public static function get_table(): string @@ -10,7 +10,26 @@ namespace Model{ public static function get_primary(): string { - return 'id'; + return "id"; + } + public static function get_schema(): string + { + return "panda"; + } + public function get_checkboxes(): array + { + $all_permissions = $this->db->all($this::class); + $html = "<div class='check_this_box'>"; + foreach($all_permissions as $permission) { + $html .= '<input type="checkbox" id="'. $permission->name .'" name="permissions[]" value="'. $permission->id .'"'; + if($permission->id == 0) { + $html .= ' checked'; + } + $html .= '>'; + $html .= '<label for="'. $permission->name .'">'. $permission->name .'</label>'; + } + $html .= "</div>"; + return [0 => $html]; } } } diff --git a/Model/PermissionUser.php b/Model/PermissionUser.php @@ -12,5 +12,36 @@ namespace Model { { return 'email'; } + public static function get_schema(): string + { + return "panda"; + } + public function add_permissions(User $user): bool + { + if(array_key_exists('permissions', $_POST)) { + foreach($_POST['permissions'] as $permission) { + $this->{$user->get_primary()} = $user->{$user->get_primary()}; + $this->id_permission = $permission; + $this->add(); + } + return true; + } + return false; + } + public function update_permissions(User $user): bool + { + foreach($this->db->all_where(PermissionUser::class, [$this->get_primary() => $_POST[$this->get_primary()]]) as $permission) { + $permission->delete(); + } + if(array_key_exists('permissions', $_POST)) { + foreach($_POST['permissions'] as $permission) { + $this->{$user->get_primary()} = $user->{$user->get_primary()}; + $this->id_permission = $permission; + $this->add(); + } + return true; + } + return false; + } } } diff --git a/Model/User.php b/Model/User.php @@ -12,5 +12,141 @@ namespace Model { { return "email"; } + + public static function get_password_field(): string + { + return "password"; + } + public static function get_schema(): string + { + return "panda"; + } + + public function login_fields(): string + { + $html = ""; + $html .= '<input type="text" name="' . $this->get_primary(). '" placeholder="' . $this->get_primary() . '">'; + $html .= '<input type="password" name="' . $this->get_password_field() . '" placeholder="password">'; + return $html; + } + + public function all_fields(array $res = []): string + { + $html = ""; + foreach($this->column_names as $field) { + if($field == $this->get_password_field()) { + $html .= '<input type="password" name="' . $field . '" placeholder="' . $field . '">'; + } else { + $html .= '<input type="text" name="' . $field . '" placeholder="' . $field . '">'; + } + $miss_key = 'missing_'.$field; + if(array_key_exists($miss_key, $res)) { + $html .= '<div class="form-response"><p style="color:red;"> Field: '. $field . ' cannot be empty</p></div>'; + } + } + return $html; + } + + public function login(): array + { + if([$this->get_primary() != "" && !$this->get_password_field() == ""]) { + return $this->authenticate(); + } else { + return ["response" => ""]; + } + } + public function authenticate(): array + //this function return true when user is autheticated uses set_globals to set $_SESSION variables + { + //check if the email exists in db + if(!$this->load($_POST[$this->get_primary()])) { + //email does not exist + return ["response" => "{$this->get_primary()}: {$_POST[$this->get_primary()]} does not exists in db"]; + } else { + if(password_verify($_POST[$this->get_password_field()], $this->{$this->get_password_field()})) { + //authenticated -> set $_SESSION variables + $this->set_globals(); + return []; + } else { + //password did not match + return ["response" => "incorrect password"]; + } + } + } + + private function set_globals() + //this function sets Session variables + { + $user_permissions = []; + //foreach field in database which is not password add to session + foreach($this->getData() as $key => $data) { + if($key != $this->get_password_field()) { + $_SESSION[$key] = $data; + } + } + //get permissions form db and set sessions_permissions + $p = $this->db->all_where(PermissionUser::class, [$this->get_primary() => $this->{$this->get_primary()}]); + foreach($p as $permission) { + $user_permissions[] = $permission->id; + } + $_SESSION['user_permissions'] = $user_permissions; + } + + public function add_user(): array + { + $missing_fields = \Lollipop\Utils::missing_fields($this->notNullable()); + + if(sizeof($missing_fields) == 0) { + return $this->add_data_db(); + } else { + return $missing_fields; + } + } + + private function add_data_db(): array + { + $user_credentials = []; + $response["success"] = false; + if($this->load($_POST[$this->get_primary()])) { + $response["response"] = "<p style=\"color:red;\">this email address is already taken: {$_POST[$this->get_primary()]} </p>"; + return $response; + } else { + if($_POST[$this->get_password_field()]) { + $_POST[$this->get_password_field()] = password_hash($_POST[$this->get_password_field()], PASSWORD_DEFAULT); + } + foreach($this->get_col_names_no_ai() as $col) { + if($_POST[$col] != "") { + $this->$col = $_POST[$col]; + $user_credentials[$col] = $_POST[$col]; + } + } + if($this->add()) { + $response["response"] = "<p style=\"color:green;\">succes</p>"; + $response += $user_credentials; + $response["success"] = true; + return $response; + } else { + $response["response"] = "<p style=\"color:red;\">could not add user to database</p>"; + return $response; + } + } + } + public function update_user(): bool + { + $missing_fields = \Lollipop\Utils::missing_fields_sans_pw($this->notNullable()); + if(sizeof($missing_fields) == 0) { + foreach($_POST as $key => $post) { + if(in_array($key, $this->get_column_names())) { + if($key == $this->get_password_field()) { + $this->{$key} = password_hash($_POST[$key], PASSWORD_DEFAULT); + } else { + $this->{$key} = $post; + } + } + } + return $this->save(); + } + return false; + } } } diff --git a/index.php b/index.php @@ -4,6 +4,8 @@ require_once "utils/autoloader.php"; require_once "routing/login.php"; require_once "routing/user_add.php"; +require_once "routing/user.php"; +$db = new Lollipop\SQLDatabase("86.92.67.21", "friedel", "hailiwa", "panda"); session_start(); @@ -14,6 +16,11 @@ $router = new Lollipop\Router($templater); $router->addRoute(["GET"], "/", "views/login.html"); $router->addRoute(["POST"], "/login", $login); +//css +$router->addRoute(["GET"], "css/dashboard.css", "css/dashboard.css"); +$router->addRoute(["GET"], "css/hdata.css", "css/hdata.css"); +$router->addRoute(["GET"], "css/login.css", "css/login.css"); +$router->addRoute(["GET"], "css/map.css", "css/map.css"); //logout $router->addRoute(["POST", "GET"], "/logout", $logout); @@ -104,6 +111,19 @@ if(isset($_SESSION['user_permissions']) && in_array(1, $_SESSION['user_permissio return "views/hdata.html"; }); + + $router->addRoute(["GET"], "/user", $user_get); + + $router->addRoute(["POST"], "/user", $user_post); + + $router->addRoute(["GET"], "/user/search/:search_query", $user_query); + + $router->addRoute(["POST"], "/user/search", $user_search); + + $router->addRoute(["GET"], "/user/:primary_key/edit", $user_edit); + + $router->addRoute(["GET"], "/user/:primary_key/delete", $user_delete); + } // static files // diff --git a/routing/user.php b/routing/user.php @@ -0,0 +1,120 @@ +<?php +$user_get = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $permissions = $db->get(Model\Permission::class); + $permission_user = $db->get(Model\PermissionUser::class); + $vars += get_vars($user, "/user", "/user/search", "", "email", [], $permissions->get_checkboxes(), $permission_user); + return "views/user.html"; +}; + +$user_post = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $permissions = $db->get(Model\Permission::class); + $permission_user = $db->get(Model\PermissionUser::class); + + if(isset($_POST["form_type"])) { + if($_POST["form_type"] == 'Add') { + if($user->add_user() && $permission_user->add_permissions($user)) { + $vars["response"] = 'succesfully added: ' . $_POST["email"]; + } + } elseif($_POST["form_type"] == 'Update') { + if($user->update_user() && $permission_user->update_permissions($user)) { + $vars["response"] = 'succesfully updated: ' . $_POST["email"]; + } else { + echo"something went wrong"; + } + } + } + $vars += get_vars($user, "/user", "/user/search", "", "email", [], $permissions->get_checkboxes(), $permission_user); + return "views/user.html"; +}; + +$user_query = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $permissions = $db->get(Model\Permission::class); + $permission_user = $db->get(Model\PermissionUser::class); + $query = '%' . $vars['search_query'] . '%'; + $vars += get_vars($user, "/user", "/user/search", $query, "email", [], $permissions->get_checkboxes(), $permission_user); + return "views/user.html"; +}; + +$user_search = function (&$vars) { + if(isset($_POST['search'])) { + if($_POST['search'] == "") { + $search = "%"; + } else { + $search = $_POST['search']; + } + $header = '/user/search/' . $search; + header('Location: ' . $header); + } else { + echo "wtF?"; + var_dump($_POST); + } +}; + +$user_edit = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $permissions = $db->get(Model\Permission::class); + $permission_user = $db->get(Model\PermissionUser::class); + $templates = new controller\templates($db, $user); + $data = []; + $user->load($vars["primary_key"]); + foreach($user->getData() as $key => $col) { + $data[$key] = $col; + } + $vars += get_vars($user, "/user", "/user/search", "", "email", $data, $permissions->get_checkboxes(), $permission_user); + return "views/user.html"; +}; + +$user_delete = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $permissions = $db->get(Model\Permission::class); + + $permission_user = $db->get(Model\PermissionUser::class); + $user->load($vars["primary_key"]); + $user->delete(); + $vars += get_vars($user, "/user", "/user/search", "", "email", $permissions->get_checkboxes(), [], $permission_user); + return "views/user.html"; +}; + +$user_page = function (&$vars) { + global $db; + $user = $db->get(Model\User::class); + $exam = $db->get(Model\Exam::class); + $user->load($vars['primary_key']); + $data = $user->getData(); + if(in_array(3, $_SESSION['user_permissions'])) { + foreach($data as $key => $d) { + $vars['user_data'] .= "<p>your $key = $d<p><br>"; + } + } elseif($vars['primary_key'] == $_SESSION['email']) { + foreach($data as $key => $d) { + $vars['user_data'] .= "<p>your $key = $d<p><br>"; + } + $vars['user_data'] .= "<h1>your grades</h1><br>"; + foreach($db->all_where(Model\Grade::class, ['email' => $vars['primary_key']]) as $grade) { + $exam->load($grade->exam); + $exam_name =$exam->name; + $vars['user_data'] .= "<p>your grade for $exam_name = $grade->grade </p><br>"; + } + } + return "views/user_page.html"; +}; +function get_vars(Lollipop\DatabaseObject $table, string $action, string $search_action, string $search_string, string $search_key, array $form_data = [], array $extra = [], Model\PermissionUser $permissionUser = null): array +{ + global $db; + $templates = new Controller\Templates($db, $table); + + $array = []; + $array["form"] = $templates->form_v2($action, $form_data, $extra); + $array["search"] = $templates->search_form($search_action); + $array["table"] = $templates->crud_table($action, $search_string, $search_key, $permissionUser); + $array['first_name'] = $_SESSION['first_name']; + return $array; +} +\ No newline at end of file diff --git a/views/dashboard.html b/views/dashboard.html @@ -18,6 +18,7 @@ <li><a href="#" class="active">Dashboard</a></li> <li><a href="/hdata">Historical Data</a></li> <li><a href="/map">Map</a></li> + <li><a href="/user">User</a></li> <li><a href="/logout">Logout</a></li> </ul> </nav> diff --git a/views/hdata.html b/views/hdata.html @@ -17,6 +17,7 @@ <li><a href="/dashboard">Dashboard</a></li> <li><a href="#" class="active">Historical Data</a></li> <li><a href="/map">Map</a></li> + <li><a href="/user">User</a></li> <li><a href="/logout">Logout</a></li> </ul> </nav> diff --git a/views/map.html b/views/map.html @@ -18,6 +18,7 @@ <li><a href="/dashboard">Dashboard</a></li> <li><a href="/hdata">Historical Data</a></li> <li><a href="#" class="active">Map</a></li> + <li><a href="/user">User</a></li> <li><a href="/logout">Logout</a></li> </ul> </nav> diff --git a/views/user.html b/views/user.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html lang="eng"> + <title>Add User</title> + <link rel="stylesheet" href="/css/login.css"> + <meta name="viewport" content="width=device-width, initial-scale=1" /> +</head> +<body> + <!--NAVBAR--> + <nav class="navbar"> + <ul> + <li><a href="/dashboard" class="a-small-logo"><IMG class="img-small-logo" SRC="/img/small_logo.png"></a></li> + <li><a href="/dashboard" class="a-big-logo"><IMG class="img-big-logo" SRC="/img/big-logo.png"></a></li> + <li><a href="#" class="active">Dashboard</a></li> + <li><a href="/hdata">Historical Data</a></li> + <li><a href="/map">Map</a></li> + <li><a href="/user">User</a></li> + <li><a href="/logout">Logout</a></li> + </ul> + </nav> + <div class ="card"> + {{$form}} + {{$response}} + </div> + <div class="card"> + {{$search}} + </div> + <div class ="form-group"> + {{$table}} + </div> +</body> +</html> +\ No newline at end of file