From 63f714d5a78b765c117ebf6bbdfdbd748dd45644 Mon Sep 17 00:00:00 2001 From: George Halkiadakis Date: Thu, 4 May 2023 03:02:01 +0300 Subject: authentication; invitation; activation; base form setup --- core/classes/Database.php | 24 ++ core/classes/authentication/User.php | 3 - core/classes/session/DefaultSession.php | 1 + core/config/anom_settings.php | 2 - public/app/config/app_constants.php | 124 +++++----- public/app/controllers/Auth.php | 280 ++++++++------------- public/app/controllers/Cms.php | 259 ------------------- public/app/controllers/JsonToForm.php | 89 +++++-- public/app/controllers/Office.php | 424 ++++++++++++++++++++++++++++++++ public/app/extends/App_manager.php | 4 +- public/app/extends/App_user.php | 63 +++-- public/app/extends/Cache_service.php | 19 -- public/app/models/Access_model.php | 57 +++-- public/app/models/Cms_model.php | 314 ----------------------- public/app/models/Office_model.php | 314 +++++++++++++++++++++++ public/app/models/_info.md | 21 ++ public/app/routes/backend.php | 11 +- public/app/routes/frontend.php | 15 +- public/app/routes/user.php | 13 +- public/app/views/error/404.php | 12 +- public/app/views/templates/penalty.php | 12 +- public/app/views/user/invitation.php | 179 ++++++++++++++ public/app/views/user/registration.php | 121 --------- public/app/views/welcome.php | 15 +- public/assets/css/admin.css | 90 +++---- public/assets/css/class.css | 345 +------------------------- public/assets/js/invitation.md | 51 ++++ tests/dotnet-pass.php | 2 +- 28 files changed, 1390 insertions(+), 1474 deletions(-) delete mode 100644 public/app/controllers/Cms.php create mode 100644 public/app/controllers/Office.php delete mode 100644 public/app/models/Cms_model.php create mode 100644 public/app/models/Office_model.php create mode 100644 public/app/views/user/invitation.php delete mode 100644 public/app/views/user/registration.php create mode 100644 public/assets/js/invitation.md diff --git a/core/classes/Database.php b/core/classes/Database.php index 8cac479..0a8a10a 100644 --- a/core/classes/Database.php +++ b/core/classes/Database.php @@ -14,6 +14,8 @@ class Database { private $result = null; + private $rowCount; + /** METHODS * ------------------------------------------------------------------------- @@ -78,6 +80,25 @@ class Database { } + + /** rowCount + * + * returns the number of affected rows from the last modification query + * (that inludes any of INSERT, UPDATE or DELETE; not the SELECT ones) + * + * NOTE: + * originally in php PDO driver, rowCount is applied onto the stamement; + * here it is applied onto the actual object, making the call much easier + * + * @param void; + * @return (int) : number of affected rows + */ + public function rowCount() + { + return $this->rowCount; + } + + /** query * --- * set and execute a query safely; @@ -103,6 +124,9 @@ class Database { } + // keep rowCount (valid for INSERT, UPDATE, DELETE) + $this->rowCount = $stmt->rowCount(); + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); $this->result = $result; diff --git a/core/classes/authentication/User.php b/core/classes/authentication/User.php index babc7fd..f6508ff 100644 --- a/core/classes/authentication/User.php +++ b/core/classes/authentication/User.php @@ -20,9 +20,6 @@ class User implements UserInterface // @var array private $roles = []; - // @var array - private $privileges = []; - // @var bool private $enabled = true; diff --git a/core/classes/session/DefaultSession.php b/core/classes/session/DefaultSession.php index 079ab9d..819f00a 100644 --- a/core/classes/session/DefaultSession.php +++ b/core/classes/session/DefaultSession.php @@ -15,6 +15,7 @@ class DefaultSession implements SessionHandlerInterface { // (the default way) // and let the session* functions // do what they know + ini_set( "session.gc_maxlifetime", MAX_SESSION_LIFE ); session_name(SESSION_NAME); session_start(); } diff --git a/core/config/anom_settings.php b/core/config/anom_settings.php index 50056bf..6713771 100644 --- a/core/config/anom_settings.php +++ b/core/config/anom_settings.php @@ -41,8 +41,6 @@ define('APP_NAME', 'e-Classroom'); // Application Name define('APP_VERSION', 'v0.2'); // Application version -define('SESSION_NAME', 'clroom'); // Session Name - /** APPLICATION PATHS /////////////////////////////////////////////////////////// diff --git a/public/app/config/app_constants.php b/public/app/config/app_constants.php index 9dff566..262a727 100644 --- a/public/app/config/app_constants.php +++ b/public/app/config/app_constants.php @@ -25,6 +25,12 @@ if (file_exists("../core/auth/.env")) { define('SITE_TITLE', 'Classroom'); define('SITE_URL', 'http://localhost'); +// Session and cookie names +// --- -- -- - - - +define('SESSION_NAME', 'offticket'); // cookie for session (office ticket) +define('CONNECTION_COOKIE', 'con'); // cookie for connection +define('MAX_SESSION_LIFE', 2*60*60); // maximum session lifetime (2 hours) + // email setup // --- -- -- - - - // SMTP @@ -144,82 +150,110 @@ define('ACCOUNT_ACTIVATED_TITLE', 'Ο λογαριασμός σας έχει ε define('ACCOUNT_ACTIVATED_MESSAGE', 'Τώρα μπορείτε να συνδεθείτε στο σύστημα.'); define('NOT_VALID_ACTIVATION_TITLE', 'Σφάλμα!'); +define('NOT_VALID_ACTIVATION_MESSAGE', 'Ο λογαριασμός δεν έχει ενεργοποιηθεί. + Ξαναδοκιμάστε αργότερα κι αν το σφάλμα επιμείνει, επικοινωνήστε με την υπεύθυνη του προγράμμαρος.'); +// forms +// --- -- -- - - - - +// registration/activation form (from invitation) +// --- define('REGISTRATION_FORM', [ 'defaults' => [ 'outer_class' => 'col-12', 'inner_class' => 'form-control', - 'type' => 'text' + 'type' => 'text', + 'source' => '\app\controllers\User::current' ], 'form' => [ [ 'name' => 'first_name', 'label' => 'Όνομα', + 'value' => 'auto', 'attributes' => ['required'] ], [ 'name' => 'last_name', 'label' => 'Επίθετο', + 'value' => 'auto', 'attributes' => ['required'] ], [ 'name' => 'email', 'label' => 'e-mail', 'type' => 'email', + 'value' => 'auto', 'attributes' => ['required'] ], [ 'name' => 'father_name', 'label' => 'Πατρώνυμο', + 'value' => 'auto', 'attributes' => ['required'] ], [ 'name' => 'registration_number', 'label' => 'Αριθμός μητρώου', 'class' => 'col-8', + 'value' => 'auto', 'attributes' => ['required'] ], [ 'name' => 'sector', 'label' => 'Κλάδος / Ειδικότητα', + 'value' => 'auto', 'type' => 'select', - // 'source' => 'sectors', 'attributes' => ['required'], 'options' => [ - 'Π01.00 Θεολόγοι', - 'Π02.00 Φιλόλογοι', - 'Π04.01 Φυσικοί', - 'Π04.02 Χημικοί' + 'ΠΕ01 ΘΕΟΛΟΓΟΙ', + 'ΠΕ02 ΦΙΛΟΛΟΓΟΙ', + 'ΠΕ02.50 ΦΙΛΟΛΟΓΟΙ ΕΙΔΙΚΗΣ ΑΓΩΓΗΣ', + 'ΠΕ03 ΜΑΘΗΜΑΤΙΚΟΙ', + 'ΠΕ03.50 ΜΑΘΗΜΑΤΙΚΟΙ ΕΙΔΙΚΗΣ ΑΓΩΓΗΣ', + 'ΠΕ04.01 ΦΥΣΙΚΟΙ', + 'ΠΕ04.01.50 ΦΥΣΙΚΟΙ ΕΙΔΙΚΗΣ ΑΓΩΓΗΣ', + 'ΠΕ04.02 ΧΗΜΙΚΟΙ', + 'ΠΕ04.04 ΒΙΟΛΟΓΟΙ', + 'ΠΕ05 ΓΑΛΛΙΚΗΣ ΦΙΛΟΛΟΓΙΑΣ', + 'ΠΕ06 ΑΓΓΛΙΚΗΣ ΦΙΛΟΛΟΓΙΑΣ', + 'ΠΕ07 ΓΕΡΜΑΝΙΚΗΣ ΦΙΛΟΛΟΓΙΑΣ', + 'ΠΕ08 ΚΑΛΛΙΤΕΧΝΙΚΩΝ', + 'ΠΕ11 ΦΥΣΙΚΗΣ ΑΓΩΓΗΣ', + 'ΠΕ23-ΣΔΕΥ ΨΥΧΟΛΟΓΟΙ', + 'ΠΕ30-ΣΔΕΥ ΚΟΙΝΩΝΙΚΟΙ ΛΕΙΤΟΥΡΓΟΙ', + 'ΠΕ78 ΚΟΙΝΩΝΙΚΩΝ ΕΠΙΣΤΗΜΩΝ', + 'ΠΕ79.01 ΜΟΥΣΙΚΗΣ ΕΠΙΣΤΗΜΗΣ', + 'ΠΕ80 ΟΙΚΟΝΟΜΙΑΣ', + 'ΠΕ81 ΠΟΛ.ΜΗΧΑΝΙΚΩΝ-ΑΡΧΙΤΕΚΤΟΝΩΝ', + 'ΠΕ82 ΜΗΧΑΝΟΛΟΓΩΝ', + 'ΠΕ86 ΠΛΗΡΟΦΟΡΙΚΗΣ', + 'ΠΕ88.01 ΓΕΩΠΟΝΟΙ' ] ], [ 'name' => 'belonging_school', 'label' => 'Σχολείο τοποθέτησης', + 'value' => 'auto', 'attributes' => ['required'] ], - [ - 'name' => 'working_school', - 'label' => 'Σχολείο εργασίας', - 'attributes' => ['required'] - ], + // [ // working school = (obviously) is the current school + // 'name' => 'working_school', + // 'label' => 'Σχολείο εργασίας', + // 'attributes' => ['required'] + // ], [ 'name' => 'position', 'label' => 'Θέση', 'type' => 'select', + 'value' => 'auto', 'attributes' => ['required'], - 'options' => [ - 'Διευθυν-τής/τρια', - 'Υποδιευθυν-τής/τρια', - 'Μόνιμ-ος/η Καθηγη-τής/τρια', - 'Αναπληρω-τής/τρια', - ] + 'options' => [] ], [ 'name' => 'phone', 'label' => 'Τηλέφωνο', 'class' => 'col-8', + 'value' => 'auto', 'attributes' => ['required'] ], [ @@ -239,7 +273,8 @@ define('REGISTRATION_FORM', [ ] ]); - +// common requesy form (for any application) +// --- define('COMMON_REQUEST_FORM', [ 'defaults' => [ 'outer_class' => 'col-12', @@ -317,6 +352,8 @@ define('COMMON_REQUEST_FORM', [ ] ]); +// penalty form +// --- define('PENALTY_FORM', [ 'defaults' => [ @@ -382,6 +419,7 @@ define('PENALTY_FORM', [ [ 'name' => 'rapporteur', 'label' => 'εισηγητής', + 'type' => 'select', 'source' => '\app\extends\Cache_service::all_users', 'attributes' => ['required'] ], @@ -426,7 +464,7 @@ define('PENALTY_FORM', [ [ 'name' => 'president', 'label' => 'Πρόεδρος συνεδρίασης', - 'type' => 'text', + 'type' => 'select', 'source' => '\app\extends\Cache_service::all_users', 'attributes' => ['required'] ], @@ -435,51 +473,7 @@ define('PENALTY_FORM', [ 'label' => 'Μέλη', 'type' => 'select', 'attributes' => ['required', 'multiple'], - 'source' => '\app\extends\Cache_service::all_users', - 'options' => [ - 'Μαρία Χαλκιαδάκη', - 'Σπαγκοβαγγελοδημήτρης Νικόλαος', - 'Χατζηχριστοδούλου Παναγιώτης', - 'Μαρία Χαλκιά', - 'Σπανοβαγγελοδημήτρης Νικόλαος', - 'Χριστοδούλου Παναγιώτης', - 'Μαρίκα Χαλκιαδάκη', - 'Σπανακοβαγγελοδημήτρης Νικόλαος', - 'Χατζηχριστοδούλου Χριστόδουλος', - 'Αννέτα Καββαδία', - 'Γιώργος Καΐσας', - 'Διονύσης - Χαράλαμπος Καλαματιανός', - 'Ηλίας Καματερός', - 'Μαρία Κανελλοπούλου', - 'Ιωάννης Καραγιάννης', - 'Χρήστος Καραγιαννίδης', - 'Ευαγγελία Καρακώστα', - 'Απόστολος Καραναστάσης', - 'Ευφροσύνη Καρασαρλίδου', - 'Νίνα Κασιμάτη', - 'Αστέριος Καστόρης', - 'Βασιλική Κατριβάνου', - 'Γιώργος Κατρούγκαλος', - 'Χρυσούλα Κατσαβριά-Σιωροπούλου', - 'Μάριος Κάτσης', - 'Χαρά Καφαντάρη', - 'Σίμος Α. Κεδίκογλου', - 'Παναγιώτα Κοζομπόλη-Αμανατίδη', - 'Βασίλης Κόκκαλης', - 'Σταύρος Κοντονής', - 'Περικλής Κοροβέσης', - 'Νίκος Κοτζιάς', - 'Φώτης Κουβέλης', - 'Τάσος Κουράκης', - 'Παναγιώτης Κουρουμπλής', - 'Μιχαήλ Κριτσωτάκης', - 'Βασίλης Κυριακάκης', - 'Αγλαΐα Κυρίτση', - 'Γιώργος Κυρίτσης', - 'Πέτρος Κωνσταντινέας', - 'Ζωή Κωνσταντοπούλου', - 'Ηλίας Κωστοπαναγιώτου' - ] + 'source' => '\app\extends\Cache_service::all_users' ] ] ]); diff --git a/public/app/controllers/Auth.php b/public/app/controllers/Auth.php index 4b3dcfb..118b4d0 100644 --- a/public/app/controllers/Auth.php +++ b/public/app/controllers/Auth.php @@ -5,8 +5,9 @@ use Registry; use Render; // user classes and models -use app\extends\Classroom_user; -use app\extends\Classroom_manager; +use app\controllers\JsonToForm; +use app\extends\App_user; +use app\extends\App_manager; use app\models\Access_model; use app\extends\SendMail_service; @@ -37,50 +38,40 @@ class Auth { // user is valid; check user password // create a user object - $user = (new Classroom_user()) + $user = (new App_user()) ->setID($record['id']) + ->setSex( ($record['prefix'] == 'η') ? 2 : 1 ) ->setUserName($record['email']) ->setName($record['first_name'] .' '. $record['last_name']) ->setPassword($record['password']) + ->setRoles([ $record['role_id'] ]) // roles is an array ->setEnabled($record['active']); + // let user manager to validate user credentials - $userManager = new Classroom_manager(); + $userManager = new App_manager(); if ($userManager->isPasswordValid($user, $req->POST['password'])) { - // get user's security attributes - $attributes = Access_model::getUser($record['id']); - $roles = json_decode($attributes['Roles_json']); - $user - ->setRoles($roles) - ->setPrivileges( - array_merge( - json_decode($attributes['RootPrivileges_json']), - self::merge_lists_array( - json_decode($attributes['SubPrivileges_json']) - ) - ) - ); - // regeneration session ID (prevent session fixation) + session_unset(); // unset $_SESSION variable for the run-time + session_destroy(); // destroy session data in storage before continue + session_start(); session_regenerate_id(); + // set cookie for connected user setcookie( - 'cluser', + CONNECTION_COOKIE, 'connected;'. $user->getName(), - time()+60*60*8, // 8 hours + time()+60*60*10, // 10 hours '/' ); - - // check if admin (and redirect differently) - $is_admin = (!empty(array_intersect([1,2,3], $roles))); - + // login OK, set Token in session $userManager->createUserToken($user); return [ 'success' => true, - 'goto' => $is_admin ? '/admin/lessons' : '/user/profile', + 'goto' => '/admin/panel' ]; } else { @@ -89,33 +80,27 @@ class Auth { } - /** - * merges an array of lists to one list - */ - private static function merge_lists_array( $list ) - { - $current = []; - foreach($list as $sublist) { - $current = array_merge($current, $sublist); - } - return $current; - } - - /** activate - * resolves a call like: /account/activate?ticket=ca42d68cfba5fbbafeacc010b8e3a551 + * resolves call POST:/account/activate + * + * @param void : all parametres passed via request->POST */ public static function activate() { $req = Registry::get('REQUEST'); + // print_r($req->POST); die(); - // get the record of the target user - $check = Access_model::activate($req->GET['ticket']); + // create a salted password hash + $userManager = new App_manager(); + $password = $userManager->cryptPassword($req->POST['password']); - if ($check == true) { + // acivate target user and set password + $check = Access_model::activate_set_password($req->POST, $password); + + if ($check != 0) { Render::view('/error/general', [ 'title' => ACCOUNT_ACTIVATED_TITLE, - 'message' => ACCOUNT_ACTIVATED_MESSAGE + 'message' => ACCOUNT_ACTIVATED_MESSAGE . '
(msg code: '. $check .')' ]); } else { @@ -127,64 +112,72 @@ class Auth { } - /** register + + /** invitation + * + * setups and renders the form for a certain invitation + * + * NOTE: + * after form is submited, client calls Auth::activate() * - * Method for new user registration + * @param $id (string|MD5) : invitation code * */ - public static function register() + public static function invitation($id) { - $userManager = new Classroom_manager(); - $req = Registry::get('REQUEST'); + // get user from invitation number + $user_array = Registry::use('database')->query( + "SELECT * FROM user WHERE invitation = :id", + ['id' => $id] + )->getFirst(); + if ($user_array == false) { + Render::view('error/404', ['moto' => 'Δεν βρέθηκε η πρόσκληση']); + die(); + } + $user = json_decode( json_encode($user_array, JSON_UNESCAPED_UNICODE)); // user in json format - // create a salted password hash - $password = $userManager->cryptPassword($req->POST['password']); + // format form_setup to a json array + $form_setup = json_decode(json_encode(REGISTRATION_FORM, JSON_UNESCAPED_UNICODE)); - // echo $password; print_r($req->POST); die(); // OK! - - $user = (new Classroom_user()) - ->setUserName($req->POST['email']) - ->setName($req->POST['name'] .' '. $req->POST['surname']) - ->setPassword($password) - ->setRoles([ READER ]) // Role: authorized reader - ->setPrivileges([]); // none privilege until acount confirmation - - // create user record - $activation_code = Access_model::registerUser($req->POST, $password); - - // TODO: - // handle error on user registration - // ... - // - // if ($activatopn_code[] == -1) { - // return [ - // 'success' => false, - // 'message' => REGISTRATION_USER_EXISTS - // ]; - // } - - $send_mail = SendMail_service::send_activation_code([ - 'email' => $req->POST['email'], - 'name' => $req->POST['name'] .' '. $req->POST['surname'], - 'code' => $activation_code['activation'] - ]); + // get $key of position item inside the form_setup->form array + for($i=0; $i < sizeof($form_setup->form) ; $i++) { + if ($form_setup->form[$i]->name == 'position') { $key = $i; } + } - // Send replies - if ($send_mail) { - return [ - 'success' => true, - 'message' => REGISTRATION_SUCCESS + // prepare gendered options to position field + $positions = ($user->prefix != 'η') + ? [ + 'Διευθυντής', + 'Υποδιευθυντής', + 'Μόνιμος Καθηγητής', + 'Αναπληρωτής Καθηγητής' + ] + : [ + 'Διευθύντρια', + 'Υποδιευθύντρια', + 'Μόνιμη Καθηγήτρια', + 'Αναπληρώτρια Καθηγήτρια' ]; + $gendered_position = json_decode( json_encode( $positions, JSON_UNESCAPED_UNICODE )); - } else { - return [ - 'success' => false, - 'message' => 'error on sending email' - ]; - } + // attach gendered options + $form_setup->form[$key]->options = $gendered_position; + + // attach default values + $form_setup->defaults->values = $user; + + // get Form's HTML and Jsvascript + $form = JsonToForm::json_form($form_setup, [ + // pass invitation identity for security + ['name' => 'id', 'value' => $user->id], + ['name' => 'invitation', 'value' => $user->invitation] + + ]); + Render::view('user/invitation', ['form' => $form]); } + /** is_connected * checks if the user is connected * @@ -192,7 +185,7 @@ class Auth { */ public static function is_connected() { - $manager = new Classroom_manager(); + $manager = new App_manager(); if ($manager->hasUserToken()) { // user is connected; @@ -215,16 +208,19 @@ class Auth { */ public static function logout() { - $userManager = new Classroom_manager(); + $userManager = new App_manager(); $userManager->logout(); // regeneration session ID (prevent session fixation) + session_unset(); // unset $_SESSION variable for the run-time + session_destroy(); // destroy session data in storage before continue + session_start(); session_regenerate_id(); // remove user-conected cookie - if (isset($_COOKIE['cluser'])) { - unset($_COOKIE['cluser']); - setcookie('cluser', '', -1, '/'); + if (isset($_COOKIE[CONNECTION_COOKIE])) { + unset($_COOKIE[CONNECTION_COOKIE]); + setcookie(CONNECTION_COOKIE, '', -1, '/'); return true; } else { @@ -233,97 +229,27 @@ class Auth { } - - /** hasPermition( PERMIT ) - * - * checks if the user owns the specified permition - * to access the source + /** TODO: * */ - public static function hasPermition($permit = [0]) + public static function forgot_password() { - if (in_array(0, $permit)) { // permision 0 means public - return true; // permision 0 is always granted - } - - if ($user = self::is_connected() === false) { // if not connected - return false; // then no other permition is granted - } - - if ($user instanceof UserInterface) { - return ( !empty( array_intersect($permit, $user->getPrivileges()) ) ); - } } - /** isAuthenticated() - * - * chechs if the user's roles and permitions - * satisfy the specified requirements - * to access the source - * - * @param $requirements (array of rules-array) - * - * example: - * [ - * [ - * role => [2, 3] - * permition => ['10', '12', '18'] - * ], - * [ - * role => [1 , 4] - * ], - * [ - * permition => [ 3 ] - * ] - * ] - * - * defines (and parses to) a requirements rule of: - * [ - * user should be creator or editor - * _AND_ have permition 10 or 12 or 18 - * ] - * OR - * [ - * user should be an administrator or developer - * ] - * OR - * [ - * user should have permition #3 - * ] - * + /** TODO: * */ - public static function isAuthorized($requirements) - { - $authorized = false; - foreach($requirements as $required) { - - if (isset($required['role'])) { // if a role is required - if ( (self::isGranted($required['role'])) // authorize both role - && (self::hasPermition($required['permition'] ?? [ 0 ])) ) { // and permition - // $authorized = true; - return true; - } - - } else { // else, if not is not required - if (self::hasPermition($required['permition'] ?? [ 0 ])) { // authorize permition - // $authorized = true; - return true; - } - } - } - return $authorized; - } - - - public static function forgot_pass() + public static function validate_otp() { } - public static function validate_otp() + /** TODO: + * + */ + public static function reset_password() { } @@ -339,7 +265,7 @@ class Auth { */ public static function allowRoles($allowed) { - $manager = new Classroom_manager(); + $manager = new App_manager(); if ($manager->isGranted($allowed)) { // if valid, return true (continue) return true; @@ -361,21 +287,17 @@ class Auth { */ public static function hasValidRole($allowed) { - $manager = new Classroom_manager(); + $manager = new App_manager(); return ($manager->isGranted($allowed)); } public static function in_admin_group() { - $manager = new Classroom_manager(); + $manager = new App_manager(); return ($manager->isGranted([1, 2, 3])); } } - - -// NOTE: -// check: https://netcorecloud.com/tutorials/send-an-email-via-gmail-smtp-server-using-php/ \ No newline at end of file diff --git a/public/app/controllers/Cms.php b/public/app/controllers/Cms.php deleted file mode 100644 index 306bc88..0000000 --- a/public/app/controllers/Cms.php +++ /dev/null @@ -1,259 +0,0 @@ -GET['type']; // get media-type - $real_path = MEDIA_STORAGE_ROOT . $file_path; // construct real path - - if (!file_exists($real_path)) { - Render::view('error/404'); - - } else { - Render::file($real_path, $media_type); - } - - } else { - Render::view('error/404', [ - 'error_code' => 403, - 'moto' => 'Forbidden', - 'message' => '' - ]); - } - } - - - /** get_file_attributes - * - * returns attributes of a file - * (medias are proxied for speed optimization) - * - * @param $path (string) : file path - * @return $file attributes --or-- false - */ - private static function get_file_attributes($path) - { - $medias = Cache_service::files_attributes(); - - foreach($medias as $key => $medi) { - - if ($medi['path'] == $path) { - - return $medi; - } - } - - return false; - } - - - - ## COURSES - ## ------------------------------------------------------------------------- - - - /** course - * prepare and render the course view - * - * @param $id : course id - */ - public static function course($id) - { - $id = intval($id); // course id - - // collect all data needed for course view - // --- -- -- - - - - $cache = Cache_service::courses_struct(); - $tree = $cache['tree']; - $breadcrumbs = $cache['breadcrumbs']; - $lessons = Cms_model::lessons_of_course(intval($id)); - - // find parent_ids of current category (to open the menu tree) - // --- - $course_path = []; - foreach($breadcrumbs[$id]['parents'] as $key => $parent) { - $course_path[] = intval($parent['id']); - } - $course_path[] = $id; - - // then Render - // --- -- -- - - - - Render::view('templates/course', [ - 'id' => $id, - 'title' => $breadcrumbs[ $id ]['rec']['label'], - 'categories' => $tree, - 'breadcrumbs' => $breadcrumbs, - 'lessons' => $lessons, - 'course_path' => $course_path, - // needed by footer - 'entity' => Cache_service::pages_list() - ]); - } - - - - ## LESSONS - ## ------------------------------------------------------------------------- - - - - /** lesson - * - * check if user is authorized to view the content; - * if so, prepare and render the lesson view - * - * @param $id : lesson id - */ - public static function lesson($id) - { - $id = intval($id); // lesson id - - $lesson = Cms_model::lesson($id); // get lesson - $course_id = $lesson['course_id']; // get course id - $pri_id = $lesson['privilege_id']; // privilege needed - - - if (self::is_admin_or_permited($pri_id)) { - - // collect all data needed for course view - // --- -- -- - - - - $cache = Cache_service::courses_struct(); - $tree = $cache['tree']; - $breadcrumbs = $cache['breadcrumbs']; - - // find parent_ids of current category (to open the menu tree) - // --- - $course_path = []; - foreach($breadcrumbs[$course_id]['parents'] as $key => $parent) { - $course_path[] = intval($parent['id']); - } - $course_path[] = intval($course_id); - - // NOTE: CRITICAL: - // do not pass Class::method directly to the eported variables - // $entity = Cache_service::pages_list(); - - // var_dump($entity); die(); - - // then Render - // --- -- -- - - - - Render::view('templates/lesson', [ - // main content - 'id' => $id, - 'course_id' => $course_id, - 'title' => $lesson['title'], - 'lesson' => $lesson, - // needed for side panel and breadcrunbs - 'categories' => $tree, - 'breadcrumbs' => $breadcrumbs, - 'course_path' => $course_path, - // needed by footer - 'entity' => Cache_service::pages_list() - ]); - - } else { // user is not authorized - Render::view('error/general', [ - 'title' => 'Δεν έχετε πρόσβαση', - 'message' => 'Θα πρέπει να αγοράσετε το πακέτο πρόσβασης ' - . $pri_id - .' για να δείτε το περιεχόμενο! -

- Αγόρασε τώρα το ' - ]); - } - - } - - - ## PAGES - ## ------------------------------------------------------------------------- - - - /** lesson - * - * check if user is authorized to view the content; - * if so, prepare and render the lesson view - * - * @param $id : lesson id - */ - public static function page($id) - { - $id = intval($id); // lesson id - - $pages = Cache_service::pages_list(); - $page = $pages[$id]; - - // then Render - // --- -- -- - - - - Render::view('templates/page', [ - // main content - 'id' => $id, - 'page' => $page, - // needed by footer - 'entity' => $pages - ]); - - } - -} diff --git a/public/app/controllers/JsonToForm.php b/public/app/controllers/JsonToForm.php index 1b05af7..5df650d 100644 --- a/public/app/controllers/JsonToForm.php +++ b/public/app/controllers/JsonToForm.php @@ -1,4 +1,5 @@ $len) ? mb_substr($str, 0, $len-1) ."…" : $str; } - - public static function make_a_form($form) + /** json_form + * + * construct a form (html, javasctipt) + * from a json designer + * + */ + public static function json_form($formJson, $require_identity = []) { - $formJson = json_decode(json_encode($form)); + // $formJson = json_decode(json_encode($form)); - $default_outer = $form->defaults->outer_class ?? ''; - $default_inner = $form->defaults->inner_class ?? ''; - $default_type = $form->defaults->type ?? 'text'; + $default_outer = $formJson->defaults->outer_class ?? ''; + $default_inner = $formJson->defaults->inner_class ?? ''; + $default_type = $formJson->defaults->type ?? 'text'; + $default_values = $formJson->defaults->values ?? ((object) ['nothing' => true]); // TODO handle $form->defaults->source; @@ -180,8 +187,15 @@ class JsonToForm $initSelectsJS = ""; // js to initialize select fields (single or multiple) + $identity = ""; // construct required identity hidden fields + foreach ($require_identity as $group) { + $identity .= " + "; + } - $html = " + // now constuct the form body + $html = "{$identity}
"; @@ -191,15 +205,22 @@ class JsonToForm $type = $field->type ?? $default_type; $class = $field->class ?? ""; $label = $field->label; - $name = $field->name ?? "$field->label"; - - // TODO: auto value - + $name = $field->name ?? $field->label; + + // handle value assignment + if (isset($field->value)) { // if value property is set + $set_value = true; // (flag: value seted) + $value = (($field->value == 'auto') && isset($default_values->$name)) + ? $default_values->$name // set auto value + : $field->value; // or other set-value + } else { + $set_value = false; + } + // print_r([ $set_value, $name, ($default_values->$name ?? 'none') ]); + $appendKey = in_array('append-key', $attributes) ? true : false; // append key (for selects) - $required = in_array('required', $attributes) ? 'required' : ''; // required + $required = in_array('required', $attributes) ? '' : ''; // required $asterisk = in_array('required', $attributes) ? '*' : ''; // asterisk in label if required - - $html .= "
@@ -220,6 +241,15 @@ class JsonToForm var {$name} = $('#{$name}'); {$name}.select2({ width: '100%', placeholde: '{$label}' });"; + if ($set_value) { // if default value is set + $initSelectsJS .= " + select2_set_multi_text( {$name} , {$value} );"; + + } else { + $initSelectsJS .= " + {$name}.val(null).trigger('change');"; + } + // prepare check if empty field $checkFilledJS .= " if (getValues({$name}) =='') { empty += '{$label} {$asterisk}
'; } @@ -234,8 +264,16 @@ class JsonToForm // prepare initialization of select2 (single) $initSelectsJS .= " var {$name} = $('#{$name}'); - {$name}.select2({ }); - {$name}.val(null).trigger('change')"; + {$name}.select2();"; + + if ($set_value) { // if default value is set + $initSelectsJS .= " + select2_set_text( {$name} , '{$value}' );"; + + } else { + $initSelectsJS .= " + {$name}.val(null).trigger('change');"; + } // prepare check if empty field $checkFilledJS .= " @@ -259,8 +297,10 @@ class JsonToForm case 'text': + $def_value = ($set_value) ? "value='{$value}'" : "value=''"; + $html .= " - "; + "; $checkFilledJS = " if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}
'; } @@ -271,6 +311,8 @@ class JsonToForm case 'password': + $def_value = ($set_value) ? "value='{$value}'" : "value=''"; + $html .= " "; @@ -283,8 +325,10 @@ class JsonToForm case 'integer': + $def_value = ($set_value) ? "value='{$value}'" : "value=''"; + $html .= " - "; + "; $checkFilledJS .= " if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}
'; } @@ -295,8 +339,10 @@ class JsonToForm case 'textarea': + $def_value = ($set_value) ? "{$value}" : ""; + $html .= " - "; + "; $checkFilledJS .= " if ($('textarea[name={$name}]').val() =='') { empty += '{$label} {$asterisk}
'; } @@ -319,8 +365,10 @@ class JsonToForm case 'email': + $def_value = ($set_value) ? "value='{$value}'" : "value=''"; + $html .= " - "; + "; $checkFilledJS .= " if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}
'; } @@ -332,7 +380,6 @@ class JsonToForm default: // label, acts as common text //$html .= "