diff options
| -rw-r--r-- | core/classes/session/DefaultSession.php | 6 | ||||
| -rw-r--r-- | public/app/config/app_constants.php | 43 | ||||
| -rw-r--r-- | public/app/controllers/Auth.php | 19 | ||||
| -rw-r--r-- | public/app/controllers/JsonToForm.php | 4 | ||||
| -rw-r--r-- | public/app/controllers/Office.php | 7 | ||||
| -rw-r--r-- | public/app/views/components/header_includes.php | 20 | ||||
| -rw-r--r-- | public/app/views/templates/course.php | 93 | ||||
| -rw-r--r-- | public/app/views/templates/lesson.php | 82 | ||||
| -rw-r--r-- | public/app/views/templates/page.php | 64 | ||||
| -rw-r--r-- | public/app/views/templates/penalty.php | 227 | ||||
| -rw-r--r-- | public/app/views/user/invitation.php | 166 | ||||
| -rw-r--r-- | public/app/views/user/login.php | 82 | ||||
| -rw-r--r-- | public/assets/css/class.css | 81 | ||||
| -rw-r--r-- | public/assets/css/overides.css | 120 | ||||
| -rw-r--r-- | public/assets/js/cookie.js | 41 |
15 files changed, 578 insertions, 477 deletions
diff --git a/core/classes/session/DefaultSession.php b/core/classes/session/DefaultSession.php index 819f00a..5e7ce39 100644 --- a/core/classes/session/DefaultSession.php +++ b/core/classes/session/DefaultSession.php @@ -16,6 +16,12 @@ class DefaultSession implements SessionHandlerInterface { // and let the session* functions // do what they know ini_set( "session.gc_maxlifetime", MAX_SESSION_LIFE ); + session_set_cookie_params([ + 'path' => '/', + // 'domain' => COOKIE_DOMAIN, # on localhost must be omitted entirely + 'secure' => COOKIE_SECURE, + 'samesite' => COOKIE_SAMESITE + ]); session_name(SESSION_NAME); session_start(); } diff --git a/public/app/config/app_constants.php b/public/app/config/app_constants.php index 262a727..3404033 100644 --- a/public/app/config/app_constants.php +++ b/public/app/config/app_constants.php @@ -23,7 +23,7 @@ if (file_exists("../core/auth/.env")) { // WEB-APP name and url // --- -- -- - - - define('SITE_TITLE', 'Classroom'); -define('SITE_URL', 'http://localhost'); +define('SITE_URL', $env['ANOM_HOSTNAME']); // Session and cookie names // --- -- -- - - - @@ -31,6 +31,19 @@ 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) +// Cookie Policy +// --- -- -- - - - +# define('COOKIE_DOMAIN', $env['ANOM_HOSTNAME']); // domain to be visible on +define('COOKIE_SECURE', false); // Secure cookie policy [true|false] +define('COOKIE_SAMESITE', 'Strict'); // SameSite cookie policy [Strict|Lax|None] + // recomended values: + // COOKIE_SECURE=true, COOKIE_SAMESITE='Strict' + // --- -- -- - - - + // for more info about cookie policy read: + // https://www.php.net/manual/en/function.session-set-cookie-params.php + + + // email setup // --- -- -- - - - // SMTP @@ -180,7 +193,7 @@ define('REGISTRATION_FORM', [ ], [ 'name' => 'email', - 'label' => 'e-mail', + 'label' => 'Email', 'type' => 'email', 'value' => 'auto', 'attributes' => ['required'] @@ -284,6 +297,11 @@ define('COMMON_REQUEST_FORM', [ ], 'form' => [ [ + 'name' => 'subject', + 'label' => 'Θέμα (χαρακτηριστικός τίτλος για αναφορά)', + 'attributes' => ['required'] + ], + [ 'name' => 'first_name', 'label' => 'Όνομα', 'attributes' => ['auto'] @@ -364,12 +382,21 @@ define('PENALTY_FORM', [ ], 'form' => [ [ + 'name' => 'subject', + 'label' => 'Θέμα (χαρακτηριστικός τίτλος για αναφορά)', + 'attributes' => ['required'] + ], + [ + 'label' => '', + 'type' => 'label' + ], + [ 'label' => 'Πειθαρχική υπόθεση', 'type' => 'label' ], [ 'name' => 'of_article', - 'label' => 'του/της...', + 'label' => 'του/της/των...', 'type' => 'select', 'options' => [ 'του μαθητή', @@ -377,33 +404,33 @@ define('PENALTY_FORM', [ 'των μαθητών', 'των μαθητριών' ], - 'class' => 'col-4', + 'class' => 'col-md-4', 'attributes' => ['required'] ], [ 'name' => 'student_names', 'label' => '(ονοματεπώνυ-μο/μα, πτώση γενική)', 'type' => 'textarea', - 'class' => 'col-8', + 'class' => 'col-md-8', 'attributes' => ['required'] ], [ 'name' => 'of_department', 'label' => 'του τμήματος...', - 'class' => 'col-4', + 'class' => 'col-md-4', 'attributes' => ['required'] ], [ 'name' => 'date', 'label' => 'Ημερομηνία', 'type' => 'date', - 'class' => 'col-4', + 'class' => 'col-md-4', 'attributes' => ['required'] ], [ 'name' => 'time', 'label' => 'Ώρα', - 'class' => 'col-4', + 'class' => 'col-md-4', 'attributes' => ['required'] ], [ diff --git a/public/app/controllers/Auth.php b/public/app/controllers/Auth.php index 118b4d0..f1e9819 100644 --- a/public/app/controllers/Auth.php +++ b/public/app/controllers/Auth.php @@ -62,9 +62,17 @@ class Auth { // set cookie for connected user setcookie( CONNECTION_COOKIE, - 'connected;'. $user->getName(), - time()+60*60*10, // 10 hours - '/' + rawurlencode(json_encode( + [ 'rid' => $record['role_id'], 'name' => $user->getName() ], + JSON_UNESCAPED_UNICODE + )), + [ + 'expires' =>time()+60*60*10, // 10 hours + 'path' => '/', + // 'domain' => COOKIE_DOMAIN, + 'secure' => COOKIE_SECURE, + 'samesite' => COOKIE_SAMESITE + ] ); // login OK, set Token in session @@ -174,7 +182,10 @@ class Auth { ]); - Render::view('user/invitation', ['form' => $form]); + Render::view('user/invitation', [ + 'form' => $form, + 'invitation_number' => $user->invitation + ]); } diff --git a/public/app/controllers/JsonToForm.php b/public/app/controllers/JsonToForm.php index 5df650d..7df8098 100644 --- a/public/app/controllers/JsonToForm.php +++ b/public/app/controllers/JsonToForm.php @@ -219,7 +219,7 @@ class JsonToForm // 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 = in_array('required', $attributes) ? 'required' : ''; // required $asterisk = in_array('required', $attributes) ? '*' : ''; // asterisk in label if required $html .= " @@ -239,7 +239,7 @@ class JsonToForm // prepare initialization of select2 (multiple) $initSelectsJS .= " var {$name} = $('#{$name}'); - {$name}.select2({ width: '100%', placeholde: '{$label}' });"; + {$name}.select2({ width: '100%' });"; if ($set_value) { // if default value is set $initSelectsJS .= " diff --git a/public/app/controllers/Office.php b/public/app/controllers/Office.php index cfadde3..44428af 100644 --- a/public/app/controllers/Office.php +++ b/public/app/controllers/Office.php @@ -160,6 +160,11 @@ class Office { } + private static function render_common_petition($opts) + { + + } + private static function render_penalty_form($opts) { $user_id = $opts['user']->getID(); @@ -193,7 +198,7 @@ class Office { // get Form's HTML and Jsvascript $form = JsonToForm::json_form($form_setup, [ - ['name' => 'id', 'value' => $user_id] // pass user identity + ['name' => 'user_id', 'value' => $user_id] // pass user identity ]); Render::view('templates/penalty', ['form' => $form]); diff --git a/public/app/views/components/header_includes.php b/public/app/views/components/header_includes.php index 433cc4e..15685b5 100644 --- a/public/app/views/components/header_includes.php +++ b/public/app/views/components/header_includes.php @@ -4,14 +4,24 @@ } ?> -<!-- fonts (CDN) --> +<!-- FONTS (CDN) --> + +<!-- Roboto slab <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> -<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400&display=swap" rel="stylesheet"> +<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400&display=swap" rel="stylesheet"> --> + +<!-- Fira Sans --> +<link rel="preconnect" href="https://fonts.googleapis.com"> +<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> +<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300;400;500&display=swap" rel="stylesheet"> <!-- fontawesome icons (CDN) --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> + +<!-- LIBRARY (dependencies) CSS --> + <!-- bootstap (CDN) --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-aFq/bzH65dt+w6FI2ooMVUpc+21e0SRygnTpmBvdBgSdnuTN7QbdgL+OapgHtvPp" crossorigin="anonymous"> @@ -21,6 +31,7 @@ <!-- select2 css --> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> +<!-- CUSTOM CSS --> <!-- main css --> <link href="/assets/css/class.css" rel="stylesheet"> @@ -28,11 +39,11 @@ <!-- overides --> <link href="/assets/css/overides.css" rel="stylesheet"> - - <!-- bootstrap javascript (CDN) --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/js/bootstrap.bundle.min.js" integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N" crossorigin="anonymous"></script> +<!-- JAVASCRIPT --> + <!-- jQuery (CDN) --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js" integrity="sha512-pumBsjNRGGqkPzKHndZMaAG+bir374sORyzM3uulLV14lN5LyykqNk8eEeUlUkB3U0M4FApyaHraT65ihJhDpQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> @@ -51,7 +62,6 @@ <script src="/assets/js/marked/marked.min.js"></script> - <!-- date handling ... https://stackoverflow.com/questions/27267565/javascript-returning-incorrect-date-from-an-input-type-date diff --git a/public/app/views/templates/course.php b/public/app/views/templates/course.php deleted file mode 100644 index 1d212b8..0000000 --- a/public/app/views/templates/course.php +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title><?=SITE_TITLE?> - <?=$title?></title> - - <?php // header includes - //////////////////////////////////////////////////////////////////////// - Render::view('components/header_includes'); - ?> - -</head> -<body class="classroom"> - - <?php // top-bar - //////////////////////////////////////////////////////////////////////// - Render::view('components/top_bar', [ - 'id' => $id, - 'label' => $breadcrumbs[ $id ]['rec']['label'], - 'parents' => $breadcrumbs[ $id ]['parents'] - ]); - ?> - - -<div class="main-content container"> - <div class="row"> - - <div class="col col-md-5 col-lg-4 d-sm-none d-md-block side-bar"> - - <?php // tree of courses - //////////////////////////////////////////////////////////////////////// - Render::view('components/courses_menu', [ - 'categories' => $categories, - 'open_path' => $course_path - ]); - ?> - - </div> - - <div class="col col-sm-12 col-md-7 col-lg-8 course-view"> - - <!-- Category Title --> - <h3> - <?=$breadcrumbs[ $id ]['rec']['label']?> - </h3> - - - <!-- Sub-Categories --> - <?php - Render::view('components/subcategories',[ - 'id' => $id, - 'breadcrumbs' => $breadcrumbs - ]) - ?> - - - <!-- Articles List --> - <?php if ($lessons) : ?> - - <h5>Μαθήματα</h5> - - <?php // list of posts/articles - //////////////////////////////////////////////////// - Render::view("components/lessons_list", [ - 'lessons' => $lessons, - 'fieldset' => ['intro', 'level'] // ['intro', 'date'] - ]); - ?> - <?php endif; ?> - - - - - </div> - - </div> - </div> - - <footer> - <div class="container"> - - <?php // render footer - //////////////////////////////////////////////////////////////// - Render::view('components/footer', [ 'entity' => $entity ]); - ?> - - </div> - </footer> - - - <script src="/assets/js/classroom.js"></script> -</body> -</html> diff --git a/public/app/views/templates/lesson.php b/public/app/views/templates/lesson.php deleted file mode 100644 index 0867cd3..0000000 --- a/public/app/views/templates/lesson.php +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title><?=SITE_TITLE?> - <?=$title?></title> - - <?php // header includes - //////////////////////////////////////////////////////////////////////// - Render::view('components/header_includes'); - ?> - -</head> -<body class="classroom"> - - <?php // top-bar - //////////////////////////////////////////////////////////////////////// - Render::view('components/top_bar', [ - 'id' => $id, - 'label' => $breadcrumbs[ $course_id ]['rec']['label'], - 'parents' => $breadcrumbs[ $course_id ]['parents'] - ]); - ?> - - -<div class="main-content container"> - <div class="row"> - - <div class="col col-md-5 col-lg-4 d-sm-none d-md-block side-bar"> - - <?php // tree of courses - //////////////////////////////////////////////////////////////////////// - Render::view('components/courses_menu', [ - 'categories' => $categories, - 'open_path' => $course_path - ]); - ?> - - </div> - - <div class="col col-sm-12 col-md-7 col-lg-8 lesson-view"> - - <!-- Lesson Title --> - <h3> - <?=$title?> - </h3> - - <!-- intro --> - <?php if ($lesson['intro'] != "") : ?> - <p class="intro"><?=$lesson['intro']?></p> - <?php endif; ?> - - <!-- body --> - <div class="article-body"> - <?php - - $parsedown = new Parsedown(); - echo $parsedown->text($lesson['body']); - - ?> - </div> - - - </div> - - </div> - </div> - - <footer> - <div class="container"> - - <?php // render footer - //////////////////////////////////////////////////////////////// - Render::view('components/footer', [ 'entity' => $entity ]); - ?> - - </div> - </footer> - - <script src="/assets/js/classroom.js"></script> - <script src="/assets/js/lesson-features.js"></script> -</body> -</html> diff --git a/public/app/views/templates/page.php b/public/app/views/templates/page.php deleted file mode 100644 index 6afe45e..0000000 --- a/public/app/views/templates/page.php +++ /dev/null @@ -1,64 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title><?=SITE_TITLE?> - <?=$page['title']?></title> - - <?php // header includes - //////////////////////////////////////////////////////////////////////// - Render::view('components/header_includes'); - ?> - -</head> -<body class="classroom"> - - <?php // top-bar - //////////////////////////////////////////////////////////////////////// - Render::view('components/top_bar', [ - 'id' => 0, - 'label' => '', - 'parents' => [] - ]); - ?> - - - <div class="main-content container page-container"> - - - <div class="lesson-view"> - - <!-- page Title --> - <h3> - <?=$page['title']?> - </h3> - - <!-- page body --> - <div class="article-body"> - <?php - - $parsedown = new Parsedown(); - echo $parsedown->text($page['body']); - - ?> - </div> - - - </div> - - </div> - - <footer> - <div class="container"> - - <?php // render footer - //////////////////////////////////////////////////////////////// - Render::view('components/footer', [ 'entity' => $entity ]); - ?> - - </div> - </footer> - - <script src="/assets/js/classroom.js"></script> - <script src="/assets/js/lesson-features.js"></script> -</body> -</html> diff --git a/public/app/views/templates/penalty.php b/public/app/views/templates/penalty.php index bbd7b4a..17e5426 100644 --- a/public/app/views/templates/penalty.php +++ b/public/app/views/templates/penalty.php @@ -9,115 +9,198 @@ Render::view('components/header_includes'); ?> - <style> - html,body{ - padding:0; margin:0; - font-size:1.25em; - color: #037; background: #f6f6f6; - line-height:1.2em; - } - h3 { - font-size: 2em; font-style: normal; - font-weight: 400; - color: #05a; - margin: 0; padding: 5px; - opacity: 0.27; - border-bottom: 1px solid #05a; - } - .container { display: flex; height: 100vh; align-items:center; } - .content { position: relative; - max-width: 800px; width: 100%; - margin: auto auto; padding: .5em; - justify-center: center; - font-size: .78em; - } - .content-form { - padding: 1.5em; - background: #eee; - border-radius: 8px; - box-shadow: 1px 5px 7px #7777; - } - .content .info { padding: 1.5em; font-size: .92em; } - .content .info p { padding: .5em; color: #444; font-size: .82em } - .form-label { margin-bottom: .25rem; } - - .select2-container--default .select2-selection--multiple { font-size: 15px; } - .select2-container--default.select2-container--focus .select2-selection--multiple { line-height: 100%; } - label { font-size: 14px; } - </style> </head> -<body class="classroom"> - <div class='container'> - <div class="content"> - <div class="info"> - <!--<h4>1o Γυμνάσιο Ραφήνας</h4> - <p>1o Γυμνάσιο Ραφήνας: Πλατφόρμα ηλεκτρονικών αιτήσεων και δημιουργίας εγγράφων</p>--> - </div> +<body class="office central-form"> + +<div class='container'> + <div class="content max720px"> + <div class='content-form'> <form method="post"> <div> - <h2>Πρακτικό Πειθαρχικής Υπόθεσης</h2> + <h4>Πρακτικό Πειθαρχικής Υπόθεσης</h4> + <hr /> <?=$form['html']?> <br /> - <button type="submit" class="btn btn-primary btn-sm col-12">Εγγραφή</button> + <button type="submit" class="btn btn-primary btn-sm col-12">Καταχώριση</button> </div> </form> </div> - <div class="info"> - <p>Απαιτείται η συμπλήρωση όλων των στοιχείων προκειμένου να γίνεται γρήγορα η σύνταξη των εγγράφων. Τα στοιχεία σας δεν πρόκειται να δημοσιοποιηθούν και προστατεύονται κατά την εισαγωγή τους με κρυπτογράφιση AES. Παράλληλα η σύνδεση στο site γίνεται με χρήση πιστοποιητικού SSL (RSA 2048 bits).</p> - <p>Αν έχετε ενεργοποιήσει ήδη το λογαρισμό σας <a href="/login">μπορείτε να συνδεθείτε</a>.</p> - </div> </div> -</body> +</body> <script> +var values = {}; +var empty = ''; + +$(document).ready(function() { + + // supplementary functions to select2 control + //////////////////////////////////////////////////////////////////////////// + + /** getValues + * --- -- -- - - - + * Get selected value(s) of Select2 control + * + * @param arg: source-element + * @return (string) value(s) comma-separated + */ + function getValues(srcElm) { + var res; + var obj = srcElm.select2('data'); // get delected data array + + if (obj.length === 0) return ''; // if empty list then nothig is selected + else { + var i = 0; + obj.forEach(function(elm){ // loop through object elements array + + if (i) res += ',' + elm.id; // if not first item, prepend ',' befor value(id) + else res = elm.id; // else set (first) checked value + + i++; + }); + } + return res; + } + + /** select2_set_text + * --- -- -- - - - + * select an (select2-)option by text + * onto a (single) select2 control + * + * @param control = jquery selector, + * @param t (string) = text of option + */ + function select2_set_text(control, t) { + 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` as text + * onto a select2 control; + * + * Can be used on single or multiple select2 contols + * + * @param control = jquery selector, + * @param t (string) = text of option + */ + function get_id_of_text( control , t) { + 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(); + } + + /** + * get selected text of a select2 control + */ + function selected_text(control) { + if (typeof control.select2('data') === 'undefined') return false; + else if (control.select2('data').length == 0) return false; + else return control.select2('data')[0].text; + } + + /** + * get all selected texts from a multi-select2 contol + */ + function selected_multitexts(control) { + if (typeof control.select2('data') === 'undefined') return false; + else if (control.select2('data').length == 0) return false; + else { + var result = []; + control.select2('data').forEach( item => { result.push(item.text); }); + return result; + } + } + + // intializations from form-definition + //////////////////////////////////////////////////////////////////////////// + + <?=$form['init_js']?> + + + // track empty values + //////////////////////////////////////////////////////////////////////////// + + + + + // When form is submited - // ------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////// $('.content-form form').submit( event => { event.preventDefault(); - if ($('input[name=password]').val() != $('input[name=password2]').val()) { + if (false) { alert('Τα δυο passrods δεν ταιριάζουν!'); } else { - // prepare data to POST - var data = { - first_name: $('input[name=first_name]').val(), - last_name: $('input[name=last_name]').val(), - email: $('input[name=email]').val(), - registration_number: $('input[name=registration_number]').val(), - sector: $('input[name=sector]').val(), - belonging_school: $('input[name=belonging_school]').val(), - working_shcool: $('input[name=working_shcool]').val(), - position_type_id: $('input[name=position_type_id]').val(), - phone: $('input[name=phone]').val(), - password: $('input[name=password]').val() + var data = { // select content data + of_article: selected_text($('select[name=of_article]')), + student_names: $('textarea[name=student_names]').val(), + of_department: $('input[name=of_department]').val(), + date: $('input[name=date]').val(), + time: $('input[name=time]').val(), + place: selected_text($('select[name=place]')), + rapporteur: selected_text($('select[name=rapporteur]')), + charge: $('textarea[name=charge]').val(), + apology: $('textarea[name=apology]').val(), + decision_reasoning: $('textarea[name=decision_reasoning]').val(), + decision: selected_text($('select[name=decision]')), + decision_more: $('input[name=decision_more]').val(), + president: selected_text($('select[name=president]')), + members: selected_multitexts($('select[name="members[]"]')) }; + var form_data = { // prepare data to post + subject: $('input[name=of_department]').val(), + content: JSON.stringify(data), + on_date: $('input[name=date]').val(), + user_id: $('input[name=id]').val() + } + // select action url (add or update) - var request = '/account/register'; + // var request = '/account/register'; + console.log(data); // send POST request - $.post(request, data) - .done(function( data ) { - $('.classroom .content-form').html(data.message) - }); + // $.post(request, form_data) + // .done(function( data ) { + // $('.classroom .content-form').html(data.message) + // }); } }); - <?=$form['init_js']?> - - <?=$form['values_js']?> + }); </script> </html> diff --git a/public/app/views/user/invitation.php b/public/app/views/user/invitation.php index eb34bc4..564b722 100644 --- a/public/app/views/user/invitation.php +++ b/public/app/views/user/invitation.php @@ -8,71 +8,55 @@ //////////////////////////////////////////////////////////////////////// Render::view('components/header_includes'); ?> - - <style> - html,body{ - padding:0; margin:0; - font-size:1.25em; - color: #037; background: #f6f6f6; - line-height:1.2em; - } - h3 { - font-size: 2em; font-style: normal; - font-weight: 400; - color: #05a; - margin: 0; padding: 5px; - opacity: 0.27; - border-bottom: 1px solid #05a; - } - .container { display: flex; height: 100vh; align-items:center; } - .content { position: relative; - max-width: 540px; width: 100%; - margin: auto auto; padding: .5em; - justify-center: center; - font-size: .78em; - } - .content-form { - padding: 1.5em; - background: #eee; - border-radius: 8px; - box-shadow: 1px 5px 7px #7777; - } - .content .info { padding: 1.5em; font-size: .92em; } - .content .info p { padding: .5em; color: #444; font-size: .82em } - .form-label { margin-bottom: .25rem; } - label { font-size: 14px; } - </style> </head> -<body class="office"> +<body class="office central-form"> + <div class='container'> - <div class="content"> + <div class="content max540px"> + <div class="info"> - <!--<h4>1o Γυμνάσιο Ραφήνας</h4> - <p>1o Γυμνάσιο Ραφήνας: Πλατφόρμα ηλεκτρονικών αιτήσεων και δημιουργίας εγγράφων</p>--> + <h4>1o Γυμνάσιο Ραφήνας</h4> + <p> + Πλατφόρμα ηλεκτρονικών αιτήσεων + και δημιουργίας διαδικαστικών εγγράφων. + </p> </div> + <div class='content-form'> <form method="post"> <div> - <p>1o Γυμνάσιο Ραφήνας /<br /> - Πλατφόρμα ηλεκτρονικών αιτήσεων και δημιουργίας διαδικαστικών εγγράφων</p> - - <h2>Πρόσκληση #</h2> + <h4>Πρόσκληση #<?=$invitation_number?></h4> + <hr/> <?=$form['html']?> <br /> - <button type="submit" class="btn btn-primary btn-sm col-12">Εγγραφή</button> + <button type="submit" class="btn btn-primary btn-sm col-12">Ενεργοποίηση Λογαριασμού</button> </div> </form> </div> <div class="info"> - <p>Απαιτείται η συμπλήρωση όλων των στοιχείων προκειμένου να γίνεται γρήγορα η σύνταξη των εγγράφων. Τα στοιχεία σας δεν πρόκειται να δημοσιοποιηθούν και προστατεύονται κατά την εισαγωγή τους με κρυπτογράφιση AES. Παράλληλα η σύνδεση στο site γίνεται με χρήση πιστοποιητικού SSL (RSA 2048 bits).</p> - <p>Αν έχετε ενεργοποιήσει ήδη το λογαρισμό σας <a href="/login">μπορείτε να συνδεθείτε</a>.</p> + <p> + Απαιτείται η συμπλήρωση όλων των στοιχείων + προκειμένου να γίνεται γρήγορα η σύνταξη των εγγράφων. + </p> + <p> + Αν έχετε ενεργοποιήσει ήδη το λογαρισμό σας + <a href="/login">μπορείτε να συνδεθείτε</a>. + </p> + <p> + Τα στοιχεία σας δεν πρόκειται να δημοσιοποιηθούν και προστατεύονται + κατά την μεταφορά τους στον server με ισχυρή κρυπτογράφιση. + Η ασφάλεια της σύνδεσης με το site πιστοποιείται από την + <a href="https://letsencrypt.org/" target="_blanc">Let's Encrypt</a>. + </p> + </div> </div> </div> + </body> <script> @@ -81,13 +65,44 @@ var empty = ''; $(document).ready(function() { + // supplementary functions to select2 control + //////////////////////////////////////////////////////////////////////////// + + /** getValues + * --- -- -- - - - + * Get selected value(s) of Select2 control + * + * @param arg: source-element + * @return (string) value(s) comma-separated + */ + function getValues(srcElm) { + var res; + var obj = srcElm.select2('data'); // get delected data array + + if (obj.length === 0) return ''; // if empty list then nothig is selected + else { + var i = 0; + obj.forEach(function(elm){ // loop through object elements array + + if (i) res += ',' + elm.id; // if not first item, prepend ',' befor value(id) + else res = elm.id; // else set (first) checked value + + i++; + }); + } + return res; + } + + /** select2_set_text + * --- -- -- - - - * select an (select2-)option by text + * onto a (single) select2 control * * @param control = jquery selector, * @param t (string) = text of option */ - function select2_set_text(control, t) { /* define function */ + function select2_set_text(control, t) { opts = control.select2()[0].options; var id; for(i=0; i<opts.length; i++) { if (opts[i].text == t) id = i; } @@ -95,23 +110,28 @@ $(document).ready(function() { } /** get_id_of_text - * get id (=value) of an option with `t` text + * --- -- -- - - - + * get id (=value) of an option with `t` as text + * onto a select2 control; + * + * Can be used on single or multiple select2 contols * * @param control = jquery selector, * @param t (string) = text of option */ - function get_id_of_text( control , t) { /* define id from text */ + function get_id_of_text( control , t) { 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 + /** select2_set_multi_text + * --- -- -- - - - * select several (select2-)options by text * * @param control = jquery selector, - * #param t_list (string) = list of selected texts + * @param t_list (string) = list of selected texts */ function select2_set_multi_text(control, t_list) { /* define function */ var ids = []; @@ -122,12 +142,40 @@ $(document).ready(function() { } + /** + * get selected text of a select2 control + */ + function selected_text(control) { + if (control.select2('data').lenght == 0) return false + else return control.select2('data')[0].text; + } + + /** + * get all selected texts from a multi-select2 contol + */ + function selected_multitexts(control) { + if (control.select2('data').legth == 0) return false; + else { + var result = []; + control.select2('data').forEach( item => { result.push(item.text); }); + return result; + } + } + + // intializations from form-definition + //////////////////////////////////////////////////////////////////////////// + <?=$form['init_js']?> + + // track empty values + //////////////////////////////////////////////////////////////////////////// + <?=$form['values_js']?> + // When form is submited - // ------------------------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////// $('form').submit( event => { event.preventDefault(); @@ -161,15 +209,15 @@ $(document).ready(function() { // access verification password: $('input[name=password]').val() }; - // console.log('post:', data); + console.log(data); - var request = '/account/activate'; // set action url - - // send POST request - $.post(request, data) - .done(function( data ) { - $('.office .content-form').html(data.message) - }); +// var request = '/account/activate'; // set action url +// +// // send POST request +// $.post(request, data) +// .done(function( data ) { +// $('.office .content-form').html(data.message) +// }); } }); diff --git a/public/app/views/user/login.php b/public/app/views/user/login.php index 58bfdbb..871e501 100644 --- a/public/app/views/user/login.php +++ b/public/app/views/user/login.php @@ -2,58 +2,66 @@ <html lang="en"> <head> <meta charset="utf-8"> - <title><?=SITE_TITLE?> - Είσοδος Χρήστη</title> + <title><?=SITE_TITLE?> - Είσοδος Χρήστη</title> - <?php // header includes + <?php // header includes //////////////////////////////////////////////////////////////////////// Render::view('components/header_includes'); ?> - - <style> - html,body{ - padding:0; margin:0; - font-size:1.25em; - color: #037; background: #eee; - line-height:1.2em; - } - h3 { - font-size: 2em; font-style: normal; - font-weight: 400; - color: #05a; - margin: 0; padding: 5px; - opacity: 0.27; - border-bottom: 1px solid #05a; - } - .container { display: flex; height: 100vh; align-items:center; } - .content { position: relative; - max-width:480px; width: 100%; - margin: auto auto; padding: 1.5em; - justify-center: center; - background: #e3e3e3; - border-radius: 8px; - box-shadow: 1px 5px 7px #7777; - } - </style> +<style> +:root { /* login-form overides */ + --form-content-font-size: 1rem; + --form-input-height: 34px; + --select2-arrow-top: 1px; +} +</style> </head> -<body class="classroom"> +<body class="office central-form"> + <div class='container'> - <div class='content'> - <h4>Είσοδος Χρήστη</h4> + <div class='content max420px'> + + <div class="info"> + <h4>1o Γυμνάσιο Ραφήνας</h4> + <p>Πλατφόρμα ηλεκτρονικών αιτήσεων και δημιουργίας διαδικαστικών εγγράφων.</p> + </div> + + <div class="content-form"> + <h4>Είσοδος</h4> <hr /> <form method="post"> - <div class="mb-3"> - <label for="exampleInputEmail1" class="form-label">Email</label> + <div class="form-group"> + <label for="exampleInputEmail1">Email</label> <input type="email" class="form-control form-control-sm" name="email" aria-describedby="emailHelp" required> </div> - <div class="mb-3"> - <label for="exampleInputPassword1" class="form-label">Κωδικός Πρόσβασης</label> + <div class="form-group"> + <label for="exampleInputPassword1">Κωδικός πρόσβασης</label> <input type="password" class="form-control form-control-sm" name="password" required> </div> <br /> - <button type="submit" class="btn btn-primary btn-sm col-12">Επιβεβαίωση και Είσοδος</button> + <div class="row justify-content-center"><div class="col-6"> + <button type="submit" class="btn btn-primary btn-sm col-12">Σύνδεση</button> + </div></div> </form> + </div> + + <div class="info"> + <!-- + <p>Αν ξεχάσατε τον κωδικό πρόσβασης μπορείτε να δημιουργήσετε ένα νέο (υπο κατασκευή).</p> + --> + <p> + Εαν δικαιούστε αλλά δεν έχετε πρόσβαση στο site, παρακαλούμε επικοινωνήστε + με τη διεύθυνση του σχολείου προκειμένου να σας αποσταλεί σχετική πρόσκληση. + </p> + <p> + Ο ιστότοπος χρησιμοποιεί cookies τα οποία έχουν αποκλειστικά λειτουργικό ρόλο. + Η χρήση των υπηρεσιών του site συνεπάγεται την αποδοχή διατήρησης αυτών των cookies. + </p> + </div> + </div> </div> + </body> <script> @@ -80,7 +88,7 @@ window.location.href = data.status.goto; } else { - alert('Wrong credentials; please try again'); + alert('Τα στοιχεία πρόσβασης που δώσατε είναι λάθος. Παρακαλώ προσπαθήστε ξανά.'); } }); diff --git a/public/assets/css/class.css b/public/assets/css/class.css index 4747507..5333f29 100644 --- a/public/assets/css/class.css +++ b/public/assets/css/class.css @@ -28,9 +28,88 @@ --class-orange-opaque: #f4792099; --class-grey-background: #eeedeb; --class-red: #d13; - --light-grey-bgr: #f2f3f8; + --light-grey-bgr: #f5f6f7; + --light-grey-layer-bgr: #eeeded; + --light-grey-shade: 1px 5px 7px #7773; + --form-content-font-size: .87rem; + --form-input-height: 31px; + --form-layer-border: 1px solid #e7e5e5; + --select2-arrow-top: -1px; } +html, body, +select, select option { + font-family: "Fira Sans", sans-serif; + font-weight: 400; + font-size: 1rem; +} + +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { font-weight: 400; }; + +html, body { + padding:0; margin:0; + font-size:1.25em; + color: #037; background: var(--light-grey-bgr); + line-height:1.2em; +} + +.office h3 { + font-size: 2em; font-style: normal; + color: #05a; + margin: 0; padding: 5px; + opacity: 0.27; + border-bottom: 1px solid #05a; +} + + +/** micro-positioning classes + * ----------------------------------------------------------------------------- + */ + +.max420px { max-width: 420px; width: 100%; } +.max480px { max-width: 480px; width: 100%; } +.max540px { max-width: 540px; width: 100%; } +.max720px { max-width: 720px; width: 100%; } +.bottom3em { padding-bottom: 3em; } + + + + +/** central form + * ----------------------------------------------------------------------------- + * includes login / invitation / reset password forms + */ + +.central-form .container { + display: flex; + min-height: 100vh; + align-items:center; +} +.central-form .content { + width: 100%; + margin: auto auto; padding: .5em; + font-size: .78em; +} + +.central-form .content-form { + padding: 1.5em; + background: var(--light-grey-layer-bgr); + border-radius: 8px; + box-shadow: var(--light-grey-shade); + border: var(--form-layer-border); +} + +.central-form .content .info { padding: 1.5em; font-size: .92em; } +.central-form .content .info p { + color: #554e; + font-size: .9rem; + line-height: 150%; +} + +.central-form form label { font-size: 14px; } + +.central-form h4 { font-size: 1.24rem; } + /* main layout classes diff --git a/public/assets/css/overides.css b/public/assets/css/overides.css index 3fd143f..aa3173a 100644 --- a/public/assets/css/overides.css +++ b/public/assets/css/overides.css @@ -2,14 +2,14 @@ --bs-heading-color: #679; } -html, body, select, select option, .select2-selection__choice { font-family: "Roboto Slab", serif; font-weight: 400; } +.content { text-align: unset; } -.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { font-weight: 400; }; +.form-control-sm { font-size: var(--form-content-font-size); } -.content { text-align: unset; } +input.form-control-sm { height: var(--form-input-height); } -.form-group { margin-bottom: 8px; } -.form-control, .form-select { border: 1px solid #7777; font-size: .857em; } +.form-group { margin-bottom: 12px; } +.form-control, .form-select { border: 1px solid #7777; } .form-label { font-size: .72em; color: var(--bs-heading-color); } .footer__listLink { color: #bbb; } @@ -49,7 +49,10 @@ html, body, select, select option, .select2-selection__choice { font-family: "Ro .admin-container .table > :not(caption) > * > * { padding: .35rem .35rem; } .admin-container .table tbody tr:hover { background: #eee; } -ul.select2-results__options li { font-size: 14px; padding: 4px 8px; } +ul.select2-results__options li { + font-size: var(--form-content-font-size); + padding: 4px 8px; +} .admin-container .modal-footer .form-actions { display: flex; gap: 8px; } @@ -74,7 +77,6 @@ ul.select2-results__options li { font-size: 14px; padding: 4px 8px; } background-color: transparent; background-size: contain; border: none !important; - height: 16 !important; width: 12px !important; margin: auto !important; top: 12px !important; @@ -82,49 +84,18 @@ ul.select2-results__options li { font-size: 14px; padding: 4px 8px; } height: 14px; } .select2-container--default .select2-selection--single .select2-selection__arrow { width: 24px; } -.select2-container--default .select2-selection--single { height: 37px; } -/* ------------------------------------------------------------------------- end -*/ - -/* - .admin-container .edit-post textarea[name=intro] { height: 94px ;} - - - .admin-container .post-media button.over-bar { margin: -26px 0 0 0; float: right; } - .admin-container .post-media ul { - border: 1px solid #ccc; - border-radius: 4px; - padding: 6px; - } - - .admin-container .post-media ul li { - border-bottom: 1px solid #ddd; - list-style-type: none; - padding: 3px 6px; - - display: flex; - justify-content: space-between; - align-items: center; - } - .admin-container .post-media ul li:last-child { border-bottom: none ;} - .admin-container .post-media ul li:hover { background: #eee; } - - .admin-container .post-media li .btn-xs { font-size: 14px; width: 24px; height: 24px; padding:0; } - - .classroom .edit-post textarea[name=body], - .classroom .edit-page textarea[name=body] { - min-height:320px; - font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace; - color: #333; - } - -*/ - +.select2-container--default .select2-selection--single { height: var(--form-input-height); } /** select2|multiple overides * --- -- -- - - - */ -input.select2-search__field { font-size: 15px; } +input.select2-search__field { font-size: var(--form-content-font-size); } + +.select2-selection__choice { + font-size: var(--form-content-font-size); + font-weight: 400; +} + ul.select2-selection__rendered { margin-bottom: 0; } /* select2: ul */ .select2-container--default .select2-selection--multiple .select2-selection__choice { padding: 2px; } /* select2: li */ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { /* select2: button */ @@ -141,4 +112,59 @@ ul.select2-selection__rendered { margin-bottom: 0; } /* select2: ul */ .select2-container--default .select2-selection--single .select2-selection__clear { margin-right: 32px; } .select2-container .select2-selection--single .select2-selection__rendered { font-size: 15px; padding: 2px 20px 2px 8px; } -
\ No newline at end of file + +.select2-container--default .select2-selection--multiple .select2-selection__choice__display { + padding-left: 16px; +} + +.select2-container--default .select2-selection--single .select2-selection__arrow { + top: var(--select2-arrow-top); +} + + + + + +/* +================================================================================ + + - - - -- -- --- C H A N G E S --- -- -- - - - + +================================================================================ +*/ + + + +/* overides.css | http://localhost/assets/css/overides.css */ + + + .select2-container .select2-selection--single .select2-selection__rendered { + font-size: var(--form-content-font-size); + } + + + +.central-form form label { + /* font-size: 14px; */ + font-size: .92rem; color: #554c; + } + + /* bootstrap.min.css | https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/css/bootstrap.min.css */ + + + + + + + .select2-container--default .select2-selection--single:focus-visible, + .select2-container--focus .select2-selection--multiple { + border-color: #86b7fe; + box-shadow: 0 0 0 .25rem rgba(13,110,253,.25); + outline: none; + color: var(--bs-body-color); + } + + .select2-container--default.select2-container--focus .select2-selection--multiple { + border: 1px solid #86b7fe;; + outline: 0; + }
\ No newline at end of file diff --git a/public/assets/js/cookie.js b/public/assets/js/cookie.js index fcd3006..ab51c05 100644 --- a/public/assets/js/cookie.js +++ b/public/assets/js/cookie.js @@ -21,7 +21,10 @@ function createCookie(name, value, expire) { expires = ""; } - document.cookie = name+"="+value+expires+"; path=/"; + // encode cookie + let enc = encodeRFC3986URIComponent(value); + + document.cookie = name +"="+ enc + expires +"; path=/; SameSite=Strict"; } @@ -41,7 +44,7 @@ function readCookie(name) { c = c.substring(1,c.length); } if (c.indexOf(nameEQ) == 0) { - return c.substring(nameEQ.length,c.length); + return decodeURIComponent(c.substring(nameEQ.length,c.length)); } } return null; @@ -76,3 +79,37 @@ function cookieExists(name) { } return false; } + + +/** encodeRFC3986URIComponent + * + * RFC3986 compatible URI encoding + * + * @param str + * @returns (string) RCF3986 compatible encoded str + */ +function encodeRFC3986URIComponent(str) { + return encodeURIComponent(str).replace( + /[!'()*]/g, + (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, + ); +} + + +/** example: + * --- -- -- - - - + * + * read connection cookie (as json object) + * + * connection = JSON.parse(decodeURIComponent(readCookie('con'))) + * + * then... + * connection = { + * rid: `role-id`, + * name: `full name` of connected user + * } + * + * so to refer to user's name ... + * console.log(connection.name) + * + */
\ No newline at end of file |
