summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
Diffstat (limited to 'public')
-rw-r--r--public/app/config/app_constants.php124
-rw-r--r--public/app/controllers/Auth.php280
-rw-r--r--public/app/controllers/Cms.php259
-rw-r--r--public/app/controllers/JsonToForm.php89
-rw-r--r--public/app/controllers/Office.php424
-rw-r--r--public/app/extends/App_manager.php4
-rw-r--r--public/app/extends/App_user.php63
-rw-r--r--public/app/extends/Cache_service.php19
-rw-r--r--public/app/models/Access_model.php57
-rw-r--r--public/app/models/Office_model.php (renamed from public/app/models/Cms_model.php)0
-rw-r--r--public/app/models/_info.md21
-rw-r--r--public/app/routes/backend.php11
-rw-r--r--public/app/routes/frontend.php15
-rw-r--r--public/app/routes/user.php13
-rw-r--r--public/app/views/error/404.php12
-rw-r--r--public/app/views/templates/penalty.php12
-rw-r--r--public/app/views/user/invitation.php (renamed from public/app/views/user/registration.php)96
-rw-r--r--public/app/views/welcome.php15
-rw-r--r--public/assets/css/admin.css90
-rw-r--r--public/assets/css/class.css345
-rw-r--r--public/assets/js/invitation.md51
21 files changed, 948 insertions, 1052 deletions
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', 'Τώρα μπορείτε να
<a href="/login">συνδεθείτε στο σύστημα</a>.');
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 . '<br>(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 @@
-<?php
-
-namespace app\controllers;
-
-use Registry;
-use Render;
-use app\controllers\Auth;
-use app\models\Cms_model;
-use app\extends\Cache_service;
-
-/** CMS class
- * (Content Management System)
- *
- * Serves the content;
- * Reponds to all front-end front-office requests
- *
- */
-class Cms {
-
-
- ## PERMITION
- ## -------------------------------------------------------------------------
-
-
- /** is admin or permited
- *
- * shortcut method for checking access authorization
- *
- * returns true if user belogns to the admin group
- * OR has the specified permition/privilege
- *
- * @param $privilege_id (int)
- *
- * NOTE:
- * unlike the other authorization methods ...
- * $privilege_id is NOT an array but a single privilege id
- *
- * @return true|false
- */
- private static function is_admin_or_permited( $privilege_id )
- {
- return (
- Auth::in_admin_group()
- || Auth::hasPermition([ $privilege_id ])
- );
- }
-
-
-
- ## FILES
- ## -------------------------------------------------------------------------
-
-
- /** serve file by file_path
- * (request is valid only for admin users)
- *
- * @param $file_path (string): relative file path
- * GET @param type (string) : media-type of file
- */
- public static function serve_file($file_path)
- {
- $file = self::get_file_attributes($file_path);
-
- // if user is authorized
- if (self::is_admin_or_permited($file['privilege_id'])) {
-
- $media_type = Registry::get('REQUEST')->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
- .' για να δείτε το περιεχόμενο!
- <br><br>
- Αγόρασε τώρα το <button class="btn">πακέτο πρόσβασης '. $pri_id .'</button>'
- ]);
- }
-
- }
-
-
- ## 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 @@
<?php
+namespace app\controllers;
class JsonToForm
{
@@ -141,14 +142,20 @@ class JsonToForm
return (mb_strlen($str) > $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 .= "
+ <input type='hidden' name='". $group['name']
+ ."' value='". $group['value'] ."'>";
+ }
- $html = "
+ // now constuct the form body
+ $html = "{$identity}
<div class='row'>
";
@@ -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 .= "
<div class='form-group {$class}'>
@@ -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}<br />'; }
@@ -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 .= "
- <input type='text' class='form-control form-control-sm' name='{$name}' {$required}>";
+ <input type='text' class='form-control form-control-sm' name='{$name}' $def_value {$required}>";
$checkFilledJS = "
if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}<br />'; }
@@ -271,6 +311,8 @@ class JsonToForm
case 'password':
+ $def_value = ($set_value) ? "value='{$value}'" : "value=''";
+
$html .= "
<input type='password' class='form-control form-control-sm' name='{$name}' {$required}>";
@@ -283,8 +325,10 @@ class JsonToForm
case 'integer':
+ $def_value = ($set_value) ? "value='{$value}'" : "value=''";
+
$html .= "
- <input type='number' class='form-control form-control-sm' name='{$name}' min='0' step='1' {$required}>";
+ <input type='number' class='form-control form-control-sm' name='{$name}' min='0' step='1' $def_value {$required}>";
$checkFilledJS .= "
if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}<br />'; }
@@ -295,8 +339,10 @@ class JsonToForm
case 'textarea':
+ $def_value = ($set_value) ? "{$value}" : "";
+
$html .= "
- <textarea class='form-control form-control-sm' name='{$name}' {$required}></textarea>";
+ <textarea class='form-control form-control-sm' name='{$name}' {$required}>{$def_value}</textarea>";
$checkFilledJS .= "
if ($('textarea[name={$name}]').val() =='') { empty += '{$label} {$asterisk}<br />'; }
@@ -319,8 +365,10 @@ class JsonToForm
case 'email':
+ $def_value = ($set_value) ? "value='{$value}'" : "value=''";
+
$html .= "
- <input type='email' class='form-control form-control-sm' name='{$name}' {$required}>";
+ <input type='email' class='form-control form-control-sm' name='{$name}' {$def_value} {$required}>";
$checkFilledJS .= "
if ($('input[name={$name}]').val() =='') { empty += '{$label} {$asterisk}<br />'; }
@@ -332,7 +380,6 @@ class JsonToForm
default: // label, acts as common text
//$html .= "<label>{$label}</label";
-
}
diff --git a/public/app/controllers/Office.php b/public/app/controllers/Office.php
new file mode 100644
index 0000000..cfadde3
--- /dev/null
+++ b/public/app/controllers/Office.php
@@ -0,0 +1,424 @@
+<?php
+
+namespace app\controllers;
+
+use Registry;
+use Render;
+use app\controllers\Auth;
+use app\extends\App_manager;
+use app\models\Cms_model;
+use app\extends\Cache_service;
+
+/** Office class
+ *
+ * Manages all requests (front/back-office)
+ */
+class Office {
+
+ ## -------------------------------------------------------------------------
+ ##
+ ## SERVE METHODS (selects)
+ ##
+ ## -------------------------------------------------------------------------
+
+ ## PERMITION
+ ## -------------------------------------------------------------------------
+
+
+ /** is admin or permited
+ *
+ * shortcut method for checking access authorization
+ *
+ * returns true if user belogns to the admin group
+ * OR has the specified permition/privilege
+ *
+ * @param $privilege_id (int)
+ *
+ * NOTE:
+ * unlike the other authorization methods ...
+ * $privilege_id is NOT an array but a single privilege id
+ *
+ * @return true|false
+ */
+ private static function is_admin_or_permited( $privilege_id )
+ {
+ return (
+ Auth::in_admin_group()
+ || Auth::hasPermition([ $privilege_id ])
+ );
+ }
+
+
+
+ ## SERVE FILE
+ ## -------------------------------------------------------------------------
+
+
+ /** serve file by file_path
+ * (request is valid only for admin users)
+ *
+ * @param $file_path (string): relative file path
+ * GET @param type (string) : media-type of file
+ */
+ public static function serve_file($file_path)
+ {
+ $file = self::get_file_attributes($file_path);
+
+ // if user is authorized
+ if (self::is_admin_or_permited($file['privilege_id'])) {
+
+ $media_type = Registry::get('REQUEST')->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;
+ }
+
+
+
+ ## PETITIONS
+ ## -------------------------------------------------------------------------
+ ## secretarial support / teachers' requests and applications
+
+
+
+ /** (any) petition
+ *
+ * check if user is authorized to view the content;
+ * if so, prepare and render the petition view
+ *
+ * @param $petition_type (string): [common|penalty]
+ */
+ public static function request_petition($petition_tag)
+ {
+ // get current user
+ $manager = new App_manager();
+ if (!$manager->hasUserToken()) { // if user is not connected
+ Render::view('error/404', [
+ 'error_code' => 403, // serve forbidden
+ 'moto' => 'Forbidden',
+ 'message' => 'Για να έχετε πρόσβαση, θα πρέπει πρώτα να συνδεθείτε'
+ ]);
+ die(); // then end;
+ }
+
+ $token = $manager->getUserToken(); // from token
+ $user = $token->getUser(); // create user
+ $id = $user->getID(); // keep id user
+
+ switch ($petition_tag) { // route to specific type of petition
+
+ case 'common':
+ self::render_common_petition(['user' => $user]);
+ break;
+
+ case 'penalty':
+ self::render_penalty_form(['user' => $user]);
+ break;
+
+ default: // if not a known petition type
+ Render::view('error/404', [ // then serve not-found
+ 'message' => 'Δεν βρέθηκε το είδος της αίτησης ή του εγγράφου που ζητήσατε.'
+ ]);
+ }
+ }
+
+
+ private static function render_penalty_form($opts)
+ {
+ $user_id = $opts['user']->getID();
+
+ $form_setup = json_decode(json_encode(PENALTY_FORM, JSON_UNESCAPED_UNICODE));
+
+ // get all teachers
+ $teachers_array = Registry::use('database')->runQuery(
+ "SELECT concat(last_name, ' ', first_name) as TeacherName
+ FROM user ORDER BY TeacherName", []
+ );
+ $teachers = []; // constuct teacher names as a simple array
+ foreach($teachers_array as $key => $person) {
+ $teachers[] = $person['TeacherName'];
+ }
+ // print_r( $teachers); die();
+
+ // get $key of rapporteur, president and members inside the form_setup->form array
+ for($i=0; $i < sizeof($form_setup->form) ; $i++) {
+ if (isset($form_setup->form[$i]->name)) {
+ if ($form_setup->form[$i]->name == 'rapporteur') { $keyRapporteur = $i; }
+ if ($form_setup->form[$i]->name == 'president') { $keyPresident = $i; }
+ if ($form_setup->form[$i]->name == 'members') { $keyMembers = $i; }
+ }
+ }
+
+ // set option sources for rapporteur, president and members
+ $form_setup->form[$keyRapporteur]->options = $teachers;
+ $form_setup->form[$keyPresident]->options = $teachers;
+ $form_setup->form[$keyMembers]->options = $teachers;
+
+ // get Form's HTML and Jsvascript
+ $form = JsonToForm::json_form($form_setup, [
+ ['name' => 'id', 'value' => $user_id] // pass user identity
+ ]);
+
+ Render::view('templates/penalty', ['form' => $form]);
+
+ }
+
+
+
+ ## -------------------------------------------------------------------------
+ ##
+ ## ADMIN METHODS (insert, updated etc.)
+ ##
+ ## -------------------------------------------------------------------------
+
+
+ /** files
+ * echo all files
+ *
+ * @return (array)
+ */
+ public static function files()
+ {
+ return Cache_service::files_attributes();
+ }
+
+
+ /** upload_file
+ * upload the file to the file system
+ *
+ * the method reads the POST and FILES array
+ * to retrieve all needed parametres
+ *
+ * FILES @param file
+ * POST @param folder : petition's ID or somthing random
+ * SESSION @param user_id
+ */
+ public static function upload_file()
+ {
+ $request = Registry::get('REQUEST');
+
+ $uploaded = self::upload_to_fs(); // upload file to file-system
+
+ if ($uploaded['success']) {
+
+ $media_id = self::define_media([ // define media in database; get id
+ 'title' => $request->POST['title'],
+ 'type' => $uploaded['type'],
+ 'path' => $uploaded['path']
+ ]);
+
+ Render::json([ // render results as json
+ 'success' => true,
+ 'id' => $media_id,
+ 'title' => $request->POST['title'],
+ 'path' => $uploaded['path'],
+ 'type' => $uploaded['type']
+ ]);
+
+ } else {
+ Render::json(['success' => false ]);
+ }
+ }
+
+
+ /** upload to fs
+ * upload file to File-System
+ *
+ * POST @param folder
+ * FILES @param file
+ */
+ private static function upload_to_fs()
+ {
+ $post = Registry::get('REQUEST')->POST;
+ $files = Registry::get('REQUEST')->FILES;
+
+
+ // Checks before uploading the file
+ ////////////////////////////////////////////////////////////////////////
+
+ // ** 1: file is upladed to temporary folder ---------------------------
+ if (! is_uploaded_file($files['file']['tmp_name'])) {
+ return ['success' => false]; // bye!
+ }
+
+ // ** 2: File belongs to the allowed MIME types ------------------------
+ $allowed_file_types = [
+ // pdf
+ 'application/pdf',
+ // images
+ 'image/png', 'image/jpeg',
+ // word
+ 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ // excel
+ 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ // rar
+ 'application/vnd.rar', 'application/x-rar-compressed', 'application/octet-stream',
+ // zip
+ 'application/zip', 'application/x-zip-compressed', 'multipart/x-zip'
+ // 'application/octet-stream' refers to zip; also to rar (no-need to re-include)
+ ];
+ // Recomended MIME type checking via mime_content_type():
+ $mime_type = mime_content_type($files['file']['tmp_name']);
+ if (! in_array($mime_type, $allowed_file_types)) { // File type NOT allowed ...
+ return ['success' => false]; // bye!
+ }
+
+ $file_name = $files['file']['name'];
+ $file_type = $files['file']['type']; // do not take it for granted
+ $file_size = $files['file']['size'];
+ $file_tmp = $files['file']['tmp_name'];
+
+ $bare_name = pathinfo($file_name, PATHINFO_FILENAME);
+ $file_ext = pathinfo($file_name, PATHINFO_EXTENSION);
+
+
+ // ** 3: filename or size checks may be added --------------------------
+ if ($file_name == "") {
+ return ['success' => false]; // bye!
+ }
+
+
+ // READY to finaly save/upload the file to CDN /////////////////////////
+
+ $folder = MEDIA_STORAGE_ROOT . $post['folder'];
+ if (!file_exists($folder)) { // create folder if not exists
+ mkdir($folder, 0757, true);
+ }
+
+ // print_r([
+ // 'dir' => $folder,
+ // 'file' => $bare_name,
+ // 'ext' => $file_ext,
+ // 'type' => $file_type
+ // ]); die();
+
+ $relative_filename = $post['folder']
+ .'/'
+ . strtolower(self::clear_file_name($bare_name) .'.'. $file_ext);
+ $store_filename = MEDIA_STORAGE_ROOT . $relative_filename;
+
+ if (move_uploaded_file($files["file"]["tmp_name"], $store_filename)) {
+ return [
+ 'success' => true,
+ 'path' => $relative_filename,
+ 'type' => $mime_type
+ ];
+
+ } else { return ['success' => false]; }
+
+ }
+
+
+ /** clear_file_name
+ * replace greek characters and strip symbols
+ */
+ private static function clear_file_name($str)
+ {
+ $el = mb_split( "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάέήίόύώϊϋς ", "");
+ $en = str_split("ABGDEZHUIKLMNJOPRSTYFXCVabgdezhuiklmnjoprstyfxcvaehioyviys-");
+ $strip = str_split("!@#$%^&*()+~`[]{};'/<>?=\"");
+
+ return str_replace($strip, '', str_replace($el, $en, $str));
+ }
+
+
+ /** define_media
+ *
+ * create a record in media table
+ *
+ * @param $data (array): [title => , path => , type => mime-type]
+ * @return id (int): id of created media record
+ */
+ private static function define_media($data)
+ {
+ $request = Registry::get('REQUEST');
+
+ $media_id = Registry::use('database')->query(
+ "INSERT INTO media (label, `type`, `path`)
+ VALUES (:label, :mimetype, :filepath)",
+ [
+ 'label' => $data['title'],
+ 'mimetype' => $data['type'],
+ 'filepath' => $data['path']
+ ]
+ )->lastInsertID();
+ return $media_id;
+ }
+
+
+ /** create media for petition
+ *
+ * links petition to each media-file of the media `id`s array
+ *
+ * @param $media (array): a list of media-file `id`s
+ * @param $petition_id (int)
+ */
+ private static function create_medias_for_petition($medias, $petition_id)
+ {
+ foreach($medias as $key => $medi) {
+ self::link_media_to_petition($medi, $petition_id); // link to petition
+ }
+ return true;
+ }
+
+ /** link one media-file to a specific post
+ *
+ * NOTE:
+ * the method does not check if media is linked already
+ * so be sure that the pair of (media_id,post_id) not exist
+ *
+ * @param $media_id (int)
+ * @param $petition_id (int)
+ */
+ private static function link_media_to_petition( $media_id, $petition_id )
+ {
+ Registry::use('database')->runQuery(
+ "INSERT INTO petition_media (petition_id, media_id)
+ VALUES (:petition, :media)",
+ [
+ 'petition' => $petition_id,
+ 'media' => $media_id,
+ ]
+ );
+ return true;
+ }
+
+
+}
diff --git a/public/app/extends/App_manager.php b/public/app/extends/App_manager.php
index 8e6ce95..b003015 100644
--- a/public/app/extends/App_manager.php
+++ b/public/app/extends/App_manager.php
@@ -53,7 +53,9 @@ class App_manager extends UserManager
}
-
+ /** ??
+ *
+ */
public function login_user()
{
diff --git a/public/app/extends/App_user.php b/public/app/extends/App_user.php
index 9aed489..6e93969 100644
--- a/public/app/extends/App_user.php
+++ b/public/app/extends/App_user.php
@@ -12,14 +12,6 @@ use Registry;
* this way it specializes the UserManagement
* according to this app's special rules
*
- * Add privileges concept
- * ---
- * A Class_user has privileges (which are deferent than Roles)
- * In fact, privileges extend the authorization requirements for users
- *
- * Authorized content is marked with some 'minimum Privilege'
- * So the content is available to the READER(s) that have certain Privileges
- *
*/
class App_user extends User
{
@@ -29,18 +21,20 @@ class App_user extends User
*/
private $id;
- /** user privileges
- * @var array
+ /** sex (gender)
+ * @var int (1 = male, 2 = female )
*/
- private $privileges = [];
+ private $sex;
/** user name
- * @var string
+ * @var string : first_name +' '+ last_name
*/
private $name;
+
+
/** SETTERS AND GETTERS
- * for id, name, privileges attributes
+ * for id, name, attributes
* -------------------------------------------------------------------------
*/
@@ -68,54 +62,55 @@ class App_user extends User
}
- // name
+ // sex
// --- -- -- - - -
- /** getName
+ /** getSex()
* @return int
*/
- public function getName(): string
+ public function getSex(): int
{
- return $this->name;
+ return $this->sex;
}
- /** setName()
+
+ /** setSex()
*
- * @param string : user's full name
+ * @param int : sex (id)
*
* @return User
*/
- public function setName(string $name): self
+ public function setSex(int $sex): self
{
- $this->name = $name;
+ $this->sex = $sex;
return $this;
}
-
- // privileges
+
+
+ // name
// --- -- -- - - -
- /** getPrivileges
- *
- * @return privileges (array)
+ /** getName
+ * @return string
*/
- public function getPrivileges(): array
+ public function getName(): string
{
- return $this->privileges;
+ return $this->name;
}
-
- /** setPrivileges()
+ /** setFirstName()
*
- * @param array $privileges
+ * @param string : user's full name
*
* @return User
*/
- public function setPrivileges(array $privileges): self
+ public function setName(string $name): self
{
- $this->privileges = $privileges;
+ $this->name = $name;
return $this;
}
-
+
+
} \ No newline at end of file
diff --git a/public/app/extends/Cache_service.php b/public/app/extends/Cache_service.php
index c435b75..05fd39e 100644
--- a/public/app/extends/Cache_service.php
+++ b/public/app/extends/Cache_service.php
@@ -36,25 +36,6 @@ class Cache_service
}
- public static function privileges_hierarchy( $options = 0 )
- {
- return proxy(
- [\app\models\Access_model::class, 'privileges'],
- [], CACHE_ROOT_TTL,
- $options
- );
- }
-
- public static function pages_list( $options = 0 )
- {
- return proxy(
- [\app\models\Cms_model::class, 'pages'],
- [], CACHE_ROOT_TTL,
- $options
- );
- }
-
-
/** entity
*
* create and retrieve a cached array of some entity
diff --git a/public/app/models/Access_model.php b/public/app/models/Access_model.php
index 8d446dc..8a2e5ce 100644
--- a/public/app/models/Access_model.php
+++ b/public/app/models/Access_model.php
@@ -3,6 +3,7 @@
namespace app\models;
use \Registry;
+use app\extends\App_manager;
use app\models\History_model;
class Access_model
@@ -148,36 +149,52 @@ class Access_model
}
- /** activate
+ /** activate_set_password
*
- * check if activation code is valid;
- * if valid, set account active;
+ * activate user and set password
*
* @param $ticket (hex/MD5): activation code;
*
*/
- public static function activate($ticket)
+ public static function activate_set_password($post, $password)
{
- $user = Registry::use('database')->query(
- "SELECT * FROM user WHERE activation = :ticket",
- [ 'ticket' => $ticket ]
- )->getFirst();
-
- // if no user with this activation code, return false
- if ($user === false) return false;
-
- // remove activation code from user record
- Registry::use('database')->runQuery(
+ // Update and set activate = true
+ $rowCount = Registry::use('database')->query(
"UPDATE user
- SET active = 1, `activation` = NULL
- WHERE activation = :ticket",
- [ 'ticket' => $ticket ]
- );
+ SET first_name = :first_name,
+ last_name = :last_name,
+ email = :email,
+ father_name = :father_name,
+ registration_number = :registration_number,
+ sector = :sector,
+ belonging_school = :belonging_school,
+ position = :position,
+ phone = :phone,
+ `password` = :password,
+ invitation = NULL,
+ active = :active
+ WHERE id = :id AND invitation = :invitation",
+ [
+ ':first_name' => $post['first_name'],
+ ':last_name' => $post['last_name'],
+ ':email' => $post['email'],
+ ':father_name' => $post['father_name'],
+ ':registration_number' => $post['registration_number'],
+ ':sector' => $post['sector'],
+ ':belonging_school' => $post['belonging_school'],
+ ':position' => $post['position'],
+ ':phone' => $post['phone'],
+ ':password' => $password,
+ ':active' => 1,
+ ':id' => $post['id'],
+ ':invitation' => $post['invitation']
+ ]
+ )->rowCount();
// update history
- History_model::trackUserAccess($user['id'], TRACK_ACCOUNT, 'User Account Activated');
+ History_model::trackUserAccess($post['id'], TRACK_ACCOUNT, 'User Account Activated');
- return true;
+ return $rowCount;
}
diff --git a/public/app/models/Cms_model.php b/public/app/models/Office_model.php
index fad11b8..fad11b8 100644
--- a/public/app/models/Cms_model.php
+++ b/public/app/models/Office_model.php
diff --git a/public/app/models/_info.md b/public/app/models/_info.md
index 82143bf..ac6d334 100644
--- a/public/app/models/_info.md
+++ b/public/app/models/_info.md
@@ -150,3 +150,24 @@ $myobject = new myclass();
call_user_func(array($myobject, 'say_hello'));
?>
+
+
+
+
+# APPlication
+
+\ controllers
+ [ ] App
+ [ ] Auth
+
+\ extends
+ [ ] Cache_service
+ [*] App_manager
+ [*] App_user
+ [ ] SendMail_service
+ [ ] Form_builder
+
+
+\ models
+ [ ] Access_model
+ [ ] History_model \ No newline at end of file
diff --git a/public/app/routes/backend.php b/public/app/routes/backend.php
index 1290f8a..6fbc157 100644
--- a/public/app/routes/backend.php
+++ b/public/app/routes/backend.php
@@ -1,9 +1,9 @@
<?php
-use app\controllers\Auth;
-use app\controllers\CmsAdmin;
-use app\models\admin\Privilege_model;
-use app\extends\Cache_service;
+//// use app\controllers\Auth;
+//// use app\controllers\CmsAdmin;
+//// use app\models\admin\Privilege_model;
+//// use app\extends\Cache_service;
/** admin pages
@@ -11,7 +11,7 @@ use app\extends\Cache_service;
* NOTE:
* All adminitration routes MUST INCLUDE an Auth::allowRoles() check
*/
-
+/*
// admin panel
////////////////////////////////////////////////////////////////////////////////
@@ -167,3 +167,4 @@ Route::add('/admin/api/pages', function () { // ajax: get all pages
CmsAdmin::all_pages();
});
+*/ \ No newline at end of file
diff --git a/public/app/routes/frontend.php b/public/app/routes/frontend.php
index 2defce5..b0e064b 100644
--- a/public/app/routes/frontend.php
+++ b/public/app/routes/frontend.php
@@ -1,8 +1,8 @@
<?php
use app\controllers\Auth;
-use app\controllers\Classroom_user;
-use app\controllers\Cms;
+use app\controllers\App_user;
+use app\controllers\Office;
use app\extends\Cache_service;
@@ -10,9 +10,16 @@ use app\extends\Cache_service;
////////////////////////////////////////////////////////////////////////////////
// Route::add('/', function() { Render::view('welcome'); });
-Route::add('/', function() { Render::view('user/registration'); });
+Route::add('/', function() { Render::view('user/login'); });
-Route::add('/penalty', function() { Render::view('templates/penalty'); });
+
+Route::add('/invitation/([0-9]*)', function($id) {
+ Auth::invitation($id);
+});
+
+Route::add('/petition/([0-9a-z\-_]*)', function($tag) {
+ Office::request_petition($tag);
+});
// Error pages
////////////////////////////////////////////////////////////////////////////////
diff --git a/public/app/routes/user.php b/public/app/routes/user.php
index 146b212..a2d48d6 100644
--- a/public/app/routes/user.php
+++ b/public/app/routes/user.php
@@ -13,29 +13,28 @@ use app\controllers\Classroom_user;
// request login ... -> then sends to POST:/account/check-login
Route::add('/login', function() { Render::view('user/login'); });
-// request registration ... -> then sends to POST:/account/register
-Route::add('/registration', function() { Render::view('user/registration'); });
-
// request logout
Route::add('/logout', function() {
Auth::logout();
header('Location: /'); die();
});
-// request activation
-Route::add('/account/activate', function() { Auth::activate(); } );
+// request activation (from invitation page; POST:form is sent)
+Route::add('/account/activate', function() { Auth::activate(); }, 'post');
// request password reset
Route::add('/account/reset_password', function() { Auth::reset_password(); } );
-// invite
+// invite some users
Route::add('/invite', function() {
Auth::allowRoles([1, 2, 3]);
Render::view('admin/invite');
});
-
+Route::add('/panel', function() {
+ Render::json(['connected' => Auth::is_connected()]);
+});
// Replies to common requests (POST method)
// --- -- -- - - -
diff --git a/public/app/views/error/404.php b/public/app/views/error/404.php
index a085830..41f17da 100644
--- a/public/app/views/error/404.php
+++ b/public/app/views/error/404.php
@@ -7,7 +7,6 @@
*
* optional @var $error_code (int) : error code
* optional @var $moto (string) : super-mini description text
- * optional @var $message (string)
*
*/
@@ -15,14 +14,14 @@
$error_code = 404; // set default (404)
}
- http_response_code(403);
+ http_response_code($error_code);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
- <title>404: Not Found</title>
+ <title><?=$error_code?> : <?= $moto ?? 'Not found' ?></title>
<style>
html,body{
@@ -52,13 +51,10 @@
<body>
<div class='container'>
<div class='content'>
+
<h3><?=$error_code?></h3>
<?= $moto ?? 'Not found' ?><br />
- <!--
- —
- <br />
- <span><?= $message ?? "and I still haven't found what I'm looking for." ?></span>
- -->
+
</div>
</div>
</body>
diff --git a/public/app/views/templates/penalty.php b/public/app/views/templates/penalty.php
index 6a8f563..bbd7b4a 100644
--- a/public/app/views/templates/penalty.php
+++ b/public/app/views/templates/penalty.php
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
- <title><?=SITE_TITLE?> - Εγγραφή</title>
+ <title><?=SITE_TITLE?> - Πρακτικό Πειθαρχικής Υπόθεσης</title>
<?php // header includes
////////////////////////////////////////////////////////////////////////
@@ -56,14 +56,8 @@
<div class='content-form'>
<form method="post">
<div>
- <p>1o Γυμνάσιο Ραφήνας /<br />
- Πλατφόρμα ηλεκτρονικών αιτήσεων και δημιουργίας διαδικαστικών εγγράφων</p>
- <h2>Πρόσκληση #</h2>
-
- <?php
- $form = JsonToForm::make_a_form(PENALTY_FORM);
- ?>
+ <h2>Πρακτικό Πειθαρχικής Υπόθεσης</h2>
<?=$form['html']?>
@@ -122,6 +116,8 @@
<?=$form['init_js']?>
+
+ <?=$form['values_js']?>
</script>
</html>
diff --git a/public/app/views/user/registration.php b/public/app/views/user/invitation.php
index 9eb0ea3..eb34bc4 100644
--- a/public/app/views/user/registration.php
+++ b/public/app/views/user/invitation.php
@@ -43,7 +43,7 @@
label { font-size: 14px; }
</style>
</head>
-<body class="classroom">
+<body class="office">
<div class='container'>
<div class="content">
<div class="info">
@@ -58,10 +58,6 @@
<h2>Πρόσκληση #</h2>
- <?php
- $form = JsonToForm::make_a_form(REGISTRATION_FORM);
- ?>
-
<?=$form['html']?>
<br />
@@ -80,42 +76,104 @@
</body>
<script>
+var values = {};
+var empty = '';
+
+$(document).ready(function() {
+
+ /** select2_set_text
+ * select an (select2-)option by text
+ *
+ * @param control = jquery selector,
+ * @param t (string) = text of option
+ */
+ function select2_set_text(control, t) { /* define function */
+ opts = control.select2()[0].options;
+ var id;
+ for(i=0; i<opts.length; i++) { if (opts[i].text == t) id = i; }
+ control.val(id).trigger('change');
+ }
+
+ /** get_id_of_text
+ * get id (=value) of an option with `t` text
+ *
+ * @param control = jquery selector,
+ * @param t (string) = text of option
+ */
+ function get_id_of_text( control , t) { /* define id from text */
+ opts = control.select2()[0].options;
+ var id = false;
+ for(i=0; i<opts.length; i++) { if (opts[i].text == t) id = i; }
+ return id;
+ }
+
+ /** select2_set_multi_text
+ * select several (select2-)options by text
+ *
+ * @param control = jquery selector,
+ * #param t_list (string) = list of selected texts
+ */
+ function select2_set_multi_text(control, t_list) { /* define function */
+ var ids = [];
+ t_list.forEach (t => { let id = get_id_of_text(control, t);
+ if (id !== false) ids.push(id);
+ })
+ control.val(ids).change();
+ }
+
+
+ <?=$form['init_js']?>
+
+ <?=$form['values_js']?>
+
// When form is submited
// -------------------------------------------------------------------------
- $('.content-form form').submit( event => {
+ $('form').submit( event => {
event.preventDefault();
- if ($('input[name=password]').val() != $('input[name=password2]').val()) {
- alert('Τα δυο passrods δεν ταιριάζουν!');
+ if ($('input[name=password]').val() != $('input[name=confirm_password]').val()) {
+ alert('Τα δυο κωδικοί πρόσβασης δεν ταιριάζουν!');
+
+ } else if ($('input[name=password]').val() == "") {
+ alert('Ο κωδικός πρόσβασης δεν μπορεί να είναι κενός')
- } else {
+ } else if ( ($('input[name=password]').val() == '0')
+ || ($('input[name=password]').val() =='') ) {
+ alert('Παρκαλώ συμπληρώστε ένα τηλέφωνο επικοινωνίας')
+ } else {
// prepare data to POST
var data = {
+ // identification fields
+ id: $('input[name=id]').val(),
+ invitation: $('input[name=invitation]').val(),
+ // data fields
first_name: $('input[name=first_name]').val(),
last_name: $('input[name=last_name]').val(),
+ father_name: $('input[name=father_name]').val(),
email: $('input[name=email]').val(),
registration_number: $('input[name=registration_number]').val(),
- sector: $('input[name=sector]').val(),
+ sector: $('select[name=sector]').select2('data')[0].text,
belonging_school: $('input[name=belonging_school]').val(),
- working_shcool: $('input[name=working_shcool]').val(),
- position_type_id: $('input[name=position_type_id]').val(),
+ position: $('select[name=position]').select2('data')[0].text,
phone: $('input[name=phone]').val(),
+ // access verification
password: $('input[name=password]').val()
};
-
- // select action url (add or update)
- var request = '/account/register';
+ // console.log('post:', data);
+
+ var request = '/account/activate'; // set action url
// send POST request
$.post(request, data)
.done(function( data ) {
- $('.classroom .content-form').html(data.message)
+ $('.office .content-form').html(data.message)
});
- }
-
+ }
});
-</script>
+
+});
+</script>
</html>
diff --git a/public/app/views/welcome.php b/public/app/views/welcome.php
index e97f748..fd3f703 100644
--- a/public/app/views/welcome.php
+++ b/public/app/views/welcome.php
@@ -26,15 +26,14 @@ select option { font-size: .87rem; }
</head>
<body class='classroom'>
<div class="container" style="max-width: 640px;">
- <div class="row">
+ <div class="row">
- <?php
- $form = JsonToForm::make_a_form(REGISTRATION_FORM);
- ?>
+<?php
+ $form = JsonToForm::make_a_form(REGISTRATION_FORM);
+?>
+<?=$form['html']?>
- <?=$form['html']?>
-
- </div>
+ </div>
</div>
@@ -196,6 +195,8 @@ $('.select-field').select2({ width: '100%' });
// ---------------------------------------------------------------------------
<?=$form['init_js']?>
+<?=$form['values_js']?>
+
// 04. FORM-LOGIC
// ---------------------------------------------------------------------------
diff --git a/public/assets/css/admin.css b/public/assets/css/admin.css
index 4bd8718..58fcc45 100644
--- a/public/assets/css/admin.css
+++ b/public/assets/css/admin.css
@@ -5,31 +5,31 @@
--class-btn-grey-light: #c9c9c999;
}
-.classroom .manage {
+.office .manage {
width: 100%;
max-width: 1600px;
margin: 0 auto 2em;
}
-.classroom .manage.maximized { max-width: 1960px; }
-.classroom .manage.minimized { max-width: 960px; }
-.classroom .manage.edit-post { max-width: 1420px; }
+.office .manage.maximized { max-width: 1960px; }
+.office .manage.minimized { max-width: 960px; }
+.office .manage.edit-post { max-width: 1420px; }
-.classroom .edit-post textarea[name=intro] { height: 12vh; }
-.classroom .edit-post textarea[name=body] {
+.office .edit-post textarea[name=intro] { height: 12vh; }
+.office .edit-post textarea[name=body] {
height: calc(100vh - 492px);
min-height:320px;
font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace;
color: #333;
}
-.classroom .edit-post .post-media button.over-bar { margin: -26px 0 0 0; }
-.classroom .edit-post .post-media ul {
+.office .edit-post .post-media button.over-bar { margin: -26px 0 0 0; }
+.office .edit-post .post-media ul {
border: 1px solid #ccc;
border-radius: 4px;
padding: 6px;
}
-.classroom .edit-post .post-media ul li {
+.office .edit-post .post-media ul li {
border-bottom: 1px solid #ddd;
list-style-type: none;
padding: 3px 6px;
@@ -38,77 +38,77 @@
justify-content: space-between;
align-items: center;
}
-.classroom .edit-post .post-media ul li:last-child { border-bottom: none ;}
-.classroom .edit-post .post-media ul li:hover { background: #eee; }
+.office .edit-post .post-media ul li:last-child { border-bottom: none ;}
+.office .edit-post .post-media ul li:hover { background: #eee; }
-.classroom .manage h2 {
+.office .manage h2 {
font-size: 20px;
color: #445;
margin: 20px 0;
}
-.classroom .manage.edit-post textarea { width: 100% !important;}
-.classroom .manage.edit-post .select2-selection { min-height: 34px; }
+.office .manage.edit-post textarea { width: 100% !important;}
+.office .manage.edit-post .select2-selection { min-height: 34px; }
-.classroom .manage.edit-post select#status.published {
+.office .manage.edit-post select#status.published {
background-color: #5cb85c;
border-color: #4cae4c;
color: #fff;
text-align: center;
}
-.classroom .manage.edit-post select#status option {
+.office .manage.edit-post select#status option {
background: #fff;
color: #333;
}
/* --- optional fields: defaut=hide --- */
-.classroom .edit-post .optional label {
+.office .edit-post .optional label {
margin-bottom: 1em;
padding-bottom: .5em;
border-bottom: 1px solid var(--class-btn-grey-light)
}
-.classroom .edit-post .optional label.show {
+.office .edit-post .optional label.show {
margin-bottom: unset;
border: none;
}
-.classroom .edit-post .optional label:hover {
+.office .edit-post .optional label:hover {
cursor: pointer;
color: var(--class-btn-blue);
}
-.classroom .edit-post .optional label::after { float: right; content: "+"; }
-.classroom .edit-post .optional label.show::after { content: "–"; }
-.classroom .edit-post .optional label + div { display: none; }
-.classroom .edit-post .optional label.show + div { display: block; }
+.office .edit-post .optional label::after { float: right; content: "+"; }
+.office .edit-post .optional label.show::after { content: "–"; }
+.office .edit-post .optional label + div { display: none; }
+.office .edit-post .optional label.show + div { display: block; }
.alert.alert-info.title-bar { min-height: 52px; margin-top: 20px; }
.alert.alert-info.title-bar button { margin-left: 8px; }
-.classroom .title-bar {
+.office .title-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
}
-.classroom .action-btn button { float: right; }
+.office .action-btn button { float: right; }
-.classroom .top-bar { padding: 4px 0; }
+.office .top-bar { padding: 4px 0; }
-.classroom .top-bar .breadcrumb .btn {
+.office .top-bar .breadcrumb .btn {
margin-left: 0;
margin-right: 8px;
border-radius: 3px;
color: var(--class-btn-blue);
}
-.classroom .top-bar .btn:hover {
+.office .top-bar .btn:hover {
background-color: var(--class-btn-grey-light);
}
-.classroom .top-bar .btn.selected {
+.office .top-bar .btn.selected {
color: #fff;
background-color: var(--class-btn-blue);
}
@@ -116,35 +116,9 @@
/* --- dataTables --- */
-.classroom .manage .dataTable tbody tr:hover { background: #f8f8f8; }
-.classroom .manage .dataTable .dt-actions { width: 48px; text-align: right }
+.office .manage .dataTable tbody tr:hover { background: #f8f8f8; }
+.office .manage .dataTable .dt-actions { width: 48px; text-align: right }
/* --- unpublished posts -- */
-.classroom .manage .dataTable .fa-eye-slash { color: #999; }
-
-
-.classroom .js-copy:hover::after {
- opacity: 0;
- pointer-events: none;
- background: #ddd7;
- border-radius: 2px;
- content: "Copy";
- padding: .25em .75em;
- position: absolute;
- z-index: 10;
- transform-origin: top;
- margin-top: -16px;
- transform: translate(-50%, 0);
-}
-
-.classroom .js-copy.copied:hover::after {
- content: "Αντιγράφηκε";
- opacity: 1;
- margin-top: -22px;
- transform: translate(-50%, 0);
- transition: all 0.18s ease-out 0.18s;
- background: #eee;
- border: 1px solid #ddd9;
-}
+.office .manage .dataTable .fa-eye-slash { color: #999; }
- \ No newline at end of file
diff --git a/public/assets/css/class.css b/public/assets/css/class.css
index 5252975..4747507 100644
--- a/public/assets/css/class.css
+++ b/public/assets/css/class.css
@@ -1,7 +1,7 @@
-/** Classroom sections
+/** Office sections
* (main layout css-classes)
* -----------------------------------------------------------------------------
- * .classroom {
+ * .office {
* .top-bar {
* .breadcrumb
* .admin
@@ -37,7 +37,7 @@
* ----------------------------------------------------------------------------
*/
-.classroom .top-bar {
+.office .top-bar {
display: flex;
justify-content: space-between;
align-items: center;
@@ -47,348 +47,17 @@
background: var(--light-grey-bgr);
}
-.classroom .top-bar .breadcrumb { margin: 0; padding: 0; background: none; }
-
-.classroom .top-bar .fa,
-.classroom .top-bar .fas {
+.office .top-bar .fa,
+.office .top-bar .fas {
width: 32px;
text-align: center;
}
-
-.classroom .main-content {
+.office .main-content {
padding: 1.5em;
max-width: 1440px;
min-height: calc(100vh - 345px);
}
-
-/* category list menu
- * -----------------------------------------------------------------------------
- */
-
-.classroom .side-bar { padding-right: 1em; }
-
-
-.classroom .side-bar h3 {
- font-weight: 600; font-size: 1em;
- color: var(--class-blue);
-}
-
- /* --- ul > li > a --- */
-
-.classroom .side-bar ul { list-style: none; padding: 0; }
-.classroom .side-bar ul li { margin: 0.5em 0; }
-.classroom .side-bar ul li a {
- display: flex;
- padding: .2em;
- background: #4442;
- border-radius: 6px;
- transition: background 0.3s;
-}
-.classroom .side-bar ul li a:hover,
-.classroom .side-bar ul li a:active {
- background: #cde;
- text-decoration: none;
-}
-
-/* --- li > a > span --- */
-
-.classroom .side-bar ul li a span {
- display: block;
- align-self: center;
- padding: .3em;
-}
-.classroom .side-bar ul li a .label {
- font-size: 13px;
- color: var(--class-blue-dark);
- flex-grow: 1;
- text-align: left;
- padding-left: 1em;
- border-radius: 6px;
- white-space: normal;
- font-weight: 400;
-}
-
-/* --- inner --- */
-
-.classroom .side-bar ul .inner {
- padding-left: 1em;
- overflow: hidden;
- display: none;
-}
-.classroom .side-bar ul .inner.show { display: block; }
-
-/* --- has-childs | toggler --- */
-
-.classroom .side-bar ul li a.has-childs { background: #9bf4; }
-.classroom .side-bar ul li a.has-childs:hover { background: #cde;}
-
-.classroom .side-bar ul li a.has-childs .label {
- font-weight: 600;
- border-radius: 6px 0 0 6px;
- width: calc(100% - 36px);
-}
-
-.classroom .side-bar ul li a.has-childs .toggler {
- text-align: center;
- width: 32px;
- font-size: 15px;
- border-radius: 4px;
- background: #7774;
- font-weight: 700;
-}
-.classroom .side-bar ul li a.has-childs .toggler:hover {
- background: var(--class-blue);
- color: #fff;
-}
-.classroom .side-bar ul li a.selected {
- background: var(--class-orange-opaque);
-}
-.classroom .side-bar ul li a:hover,
-.classroom .side-bar ul li a:active,
-.classroom .side-bar ul li a:focus,
-.classroom .side-bar ul li a:visited,
-.classroom .side-bar ul li a:link,
-.classroom .side-bar ul li a span:hover,
-.classroom .side-bar ul li a span:active,
-.classroom .side-bar ul li a span:focus,
-.classroom .side-bar ul li a span:visited,
-.classroom .side-bar ul li a span:link,
-.classroom .side-bar ul li a span:target { text-decoration: none !important; }
-
-
-
-.classroom .lesson-view img { max-width: 100%; }
-
-
-
-/** breadcrumb
- * -----------------------------------------------------------------------------
- */
-
-.classroom .breadcrumb a { counter-reset: var(--class-blue); font-size: 14px; }
-.classroom .breadcrumb i.fas { padding-top: 7px; font-size: 12px; }
-
-
-
-
-/** content
- * -----------------------------------------------------------------------------
- */
-
-.classroom .content--wrapper {
- max-width: 1024px;
- width: 100%;
- margin: 1em auto;
- padding: 0 2em 2em 2em;
-}
-.classroom .content h2 {
- font-weight: 700;
- font-size: 24px;
- padding: 8px 3em 1em 0; /* 1em 3em 1em 0; */
- color: var(--class-blue-dark);
-}
-.classroom .content h3 {
- font-weight: 600; font-size: 1.4em;
- padding: 1em 3em 1em 0;
- color: var(--class-blue);
- border-bottom: 1px dashed var(--class-blue-opaque);
-}
-.classroom .content h3 span { font-weight: 400; color: #444; }
-.classroom .content p {
- line-height: 150%;
- padding: 5px 0;
-}
-
-/* --- post: medias -- */
-/* DEPRICATED: not needed
-.classroom .content--wrapper .medias {
- padding: 2em 0 1em;
- border-top: 1px solid var(--class-grey-background);
-}
-.classroom .content--wrapper .medias ol li {
- margin-left: -12px;
- padding: 2px 8px;
-}
-.classroom .content--wrapper .medias ol li::marker {
- font-size: 12px;
- color: #999;
-}
-*/
-
-/* --- post: tags --- */
-
-.classroom .content--wrapper .tags {
- padding: 2em 0 1em;
- border-top: 1px solid var(--class-grey-background);
-}
-.classroom .content--wrapper .tags a {
- color: #444;
- background-color: var(--class-grey-background);
- padding: 6px 12px;
- margin: 6px;
- border-radius: 3px;
-}
-
-
-
-.classroom .course-view h5 { padding-top: 2em; }
-
-/** sub-categories on category page
- * -----------------------------------------------------------------------------
- */
-/*
-.classroom .category-childs { margin: 1em; padding: 1em; }
-
-.classroom .category-childs a {
- display: inline-block;
- margin: .5em;
- padding: .2em 2em;
- border-radius: 2em;
- border: 1px solid var(--class-blue);
- line-height: 2em;
- font-weight: 600;
- transition: background 0.3s;
-}
-
-.classroom .category-childs a:hover {
- background-color: var(--class-blue);
- color: #fffe;
- text-decoration: none;
-}
-
-*/
-
-
-
-/** articles-list
- * -----------------------------------------------------------------------------
- * 22 | Title of artivle
- * July | path / of / categories
- * 2023 | * some intro of article
- * -----------------------------------------------------------------------------
- */
-.classroom .post-card {
- padding-top: .75em;
- margin: 0;
- border-bottom: 1px solid #7773;
- display: flex;
-}
-.classroom .post-card .post-card--content {
- flex-grow: 1;
- width: calc(100% - 90px);
-}
-.classroom .post-card h3 { padding: 0; margin: 0; border: none; font-size: 20px; }
-.classroom .post-card h3 a { display: block; }
-.classroom .post-card h3 a:hover { color: #f47920; }
-.classroom .post-card .category { color: #566; }
-.classroom .post-card .intro {
- font-style: italic;
- font-size: 16px;
-}
-/* --- date block --- */
-.classroom .date {
- display: flex;
- flex-direction: column;
- width: 90px;
-}
-.classroom .date p {
- padding: 0; margin: 0;
- line-height: 115%;
- text-align: center;
-}
-.classroom .date .day { font-size: 24px; color: var(--class-blue-opaque); }
-.classroom .date .month { font-size: 16px; color: #555; }
-.classroom .date .year { font-size: 12px; color: #666; }
-
-
-
-
-.classroom .content-form h3 { color: #369; opacity: 0.9; }
-
-
-
-
-/** post (article)
- * -----------------------------------------------------------------------------
- */
-
-
-
-.classroom .lesson-view h2 { padding-bottom: 0; font-size: 24px; }
-
-.classroom .lesson-view h2 span { float:right; margin-right: -3em;}
-
-.classroom .lesson-view pre { padding: 1em; background: #f5f5f6;}
-
-.classroom .lesson-view .intro {
- font-style: italic;
- font-size: 18px;
- color: var(--class-blue-dark);
- padding-bottom: 1em;
-}
-
-.classroom .lesson-view .post--date {
- padding: 0;
- color: var(--class-blue);
-}
-
-.classroom .article-body img {
- display: block;
- max-width: 100%;
- margin: 1em auto;
-}
-/*
-.classroom .article-body a.modal-toggler {
- padding: 0 16px;
- background: #def;
- color: #334;
- border-radius: 3px;
- text-decoration: none;
- border: 1px solid var(--class-blue-opaque);
-}
-.classroom .article-body a.modal-toggler:hover { background: var(--class-blue); color: #fff; }
-*/
-.classroom .article-body table {
- margin: 20px auto;
- min-width: 67%;
- border-spacing: 6px 0;
- border-collapse: separate;
-}
-.classroom .article-body table tr { margin: 4px; }
-.classroom .article-body table thead th {
- color: var(--class-btn-blue);
- border-bottom: 3px solid var(--class-blue);
- padding: 0 8px;
- text-align: revert-layer;
-}
-.classroom .article-body table tbody td {
- padding: 6px 8px;
- border-bottom: 1px solid var(--class-grey-background);
-}
-
-
-
-.classroom footer {
- margin: 2em 0 0 0;
- padding: 2.5em 0;
- font-size: .87em;
- background: #f5f6f7;
-}
-.classroom footer a {
- color: #024;
- text-decoration: none;
- padding: 2px 36px 2px 4px;
- border-radius: 3px;
-}
-.classroom footer a:hover { color: #fff; background: #369 ; }
-.classroom footer h4 { font-size: 20px; }
-.classroom footer .no-list-mark ul { padding-left: 0; margin-left: 0; list-style: none; }
-.classroom footer .no-list-mark ul li { margin: 0 0 4px 0; }
-
-
-.classroom .page-container { max-width: 1024px; }
-
-iframe .ytp-chrome-top-buttons { display: none !important; } \ No newline at end of file
+.office .page-container { max-width: 1024px; }
diff --git a/public/assets/js/invitation.md b/public/assets/js/invitation.md
new file mode 100644
index 0000000..ebcf0f7
--- /dev/null
+++ b/public/assets/js/invitation.md
@@ -0,0 +1,51 @@
+# SELECT2 HANDLING
+
+handling select2 properties (case-study javascript code)
+
+
+## get all options' loop through all ...
+
+ opts = $('#sector').select2()[0].options
+ for(i=0; i<opts.length; i++) { el = opts[i]; console.log(el.value, el.text); }
+
+
+
+## set option by selected 'TEXT'
+
+ var id;
+ for(i=0; i<opts.length; i++) { if (opts[i].text == 'TEXT') id = i; }
+ $('#sector').val(id).trigger('change);
+
+
+
+## prepare as functions
+
+ function select2_set_text(control, t) { /* define function */
+ opts = control.select2()[0].options;
+ var id;
+ for(i=0; i<opts.length; i++) { if (opts[i].text == t) id = i; }
+ control.val(id).trigger('change');
+ }
+ select2_set_text( $('#sector') , '04 Physics') /* call */
+
+
+
+## in multiple select2 ...
+
+ function get_id_of_text( control , t) { /* define id from text */
+ opts = control.select2()[0].options;
+ var id = false;
+ for(i=0; i<opts.length; i++) {
+ if (opts[i].text == t) id = i;
+ }
+ return id;
+ }
+ function select2_set_multi_text(control, t_list) { /* define function */
+ var ids = [];
+ t_list.forEach (t => { let id = get_id_of_text(control, t);
+ if (id !== false) ids.push(id);
+ })
+ control.val(ids).change();
+ }
+ select2_set_multi_text( $('#tags') , ['crime', '90s']) /* call */
+