summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/classes/session/DatabaseSession.php2
-rw-r--r--public/app/config/init_routes.php2
-rw-r--r--public/app/controllers/Auth.php2
-rw-r--r--public/app/controllers/CmsAdmin.php676
-rw-r--r--public/app/controllers/Office.php51
-rw-r--r--public/app/controllers/Petition.php63
-rw-r--r--public/app/extends/SendMail_service.php4
-rw-r--r--public/app/models/Access_model.php73
-rw-r--r--public/app/routes/api.php2
-rw-r--r--public/app/routes/frontend.php66
-rw-r--r--public/app/routes/user.php114
-rw-r--r--public/app/views/components/header_includes.php8
-rw-r--r--public/app/views/components/menu.php1
-rw-r--r--public/app/views/components/theme.php89
-rw-r--r--public/app/views/js/credits.php26
-rw-r--r--public/app/views/js/submit/application-form.php2
-rw-r--r--public/app/views/templates/admin_users.php134
-rw-r--r--public/app/views/templates/application.php2
-rw-r--r--public/app/views/templates/create_pdf.php2
-rw-r--r--public/app/views/templates/invite.php8
-rw-r--r--public/app/views/templates/penalty.php4
-rw-r--r--public/app/views/user/invitation.php4
-rw-r--r--public/app/views/user/login.php6
-rw-r--r--public/app/views/user/update_password.php2
-rw-r--r--public/assets/css/class.css5
-rw-r--r--public/assets/css/themes/fall-09.css8
-rw-r--r--public/assets/css/themes/spring-09.css2
-rw-r--r--public/assets/css/themes/winter-03.css13
-rw-r--r--public/assets/css/themes/winter-08.css11
-rw-r--r--public/assets/css/themes/winter-10.css25
-rw-r--r--public/assets/js/panel/admin_users.js177
-rw-r--r--public/assets/media/credits.txt13
-rw-r--r--public/assets/media/fall-09.webpbin0 -> 43856 bytes
-rw-r--r--public/assets/media/summer-0.jpgbin160764 -> 0 bytes
-rw-r--r--public/assets/media/summer-01.jpgbin56385 -> 0 bytes
-rw-r--r--public/assets/media/winter-03.jpgbin312425 -> 0 bytes
-rw-r--r--public/assets/media/winter-03.webpbin0 -> 68082 bytes
-rw-r--r--public/assets/media/winter-08.jpgbin41860 -> 0 bytes
-rw-r--r--public/assets/media/winter-08.webpbin0 -> 153164 bytes
-rw-r--r--public/assets/media/winter-10.webpbin0 -> 50930 bytes
40 files changed, 682 insertions, 915 deletions
diff --git a/core/classes/session/DatabaseSession.php b/core/classes/session/DatabaseSession.php
index aa31b62..fed6353 100644
--- a/core/classes/session/DatabaseSession.php
+++ b/core/classes/session/DatabaseSession.php
@@ -66,7 +66,7 @@ class DatabaseSession implements SessionHandlerInterface
public function close() : bool
{
- // depricated: the database object is shared (don;t clode it!)
+ // DEPRECATED: the database object is shared (don;t clode it!)
// // Close the database connection
// if ($this->db = null) { return true; }
// else return false;
diff --git a/public/app/config/init_routes.php b/public/app/config/init_routes.php
index 22d6ec0..1d697b8 100644
--- a/public/app/config/init_routes.php
+++ b/public/app/config/init_routes.php
@@ -5,7 +5,7 @@
require_once 'app/routes/api.php'; // API: =/api/{table}/{id};/api/*
-require_once 'app/routes/backend.php'; // Backend: =/admin/*
+// require_once 'app/routes/backend.php'; // Backend: =/admin/*
require_once 'app/routes/user.php'; // User account management
diff --git a/public/app/controllers/Auth.php b/public/app/controllers/Auth.php
index f356dfe..e0d84fc 100644
--- a/public/app/controllers/Auth.php
+++ b/public/app/controllers/Auth.php
@@ -166,6 +166,7 @@ class Auth {
// acivate target user and set password
$check = Access_model::activate_set_password($req->POST, $password);
+ // TODO: Cache_service::update_teachers();
if ($check != 0) {
Render::json([
@@ -201,6 +202,7 @@ class Auth {
$req->POST,
$uid
);
+ // TODO: Cache_service::update_teachers();
// user properties changed, so update user's session token
self::reset_user_token($uid);
diff --git a/public/app/controllers/CmsAdmin.php b/public/app/controllers/CmsAdmin.php
deleted file mode 100644
index 9629741..0000000
--- a/public/app/controllers/CmsAdmin.php
+++ /dev/null
@@ -1,676 +0,0 @@
-<?php
-
-namespace app\controllers;
-
-use Registry;
-use Render;
-use app\models\Cms_model;
-use app\extends\Cache_service;
-
-class CmsAdmin {
-
-
- ## -------------------------------------------------------------------------
- ##
- ## COURSE (category) METHODS
- ##
- ## -------------------------------------------------------------------------
-
-
- /** breadcrumbs
- * ---
- * responds to ajax GET: /admin/api/categories
- */
- public static function breadcrumbs()
- {
- Render::json( Cache_service::courses_struct()['breadcrumbs'] );
- }
-
- /** add course
- * ---
- * @param void (get data from POST)
- */
- public static function add_course()
- {
- // insert new category; id = new category id
- $id = Registry::use('database')->query(
- "INSERT INTO course (parent_id, label) VALUES (:parent, :label)",
- [
- ':parent' => Registry::get('REQUEST')->POST['parent_id'],
- ':label' => Registry::get('REQUEST')->POST['label']
- ]
- )->lastInsertID();
-
- $cache = self::update_courses_cache(); // update category caches
- return $cache['breadcrumbs']; // return
- }
-
-
- /** update course
- * ---
- * @param void (get data from POST)
- */
- public static function update_course()
- {
- Registry::use('database')->query(
- "UPDATE course SET parent_id = :parent, label = :label
- WHERE id = :id",
- [
- ':id' => Registry::get('REQUEST')->POST['id'],
- ':parent' => Registry::get('REQUEST')->POST['parent_id'],
- ':label' => Registry::get('REQUEST')->POST['label']
- ]
- );
- $cache = self::update_courses_cache();
- return $cache['breadcrumbs'];
- }
-
-
- /** update courses cache
- * --- -- -- - - -
- * Forces re-caching of courses tree
- * Shall run if anything changes to courses
- *
- * @param void
- * @return (array): ['tree' => ..., 'breadcrumbs' => ... ]
- */
- public static function update_courses_cache()
- {
- return Cache_service::courses_struct(PROXY_IGNORE_CACHE);
- }
-
-
- ## -------------------------------------------------------------------------
- ##
- ## LESSON METHODS
- ##
- ## -------------------------------------------------------------------------
-
-
- /** all lessons
- *
- */
- public static function all_lessons()
- {
- Render::json(Registry::use('database')->runQuery(
- "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson
- LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id",
- []
- ));
- }
-
-
- /** get_lesson
- *
- * @param $id (int) : lesson's id
- */
- public static function get_lesson($id)
- {
- // get (first) lesson with id = $id; render as json
- Render::json(Registry::use('database')->query(
- "SELECT lesson.*,
- ( SELECT
- CONCAT('[', GROUP_CONCAT(JSON_OBJECT(
- 'id', media.id,
- 'label', media.label,
- 'type', media.type,
- 'path', media.path )),
- ']')
- FROM media
- LEFT JOIN lesson_media ON lesson_media.media_id = media.id
- WHERE lesson_media.lesson_id = :id
- ) AS medias_json,
- lesson_privilege.privilege_id
- FROM lesson
- LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id
- WHERE lesson.id = :id",
- [ ':id' => $id]
- )->getFirst());
- }
-
-
- /** add_lesson
- * insert a new lesson
- *
- * all parametres are passed via $_POST array
- *
- * POST @param title
- * POST @param course_id
- * POST @param intro
- * POST @param body
- * POST @param published
- */
- public static function add_lesson()
- {
- $post = Registry::get('REQUEST')->POST;
-
- // insert lesson content into daabase
- $id = Registry::use('database')->query(
- "INSERT INTO lesson (title, course_id, intro, `body`, `status`)
- VALUES (:title, :courseid, :intro, :body, :status)",
- [
- ':title' => $post['title'],
- ':courseid' => $post['course_id'],
- ':intro' => $post['intro'],
- ':body' => $post['body'],
- 'status' => $post['status']
- ]
- )->lastInsertID();
-
- // set lesson privileges to database
- Registry::use('database')->runQuery(
- "INSERT INTO lesson_privilege (lesson_id, privilege_id)
- VALUES (:lesson_id, :privilege_id)",
- [
- ':lesson_id' => $id,
- ':privilege_id' => $post['privilege_id']
- ]
- );
-
- if (isset($post['media'])) {
- // update media's privileges; NOTE: media table
- self::update_medias_privileges($post['media'], $post['privilege_id']);
-
- // set lesson's media files; NOTE: lesson_media table
- // ERROR: self::create_medias_for_lesson($post['media'], $id, $post['privilege_id']);
- self::create_medias_for_lesson($post['media'], $id);
-
- // recache media
- Cache_service::files_attributes(PROXY_IGNORE_CACHE);
- }
-
- return true;
- }
-
-
- public static function update_lesson()
- {
- $post = Registry::get('REQUEST')->POST;
-
- // print_r($post); die();
-
- // update lesson's content
- Registry::use('database')->query(
- "UPDATE lesson
- SET title = :title,
- course_id = :courseid,
- intro = :intro, `body` = :body,
- `status` = :status
- WHERE id = :id",
- [
- ':id' => $post['id'],
- ':title' => $post['title'],
- ':courseid' => $post['course_id'],
- ':intro' => $post['intro'],
- ':body' => $post['body'],
- ':status' => $post['status']
- ]
- );
-
- // update lesson's privileges
- Registry::use('database')->runQuery(
- "UPDATE lesson_privilege SET privilege_id = :privilege_id
- WHERE lesson_id = :lesson_id",
- [
- ':lesson_id' => $post['id'],
- ':privilege_id' => $post['privilege_id']
- ]
- );
-
- if (isset($post['media'])) {
- // update media's privileges
- self::update_medias_privileges($post['media'], $post['privilege_id']);
- }
-
- // remove all old lesson's links to media files
- Registry::use('database')->runQuery(
- "DELETE from lesson_media WHERE lesson_id = :lesson",
- [ ':lesson' => $post['id'] ]
- );
-
- if (isset($post['media'])) {
- // update lesson's media files
- // ERROR: self::create_medias_for_lesson($post['media'], $post['id'], $post['privilege_id']);
- self::create_medias_for_lesson($post['media'], $post['id']);
-
- // recache media
- Cache_service::files_attributes(PROXY_IGNORE_CACHE);
- }
-
- return true;
- }
-
-
- ## -------------------------------------------------------------------------
- ##
- ## FILE METHODS
- ##
- ## -------------------------------------------------------------------------
-
-
- /** 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 : lesson's ID or somthing random
- * POST @param reference : reference type
- * POST @param
- */
- 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 = array(
- 'application/pdf',
- 'image/png', 'image/jpeg',
- 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
- 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
- );
- // 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 lesson
- *
- * links lesson to each media-file of the media `id`s array
- *
- * @param $media (array): a list of media-file `id`s
- * @param $lesson_id (int)
- */
- private static function create_medias_for_lesson($medias, $lesson_id)
- {
- foreach($medias as $key => $medi) {
- self::link_media_to_lesson($medi, $lesson_id); // link to lesson
- }
- return true;
- }
-
-
- /** create media for page
- *
- * links page to each media-file of the media `id`s array
- *
- * @param $media (array): a list of media-file `id`s
- * @param $page_id (int)
- */
- private static function create_medias_for_page($medias, $page_id)
- {
- foreach($medias as $key => $medi) {
- self::link_media_to_page($medi, $page_id); // link to page
- }
- 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 $lesson_id (int)
- */
- private static function link_media_to_lesson( $media_id, $lesson_id )
- {
- Registry::use('database')->runQuery(
- "INSERT INTO lesson_media (lesson_id, media_id)
- VALUES (:lesson, :media)",
- [
- 'lesson' => $lesson_id,
- 'media' => $media_id,
- ]
- );
- return true;
- }
-
- /** link one media-file to a specific page
- *
- * NOTE:
- * the method does not check if media is linked already
- * so be sure that the pair of (media_id, page_id) not exist
- *
- * @param $media_id (int)
- * @param $page_id (int)
- */
- private static function link_media_to_page( $media_id, $page_id )
- {
- Registry::use('database')->runQuery(
- "INSERT INTO page_media (page_id, media_id)
- VALUES (:page, :media)",
- [
- 'page' => $page_id,
- 'media' => $media_id,
- ]
- );
- return true;
- }
-
-
- /** update medias privileges
- *
- * UPDATE media SET privige WHERE IN {list}
- *
- * @param $medias (array) : array of media id(s)
- * @param $privilege (int) : privilege id
- * @return true (always)
- */
- private static function update_medias_privileges($medias, $privilege)
- {
- // create WHERE IN (LIST) holders and params for prepare statement
- $params = [ ':privilege' => $privilege];
- $holders = [];
- foreach($medias as $key => $media) {
- $params[':id'.$key] = $media;
- $holders[] = ':id'.$key;
- }
- $list = '('. implode(',', $holders) .')';
-
- // print_r(['params' => $params, 'list' => $list]); die();
-
- Registry::use('database')->runQuery(
- "UPDATE media SET privilege_id = :privilege
- WHERE id IN {$list}",
- $params
- );
-
- return true;
- }
-
-
-
-
-
-
- ## -------------------------------------------------------------------------
- ##
- ## PAGE METHODS
- ##
- ## -------------------------------------------------------------------------
-
-
- /** all pages
- *
- */
- public static function all_pages()
- {
- Render::json(Registry::use('database')->runQuery(
- "SELECT * FROM page", []
- ));
- }
-
-
- /** get_page
- *
- * @param $id (int) : page's id
- */
- public static function get_page($id)
- {
- // get (first) page with id = $id; render as json
- Render::json(Registry::use('database')->query(
- "SELECT page.*,
- ( SELECT
- CONCAT('[', GROUP_CONCAT(JSON_OBJECT(
- 'id', media.id,
- 'label', media.label,
- 'type', media.type,
- 'path', media.path )),
- ']')
- FROM media
- LEFT JOIN page_media ON page_media.media_id = media.id
- WHERE page_media.page_id = :id
- ) AS medias_json
- FROM page
- WHERE page.id = :id",
- [ ':id' => $id]
- )->getFirst());
- }
-
-
- /** add_page
- * insert a new page
- *
- * all parametres are passed via $_POST array
- *
- * POST @param title
- * POST @param body
- * POST @param status (int): 0 = draft , 1 = published
- */
- public static function add_page()
- {
- $post = Registry::get('REQUEST')->POST;
-
- // insert page content into daabase
- $id = Registry::use('database')->query(
- "INSERT INTO page (title, `body`, `status`)
- VALUES (:title, :body, :status)",
- [
- ':title' => $post['title'],
- ':body' => $post['body'],
- 'status' => $post['status']
- ]
- )->lastInsertID();
-
-
- if (isset($post['media'])) {
- // update media's privileges;
- // NOTE: media table; pages have public files (privilege_id=0)
- self::update_medias_privileges($post['media'], 0);
-
- // set page's media files
- // NOTE: page_media table
- self::create_medias_for_page($post['media'], $id);
- }
-
- self::update_pages_cache(); // update pages cache
-
- return true;
- }
-
-
- /** update_page
- *
- * POST @param id (int)
- * POST @param title
- * POST @param body
- * POST @param status (int): 0 = draft , 1 = published
- */
- public static function update_page()
- {
- $post = Registry::get('REQUEST')->POST;
-
- // print_r($post); die();
-
- // update page's content
- Registry::use('database')->query(
- "UPDATE page
- SET title = :title, `body` = :body, `status` = :status
- WHERE id = :id",
- [
- ':id' => $post['id'],
- ':title' => $post['title'],
- ':body' => $post['body'],
- ':status' => $post['status']
- ]
- );
-
- if (isset($post['media'])) {
- // update media's privileges
- self::update_medias_privileges($post['media'], 0);
- }
-
- // remove all old page's links to media files
- Registry::use('database')->runQuery(
- "DELETE from page_media WHERE page_id = :page",
- [ ':page' => $post['id'] ]
- );
-
- if (isset($post['media'])) {
- // update page's media files
- self::create_medias_for_page($post['media'], $post['id']);
- }
-
- self::update_pages_cache(); // update pages cache
-
- return true;
- }
-
-
- /** update pages cache
- * --- -- -- - - -
- * Forces re-caching of pages tree
- * Shall run if anything changes to courses
- *
- * @param void
- * @return (array): ['tree' => ..., 'breadcrumbs' => ... ]
- */
- public static function update_pages_cache()
- {
- return Cache_service::pages_list(PROXY_IGNORE_CACHE);
- }
-
-} \ No newline at end of file
diff --git a/public/app/controllers/Office.php b/public/app/controllers/Office.php
index 79f76d8..4161efc 100644
--- a/public/app/controllers/Office.php
+++ b/public/app/controllers/Office.php
@@ -7,6 +7,7 @@ use Render;
use app\controllers\Auth;
use app\extends\App_manager;
use app\models\Content_model;
+use app\models\Access_model;
use app\extends\SendMail_service;
use app\extends\Cache_service;
@@ -225,7 +226,7 @@ class Office {
// #3.1: get all teachers
$teachers_array = Registry::use('database')->runQuery(
"SELECT concat(last_name, ' ', first_name) as TeacherName
- FROM user ORDER BY TeacherName", []
+ FROM user WHERE deprecated IS NULL ORDER BY last_name, first_name", []
);
$teachers = []; // constuct teacher names as a simple array
foreach($teachers_array as $key => $person) {
@@ -323,18 +324,9 @@ class Office {
}
- public static function all_petitions()
- {
- if (Auth::in_admin_group()) {
- Render::json([
- 'success' => true,
- 'data' => Content_model::all_petitions()
- ]);
- }
- }
- ## SEND INVITATION
+ ## SEND INVITATION(s)
## -------------------------------------------------------------------------
public static function send_invitation()
@@ -359,11 +351,12 @@ class Office {
"SELECT * FROM user
WHERE id IN ( $all_handlers ) AND (
otp_expiration < :now OR otp_expiration IS NULL
- )",
+ ) AND deprecated IS NULL",
$binds
);
$sent = [];
+ $failed = [];
foreach($recipients as $key => $rec) {
$invitation = md5(
@@ -373,36 +366,34 @@ class Office {
. rand(0, 999999)
);
- /*
$gone = SendMail_service::send_invitation([
'email' => $rec['email'],
- 'name' => $rec['last_name'] .' '. $rec['fisrt_name'],
+ 'name' => $rec['last_name'] .' '. $rec['first_name'],
'code' => $invitation
- ])
+ ]);
- if ($gone) {
- // update user record with invitation
- Registry::use('database')->runQuery(
- "UPDATE user SET invitatopm = :inv WHERE id = :id",
- [ ':inv' => $invitation, ':id' => $rec['id'] ]
- );
+ if ($gone === true) {
+ // update user record with invitation;
+ Access_model::invite_user($rec['id'], $invitation, $expiration);
- $sent[] = $rec['first_name']
- ." ". $rec['last_name']
+ $sent[] = $rec['last_name'] // keep data for echoing
+ ." ". $rec['first_name']
." (". $rec['id'] .")"
.": ". $invitation;
- }
- */
- $sent[] = $rec['first_name']
- ." ". $rec['last_name']
- ." (". $rec['id'] .")"
- .": ". $invitation;
+ } else {
+ $failed[] = [
+ 'rec' => $rec['last_name'] ." ". $rec['first_name']
+ ." (". $rec['id'] .")",
+ 'mdg' => $gone
+ ];
+ }
}
return Render::json([
- 'success' => true,
+ 'success' => (empty($failed)),
'sent' => implode(",\n\n", $sent),
+ 'failed' => $failed
]);
}
diff --git a/public/app/controllers/Petition.php b/public/app/controllers/Petition.php
deleted file mode 100644
index fa73cf0..0000000
--- a/public/app/controllers/Petition.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?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;
-
-
-class Petition {
-
- private static function render_common_petition($opts)
- {
-
- }
-
- 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' => 'user_id', 'value' => $user_id] // pass user identity
- ]);
-
- Render::view('templates/penalty', ['form' => $form]);
-
- }
-
-
-
-
-}
diff --git a/public/app/extends/SendMail_service.php b/public/app/extends/SendMail_service.php
index 64366e0..b80e790 100644
--- a/public/app/extends/SendMail_service.php
+++ b/public/app/extends/SendMail_service.php
@@ -167,7 +167,9 @@ class SendMail_service
$response = json_decode($server_output);
- return ($response->Messages[0]->Status == 'success');
+ return ($response->Messages[0]->Status == 'success')
+ ? true
+ : $response;
}
diff --git a/public/app/models/Access_model.php b/public/app/models/Access_model.php
index c98b6c4..90aac11 100644
--- a/public/app/models/Access_model.php
+++ b/public/app/models/Access_model.php
@@ -22,7 +22,8 @@ class Access_model
public static function checkUser($email)
{
$user = Registry::use('database')->query(
- "SELECT * FROM user WHERE email = :email AND active = 1",
+ "SELECT * FROM user
+ WHERE email = :email AND active = 1 AND deprecated IS NULL",
[ ':email' => $email ]
)->getFirst();
@@ -39,7 +40,8 @@ class Access_model
public static function getUser_byID($uid)
{
$user = Registry::use('database')->query(
- "SELECT * FROM user WHERE id = :uid AND active = 1",
+ "SELECT * FROM user
+ WHERE id = :uid AND active = 1 AND deprecated IS NULL",
[ ':uid' => $uid ]
)->getFirst();
@@ -56,7 +58,8 @@ class Access_model
public static function getUserByInvitation($invitation)
{
return Registry::use('database')->query(
- "SELECT * FROM user WHERE invitation = :invitation",
+ "SELECT * FROM user
+ WHERE invitation = :invitation AND deprecated IS NULL",
[ 'invitation' => $invitation ]
)->getFirst();
}
@@ -177,7 +180,6 @@ class Access_model
History_model::trackUserAccess($post['id'], TRACK_ACCOUNT, 'User Account Activated');
return $rowCount;
-
}
@@ -263,6 +265,69 @@ class Access_model
return $rowCount;
}
+ /** deprecate user account
+ * by @param int $uid: user-id
+ */
+ public static function deprecate_user($uid)
+ {
+ Registry::use('database')->runQuery(
+ "UPDATE user
+ SET active = :active,
+ deprecated = :deprecated
+ WHERE id = :id",
+ [
+ ':active' => 0,
+ ':deprecated' => 1,
+ ':id' => $uid
+ ]
+ );
+ return true;
+ }
+
+
+ /** invite user
+ *
+ * update user with invitation data
+ *
+ * @param int $uid: user-id
+ * @param hash $invitation: MD5 hash invitation
+ * @param int expiration: expiration timestamp
+ */
+ public static function invite_user($uid, $invitation, $expiration)
+ {
+ Registry::use('database')->runQuery(
+ "UPDATE user
+ SET invitation = :inv,
+ otp_expiration = :expiration
+ WHERE id = :id",
+ [
+ ':inv' => $invitation,
+ ':expiration' => $expiration,
+ ':id' => $uid
+ ]
+ );
+ }
+
+
+ /** activate user account
+ * by @param int $uid: user-id
+ */
+ public static function activate_user($uid)
+ {
+ Registry::use('database')->runQuery(
+ "UPDATE user
+ SET active = :active,
+ deprecated = :deprecated
+ WHERE id = :id",
+ [
+ ':active' => 1,
+ ':deprecated' => NULL,
+ ':id' => $uid
+ ]
+ );
+ return true;
+ }
+
## Set permission methods
diff --git a/public/app/routes/api.php b/public/app/routes/api.php
index dd0fecf..e8dbafe 100644
--- a/public/app/routes/api.php
+++ b/public/app/routes/api.php
@@ -12,7 +12,7 @@ use app\controllers\api\Doc_api;
*/
-// depricated: (not needed)
+// DEPRECATED: (not needed)
// api: database documentation
// Route::add('/api/doc',
diff --git a/public/app/routes/frontend.php b/public/app/routes/frontend.php
index 48d5da3..d58d483 100644
--- a/public/app/routes/frontend.php
+++ b/public/app/routes/frontend.php
@@ -1,51 +1,61 @@
<?php
use app\controllers\Auth;
-use app\controllers\App_user;
-use app\controllers\Office;
-use app\extends\Cache_service;
// Home/Welcome
////////////////////////////////////////////////////////////////////////////////
-// Route::add('/', function() { Render::view('welcome'); });
-Route::add('/', function() { Render::view('user/login'); });
+// welcome -> redirecto to login
+Route::add('/', function() { header("Location: /login");; });
-// invitation
+// Error pages
////////////////////////////////////////////////////////////////////////////////
-// request invitation (for account activation)
-// --- -- -- - - -
-Route::add('/invitation/([0-9a-f]*)', function($id) {
- if ($id == "" || $id == "0") { Render::view('error/404');
- } else {
- Auth::invitation($id);
- }
+Route::notFound( function() { // 404 error page
+ header("HTTP/1.0 404 Not Found");
+ Render::view('error/404', ['message' => 'nobody knows it (but you got a secret smile;)']);
});
-// request activation (submit invitation; POST:form is sent)
-// --- -- -- - - -
-Route::add('/account/activate', function() { Auth::activate(); }, 'post');
-// DEPRICATED: user sends a registration form
-// --- -- -- - - -
-# Route::add('/account/register', function() {
-# $response = Auth::register();
-# Render::json($response);
-# },'post');
+// NOTE: this set of routes defines all valid NON-AUTHenticated requests
+////////////////////////////////////////////////////////////////////////////////
+if (!Auth::is_connected()) {
-// Error pages
-////////////////////////////////////////////////////////////////////////////////
+ // request login
+ // render Form -> will POST: /account/check-login
+ // --- -- -- - - -
+ Route::add('/login', function() { Render::view('user/login'); });
-Route::notFound( function() { // 404 error page
- header("HTTP/1.0 404 Not Found");
- Render::view('error/404', ['message' => 'nobody knows it (but you got a secret smile;)']);
-});
+
+ // user sends login form
+ // --- -- -- - - -
+ Route::add('/account/check-login', function() {
+ $response = Auth::login();
+ Render::json(['status' => $response]);
+ }, 'post');
+
+
+ // request invitation (for account activation)
+ // render Form -> will POST /account/activate
+ // --- -- -- - - -
+ Route::add('/invitation/([0-9a-f]*)', function($id) {
+ if ($id == "" || $id == "0") { Render::view('error/404');
+ } else {
+ Auth::invitation($id);
+ }
+ });
+
+
+ // POST invitation = activate
+ // --- -- -- - - -
+ Route::add('/account/activate', function() { Auth::activate(); }, 'post');
+
+}
diff --git a/public/app/routes/user.php b/public/app/routes/user.php
index 622dc57..63e4e07 100644
--- a/public/app/routes/user.php
+++ b/public/app/routes/user.php
@@ -1,8 +1,9 @@
<?php
use app\controllers\Auth;
-use app\controllers\Classroom_user;
use app\controllers\Office;
+use app\models\Content_model;
+use app\models\Access_model;
/** User Connection Management Routes
@@ -12,14 +13,6 @@ use app\controllers\Office;
// common requests (GET method)
// --- -- -- - - -
-// request login ... -> then sends to POST:/account/check-login
-Route::add('/login', function() {
- if (Auth::is_connected()) { header('Location: /panel');
- } else {
- Render::view('user/login');
- }
-});
-
// request logout
Route::add('/logout', function() {
Auth::logout();
@@ -27,53 +20,20 @@ Route::add('/logout', function() {
});
-// TODO:
-// // request password reset
-// Route::add('/account/reset_password', function() { Auth::reset_password(); } );
-
-
-// Replies to common requests (POST method)
-// --- -- -- - - -
-
-// user sends login form
-Route::add('/account/check-login', function() {
- $response = Auth::login();
- Render::json(['status' => $response]);
- },
- 'post'
-);
-
-
-
-/* DEPRICATED:
- // Account Management
- ////////////////////////////////////////////////////////////////////////////////
-
- // user profile
- Route::add('/account/profile', function() {
- $user = Auth::is_connected();
- if ($user === false) {
- Render::view('error/general',
- [
- 'title' => 'Nope!',
- 'message' => "<h2>No profile</h2>User is not connected"
- ]
- );
-
- } else {
- Render::json(['success' => true, 'status' => 'user is connected']);
- }
- }
- );
---- */
-
// routes for connected users
////////////////////////////////////////////////////////////////////////////////
if (Auth::is_connected()) {
- // serve content
+ // login while authenticated ... -> redirect to panel
+ Route::add('/login', function() { header('Location: /panel'); });
+
+ // set invitation while authenticated ... -> redirect to panel
+ Route::add('/invitation/([0-9a-f]*)', function($id) { header('Location: /panel'); });
+
+
+ // SERVE content
// -------------------------------------------------------------------------
// control panel
@@ -159,7 +119,6 @@ if (Auth::is_connected()) {
Office::add_petition();
}, 'post');
-
}
@@ -176,9 +135,27 @@ if (Auth::in_admin_group()) {
});
- // GET JSON: request RESULTS list my petitions
+ // GET HTML: administer users (page)
+ // --- -- -- - - -
+ Route::add('/admin/users', function() {
+ Render::view('templates/admin_users');
+ });
+
+
+ // GET JSON: request RESULTS list all petitions
Route::add('/admin/get/petitions', function() {
- Office::all_petitions();
+ Render::json([
+ 'success' => true,
+ 'data' => Content_model::all_petitions()
+ ]);
+ });
+
+
+ // GET JSON: request RESULTS list all petitions
+ Route::add('/admin/get/users', function() {
+ Render::json( Registry::use('database')->runQuery(
+ "SELECT * FROM user ORDER BY last_name, first_name", []
+ ));
});
@@ -188,22 +165,42 @@ if (Auth::in_admin_group()) {
}, 'post');
+ // GET AJAX: activate user (with user-id)
+ Route::add('/admin/user/activate/([0-9]*)', function( $uid ) {
+ Render::json([ 'success' => Access_model::activate_user($uid) ]);
+ // TODO: Cache_service::update_teachers();
+ });
+
+
+ // GET AJAX: depricate user (with user-id)
+ Route::add('/admin/user/deprecate/([0-9]*)', function( $uid ) {
+ Render::json([ 'success' => Access_model::deprecate_user($uid) ]);
+ // TODO: Cache_service::update_teachers();
+ });
+
+
// invite user(s)
// --- -- -- - - -
Route::add('/admin/invite', function() {
$teachers = Registry::use('database')->runQuery(
"SELECT id, concat(last_name, ' ', first_name) as TeacherName
- FROM user ORDER BY TeacherName
- WHERE otp_expiration < :now OR otp_expiration IS NULL",
+ FROM user
+ WHERE (
+ otp_expiration < :now OR otp_expiration IS NULL
+ ) AND deprecated IS NULL
+ ORDER BY TeacherName",
[ ':now' => time() ]
);
Render::view('templates/invite', ['teachers' => $teachers]);
});
+
// POST AJAX: set petition protocol
+ // --- -- -- - - -
Route::add('/admin/send/invitation', function() {
Office::send_invitation();
}, 'post');
+
}
@@ -214,9 +211,8 @@ if (Auth::in_admin_group()) {
// test connection
if (!PRODUCTION) {
- Route::add('/check/connection', function() { Auth::is_connected(); });
+ Route::add('/check/connection', function() {
+ Render::json( Auth::is_connected() );
+ });
}
-
-
-
diff --git a/public/app/views/components/header_includes.php b/public/app/views/components/header_includes.php
index bd72cb6..c096bd5 100644
--- a/public/app/views/components/header_includes.php
+++ b/public/app/views/components/header_includes.php
@@ -2,6 +2,10 @@
if (!isset($administration)) {
$administration = false;
}
+
+ if (!isset($no_dataTables)) {
+ $no_dataTables = false;
+ }
?>
<!-- FONTS and LIBRARY CSS (self-hosted)
@@ -52,13 +56,15 @@
<script src="<?=SITE_URL?>/assets/js/pdfmake/pdfmake.min.js"></script>
<script src="<?=SITE_URL?>/assets/js/pdfmake/vfs_fonts.js"></script>
+<?php if (!$no_dataTables) : ?>
<!-- DataTables js -->
<script src="/assets/js/DataTables/datatables.min.js"></script>
+<?php endif; ?>
<!-- select2-4.1.0-rc.0 js -->
<script src="/assets/js/select2-4.1.0-rc0/js/select2.min.js"></script>
-<?php /* DEPRICATED:
+<?php /* DEPRECATED:
<!-- marked -->
<script src="/assets/js/marked/marked.min.js"></script>
*/
diff --git a/public/app/views/components/menu.php b/public/app/views/components/menu.php
index 30ed673..08d459b 100644
--- a/public/app/views/components/menu.php
+++ b/public/app/views/components/menu.php
@@ -21,6 +21,7 @@
<?php if ($is_admin) : ?>
<li class="list-group-item separator">Διαχείριση</li>
<li class="list-group-item"><a href="/admin/petitions">Κατάσταση πρακτικών & αιτήσεων</a></li>
+ <li class="list-group-item"><a href="/admin/users">Διαχείριση Χρηστών</a></li>
<li class="list-group-item"><a href="/admin/invite">Αποστολή προσκλήσεων</a></li>
<?php endif; ?>
diff --git a/public/app/views/components/theme.php b/public/app/views/components/theme.php
index 4e95193..a769dce 100644
--- a/public/app/views/components/theme.php
+++ b/public/app/views/components/theme.php
@@ -1,9 +1,29 @@
<?php
+/** themes
+ * --- -- -- - - -
+ * auto select one id of L = array.LENGTH, per month:
+ * ( ( (month*31 + day) % L*2 ) div 2 )
+ * this will allow theme exchange every 2 days
+ *
+ *
+ * 4-day rollup:
+ * --- -- -- - - -
+ * supports up to 21 themes/season
+ * = 84 themes/year
+ *
+ * algo:
+ * ( ( ( month*31 + day) % L*4 ) div 4 )
+ * change seasonal theme every 4 days
+ * ... Catch Exceptions:
+ * if (month == 12) : month = 0
+ * if (month == 6 && day == 1) then day = 2
+ *
+ */
-// decide a theme according to month
-$month = idate('m');
+// decide a theme season according to month
+$mo = intval(date('m'));
-switch ($month) {
+switch ($mo) {
case 12: case 1: case 2:
$season = 'winter';
break;
@@ -25,27 +45,6 @@ switch ($month) {
}
-/** themes
- * --- -- -- - - -
- * auto select one id of L = array.LENGTH, per month:
- * ( ( (month*31 + day) % L*2 ) div 2 )
- * this will allow theme exchange every 2 days
- *
- *
- * 4-day rollup:
- * --- -- -- - - -
- * supports up to 21 themes/season
- * = 84 themes/year
- *
- * algo:
- * ( ( ( month*31 + day) % L*4 ) div 4 )
- * change seasonal theme every 4 days
- * ... Catch Exceptions:
- * if (month == 12) : month = 0
- * if (month == 6 && day == 1) then day = 2
- *
- */
-
$theme_def = [
# --- summer ---
@@ -76,15 +75,40 @@ $theme_def = [
'label' => 'Doc Searls: Amazing Santa Barbara sunset (2014/01)'
],
+ 'f9' => [
+ 'css' => 'fall-09',
+ 'url' => 'https://www.freepik.com/free-photo/flock-birds-flying-during-sunset_13962565.htm',
+ 'label' => 'wirestock: View of a flock of birds flying into a beautiful sky during sunset'
+ ],
+
# --- winter ---
+ 'w3' => [
+ 'css' => 'winter-03',
+ 'url' => 'https://unsplash.com/photos/yzkoleKww6w',
+ 'label' => 'Raimond Klavins: Snow covered mountain under blue sky during daytime, Himalayas'
+ ],
+
+ 'w8' => [
+ 'css' => 'winter-08',
+ 'url' => 'https://www.freepik.com/free-photo/3d-iceberg-blue-sea_3585791.htm',
+ 'label' => 'kjpargeter: 3d iceberg in blue sea'
+ ],
+
'w9' => [
'css' => 'winter-09',
'url' => 'https://www.freepik.com/free-photo/abstract-water-waves-with-ink-dots_5068293.htm',
'label' => 'freepik: Abstract water waves with ink dots'
],
+ 'w10' => [
+ 'css' => 'winter-10',
+ 'url' => 'https://unsplash.com/photos/D1eFDB4CMj0',
+ 'label' => 'Vidar Nordli-Mathisen: Skogsøya, Norway'
+ ],
+
+
# --- spring ---
'g1' => [
@@ -111,21 +135,28 @@ $theme_def = [
$themes = [
- 'summer' => [ 's1', 's5', 'g9', 's2', 'g1' ],
+ 'summer' => [ 's1', 's2', 's5', 'g9', 'g1' ],
- 'fall' => [ 'f8', 's5', 'g4', 's2' ],
+ 'fall' => [ 'f8', 's5', 'g4', 's2', 'f9' ],
- 'winter' => [ 'w9' ],
+ 'winter' => [ 'w3', 'w8', 'w9', 'w10' ],
- 'spring' => [ 'g1', 'g4', 'g9' ]
+ 'spring' => [ 'g1', 'g4', 'w3', 'g9', 'f9' ]
];
+/** check algo in the begining of this file */
+$day = intval(date('d'));
+$themesLen = count($themes[$season]);
+if ($mo == 12) { $mo = 0; }
+if ($mo == 6 && $day == 1) { $day == 2; }
+$imageID = intdiv( ( ( $mo*31 + $day) % $themesLen*4 ), 4 );
-define('THEME', $theme_def[ $themes['summer'][0] ]);
+define('THEME', $theme_def[ $themes[ $season ][ $imageID ] ]);
+// testing: define('THEME', $theme_def[ $themes[ 'winter' ][ 1 ] ]);
?>
<!-- theme overides -->
diff --git a/public/app/views/js/credits.php b/public/app/views/js/credits.php
index ca0f15c..5dd3fe6 100644
--- a/public/app/views/js/credits.php
+++ b/public/app/views/js/credits.php
@@ -5,6 +5,30 @@ ic_div.innerHTML = '<a href="<?=THEME['url']?>" target="_blank" title="Attributi
ic_div.className = 'image-credits';
// append image-credits div to body
-document.querySelector('body').appendChild(ic_div);
+document.querySelector('body').appendChild(ic_div);
+
+// make sure...
+// the user agrees with cookie-policy on his device
+let cookieExp = 3600*24*200; // cookie expiration (200 days)
+if (!cookieExists('operational') || (readCookie('operational') == 'no')) {
+ let confirm_cookies = confirm([
+ 'Ο ιστότοπος χρησιμοποιεί cookies τα οποία έχουν αποκλειστικά λειτουργικό ρόλο.',
+ ' ',
+ 'Ειδικότερα:',
+ '– ένα Session cookie που εγγυάται την ασφάλεια της σύνδεσής σας',
+ '– ένα Http-only cookie που διατηρεί κωδικοποιημένη την κατάσταση της σύνδεσής σας μετά την είσοδό σας στο σύστημα, και',
+ '– ένα cookie που εξετάζει αν έχετε αποδεχθεί τη χρήση αυτών των cookies.',
+ ' ',
+ 'Και τα 3 αυτά cookies είναι Secure, Same-site, Non-Tracking cookies.',
+ ' ',
+ 'Συμφωνείτε με τη διατήρηση αυτών των cookies;'
+ ].join('\n'))
+ if (!confirm_cookies) {
+ window.location.href = 'https://en.wikipedia.org/wiki/HTTP_cookie';
+
+ } else {
+ createCookie('operational', 'yes', cookieExp);
+ }
+}
</script> \ No newline at end of file
diff --git a/public/app/views/js/submit/application-form.php b/public/app/views/js/submit/application-form.php
index 272fbcb..d34b249 100644
--- a/public/app/views/js/submit/application-form.php
+++ b/public/app/views/js/submit/application-form.php
@@ -70,7 +70,7 @@
// bolditalics: 'https://example.com/fonts/fontFile4.ttf'
},
FiraMono: {
- normal: '<?=SITE_URL?>/assets/fonts/FiraMono-Regular.ttf',
+ normal: '<?=SITE_URL?>/assets/fonts/FiraMono-Regular.ttf'
}
}
diff --git a/public/app/views/templates/admin_users.php b/public/app/views/templates/admin_users.php
new file mode 100644
index 0000000..baa2e58
--- /dev/null
+++ b/public/app/views/templates/admin_users.php
@@ -0,0 +1,134 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title><?=SITE_TITLE?> - Control Panel</title>
+
+ <?php // header includes
+ ////////////////////////////////////////////////////////////////////////
+ Render::view('components/header_includes');
+ ?>
+<style>
+:root { /* login-form overides */
+ --form-content-font-size: 1rem;
+ --form-input-height: 34px;
+ --select2-arrow-top: 1px;
+}
+</style>
+</head>
+<body class="office central-form left-menu">
+
+ <div class='container'>
+ <div class='content row'>
+
+ <div class="col-sm-12">
+
+<div class="manage">
+ <!-- title bar -->
+ <div class="title-bar">
+ <div class="row">
+ <h5 class="col-md-10">Διαχείριση Χρηστών</h5>
+ <div class="col-md-2">
+ <a type="button" class="btn btn-sm btn-back2panel pull-right" href="/panel">
+ Επιστροφή
+ </a>
+ </div>
+ </div>
+
+ </div>
+
+
+ <div class="row">
+ <div class="col-md-12">
+
+ <div id="petitions">
+
+ <table id="dt-petitions" class="table table-responsive dt-table" style="width:100%">
+ <thead>
+ <th class="dt-last_name">Επίθετο</th>
+ <th class="dt-first_name">Όνομα</th>
+ <th class="dt-email">email</th>
+ <th class="dt-sector">Τομέας</th>
+ <th class="dt-status">Status</th>
+ <th class="dt-actions"></th>
+ </thead>
+ </table>
+
+ </div>
+
+ </div>
+ </div>
+
+</div><!-- /manage -->
+
+ </div>
+
+ </div>
+ </div>
+
+
+
+
+ <!-- MODAL for set protocol number -->
+ <div class="modal fade" id="managePetition" aria-labelledby="myModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+
+ <form method="post" action="">
+
+ <div class="modal-header">
+ <h4 class="modal-title" id="myModalLabel">Ενημέρωση αριθμού πρωτόκολλου</h4>
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+ </div><!-- /modal-header -->
+
+ <!-- modal-body -->
+ <div class="modal-body">
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="protocol">Αριθμός Πρψτοκόλλου</label>
+ <div class="col-sm-12">
+ <input class="form-control form-control-sm" type="text" name="protocol" value="" required="">
+ </div>
+ </div>
+
+ <div class="row form-group"><!-- hiddens -->
+ <input type="hidden" name="id" value="0"><!-- petition-id -->
+ <input type="hidden" name="signature" value=""><!-- signature -->
+ </div>
+
+ </div><!-- /modal body -->
+
+ <div class="modal-footer">
+ <div class="row form-actions" style="width: 50%;">
+
+ <div class="col-sm-4">
+ <button type="button" class="btn btn-default js-modal-close col-12" data-bs-dismiss="modal">Κλείσιμο</button>
+ </div>
+ <div class="col-sm-8">
+ <button class="btn btn-primary col-12" type="submit">Καταχώριση</button>
+ </div>
+
+ </div>
+ </div><!-- /modal-footer -->
+
+ </form><!-- /form -->
+
+ </div>
+ </div>
+ </div>
+
+ </body>
+
+<script src="/assets/js/panel/admin_users.js"></script>
+
+ <!-- scripts
+ * handle show petition request
+
+ if admin:
+ * modal + give protocol-number
+ -->
+<?php // credits
+ //////////////////////////////////////////////////////////////////////////////
+ Render::view('js/credits');
+?>
+</html>
diff --git a/public/app/views/templates/application.php b/public/app/views/templates/application.php
index 35b1435..72c9251 100644
--- a/public/app/views/templates/application.php
+++ b/public/app/views/templates/application.php
@@ -6,7 +6,7 @@
<?php // header includes
////////////////////////////////////////////////////////////////////////
- Render::view('components/header_includes');
+ Render::view('components/header_includes', [ 'no_dataTables' => true ]);
?>
</head>
diff --git a/public/app/views/templates/create_pdf.php b/public/app/views/templates/create_pdf.php
index 19b2894..6b5c164 100644
--- a/public/app/views/templates/create_pdf.php
+++ b/public/app/views/templates/create_pdf.php
@@ -58,7 +58,7 @@ pdfMake.fonts = {
// bolditalics: 'https://example.com/fonts/fontFile4.ttf'
},
FiraMono: {
- normal: '<?=SITE_URL?>/assets/fonts/FiraMono-Regular.ttf',
+ normal: '<?=SITE_URL?>/assets/fonts/FiraMono-Regular.ttf'
}
}
diff --git a/public/app/views/templates/invite.php b/public/app/views/templates/invite.php
index d7947da..ab0f12c 100644
--- a/public/app/views/templates/invite.php
+++ b/public/app/views/templates/invite.php
@@ -59,7 +59,7 @@
</form>
</div>
- <div class="info">
+ <div class="info clear-read">
<p>
Χρησιμοποιήστε τη φόρμα για να προσκαλέσετε νέους χρήστες
ή για reset ενός account.
@@ -120,7 +120,11 @@ $(document).ready(function() {
window.location.href = '/panel';
} else {
- alert('Τα στοιχεία πρόσβασης που δώσατε είναι λάθος. Παρακαλώ προσπαθήστε ξανά.');
+ alert([
+ 'Κατάσταση αποστολής προσλήσεων:\\n\n',
+ data.sent,
+ 'Υπήρξαν προβλήματα στην αποστολή κάποιων προσκλήσεων.'
+ ].join(''));
}
});
diff --git a/public/app/views/templates/penalty.php b/public/app/views/templates/penalty.php
index cad9221..232e8a8 100644
--- a/public/app/views/templates/penalty.php
+++ b/public/app/views/templates/penalty.php
@@ -6,7 +6,7 @@
<?php // header includes
////////////////////////////////////////////////////////////////////////
- Render::view('components/header_includes');
+ Render::view('components/header_includes', [ 'no_dataTables' => true ]);
?>
</head>
@@ -93,7 +93,7 @@
-<!-- DEPRICATED:
+<!-- DEPRECATED:
<script>
$(document).ready(function() {
diff --git a/public/app/views/user/invitation.php b/public/app/views/user/invitation.php
index 328c621..64e5bcb 100644
--- a/public/app/views/user/invitation.php
+++ b/public/app/views/user/invitation.php
@@ -6,7 +6,7 @@
<?php // header includes
////////////////////////////////////////////////////////////////////////
- Render::view('components/header_includes');
+ Render::view('components/header_includes', [ 'no_dataTables' => true ]);
?>
</head>
<body class="office central-form">
@@ -37,7 +37,7 @@
</form>
</div>
- <div class="info">
+ <div class="info clear-read">
<p>
Απαιτείται η συμπλήρωση όλων των στοιχείων
προκειμένου να γίνεται γρήγορα η σύνταξη των εγγράφων.
diff --git a/public/app/views/user/login.php b/public/app/views/user/login.php
index 6bf3b0a..a9517c6 100644
--- a/public/app/views/user/login.php
+++ b/public/app/views/user/login.php
@@ -45,7 +45,7 @@
</form>
</div>
- <div class="info">
+ <div class="info clear-read">
<!--
<p>Αν ξεχάσατε τον κωδικό πρόσβασης μπορείτε να δημιουργήσετε ένα νέο (υπο κατασκευή).</p>
-->
@@ -53,10 +53,6 @@
Εαν δικαιούστε αλλά δεν έχετε πρόσβαση στο site, παρακαλούμε επικοινωνήστε
με τη διεύθυνση του σχολείου προκειμένου να σας αποσταλεί σχετική πρόσκληση.
</p>
- <p>
- Ο ιστότοπος χρησιμοποιεί cookies τα οποία έχουν αποκλειστικά λειτουργικό ρόλο.
- Η χρήση των υπηρεσιών του site συνεπάγεται την αποδοχή διατήρησης αυτών των cookies.
- </p>
</div>
</div>
diff --git a/public/app/views/user/update_password.php b/public/app/views/user/update_password.php
index 38494ad..b415f7c 100644
--- a/public/app/views/user/update_password.php
+++ b/public/app/views/user/update_password.php
@@ -6,7 +6,7 @@
<?php // header includes
////////////////////////////////////////////////////////////////////////
- Render::view('components/header_includes');
+ Render::view('components/header_includes', [ 'no_dataTables' => true ]);
?>
</head>
<body class="office central-form">
diff --git a/public/assets/css/class.css b/public/assets/css/class.css
index 6c0c1bf..7aa3a2a 100644
--- a/public/assets/css/class.css
+++ b/public/assets/css/class.css
@@ -25,6 +25,7 @@
/* layer backgrounds */
--form-layer-bgr: #dddb; /* form layer background */
--backlayer-bgr: transparent;
+ --clear-read-bgr: #fff5;
/* select2 */
--select2-arrow-top: 10px;
@@ -350,6 +351,8 @@ input.form-control-sm { height: var(--form-input-height); }
}
-
.btn-xs { height: 24px; padding: 1px 8px; font-size: 14px; }
+
+.clear-read p { padding: 8px; border-radius: 6px; }
+.clear-read p:hover, .clear-read p:active { background: var(--clear-read-bgr); } \ No newline at end of file
diff --git a/public/assets/css/themes/fall-09.css b/public/assets/css/themes/fall-09.css
new file mode 100644
index 0000000..05681ef
--- /dev/null
+++ b/public/assets/css/themes/fall-09.css
@@ -0,0 +1,8 @@
+:root {
+ --background-image: url(/assets/media/fall-09.webp);
+ --form-layer-bgr: #cccc;
+ --bs-heading-color: #657;
+ --menu-hover-bgr: #fff0dc;
+ --info-text-color: #112;
+ --img-credit-hover-color: #334;
+}
diff --git a/public/assets/css/themes/spring-09.css b/public/assets/css/themes/spring-09.css
index 97fe4bb..39c3ed3 100644
--- a/public/assets/css/themes/spring-09.css
+++ b/public/assets/css/themes/spring-09.css
@@ -1,7 +1,7 @@
:root {
--background-image: url(/assets/media/spring-09.webp);
--bs-heading-color: #230;
- --menu-hover-bgr: #bee;
+ --menu-hover-bgr: #d6f899;
--info-text-color: #334;
--img-credit-hover-color: #334;
}
diff --git a/public/assets/css/themes/winter-03.css b/public/assets/css/themes/winter-03.css
new file mode 100644
index 0000000..b8e9df7
--- /dev/null
+++ b/public/assets/css/themes/winter-03.css
@@ -0,0 +1,13 @@
+:root {
+ --background-image: url(/assets/media/winter-03.webp);
+ --bs-heading-color: #035;
+ --menu-hover-bgr: #cef;
+ --info-text-color: #223;
+
+ --img-credit-hover-color: #334;
+ --img-credit-bgr: transparent;
+ --img-credit-color: #9aa;
+}
+
+.central-form form label { color: #313; }
+tbody, td, tfoot, th, thead, tr { border-color: #def7; } \ No newline at end of file
diff --git a/public/assets/css/themes/winter-08.css b/public/assets/css/themes/winter-08.css
new file mode 100644
index 0000000..c589e34
--- /dev/null
+++ b/public/assets/css/themes/winter-08.css
@@ -0,0 +1,11 @@
+:root {
+ --background-image: url(/assets/media/winter-08.webp);
+ --bs-heading-color: #035;
+ --menu-hover-bgr: #cef;
+ --info-text-color: #223;
+
+ --img-credit-hover-color: #334;
+}
+
+.central-form form label { color: #313; }
+tbody, td, tfoot, th, thead, tr { border-color: #def7; } \ No newline at end of file
diff --git a/public/assets/css/themes/winter-10.css b/public/assets/css/themes/winter-10.css
new file mode 100644
index 0000000..0673bd0
--- /dev/null
+++ b/public/assets/css/themes/winter-10.css
@@ -0,0 +1,25 @@
+/* dark theme */
+:root {
+ --background-image: url(/assets/media/winter-10.webp);
+ --light-grey-shade: 1px 5px 7px #2227;
+ --form-layer-bgr: #878b;
+ --clear-read-bgr: transparent;
+
+ --table-row-bgr: #eee2;
+ --table-odd-row-bgr: #fff3;
+ --table-head-bgr: #fff5;
+ --table-row-hover-bgr: #0137;
+
+ --bs-heading-color: #dcb;
+ --info-text-color: #c8b5a3;
+ --menu-hover-bgr: #fcc;
+
+ --img-credit-hover-color: #334;
+ --img-credit-bgr: transparent;
+ --img-credit-color: #9aa;
+}
+
+.central-form form label { color: #fed; }
+
+tbody, td, tfoot, th, thead, tr { border-color: transparent; }
+table.dt-table tr > td, table.dt-table tr > th { color: #fff; }
diff --git a/public/assets/js/panel/admin_users.js b/public/assets/js/panel/admin_users.js
new file mode 100644
index 0000000..62a2aff
--- /dev/null
+++ b/public/assets/js/panel/admin_users.js
@@ -0,0 +1,177 @@
+// Globals
+// -----------------------------------------------------------------------------
+var petitions = [];
+var table;
+
+
+
+// Supplamentary functions
+// -----------------------------------------------------------------------------
+
+// array.indexOf polyfill
+// --- -- -- - - -
+if (!Array.prototype.indexOf)
+{
+ Array.prototype.indexOf = function(elt /*, from*/)
+ {
+ var len = this.length >>> 0;
+
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0)
+ ? Math.ceil(from)
+ : Math.floor(from);
+ if (from < 0)
+ from += len;
+
+ for (; from < len; from++)
+ {
+ if (from in this &&
+ this[from] === elt)
+ return from;
+ }
+ return -1;
+ };
+}
+
+
+// return petitions user by user-id
+// --- -- -- - - -
+function user_record(id) {
+ var record = false;
+ petitions.forEach(el => { if (el.id == id) record = el; });
+
+ return record;
+}
+
+
+// create actions html (edit and delete buttons)
+// --- -- -- - - -
+function create_actions_html(el) {
+ if (el.deprecated == null) {
+ icon = '<i class="fa-solid fa-minus"></i>';
+ action = 'deprecate';
+ title = 'κατάργηση';
+ type = 'warning';
+
+ } else {
+ icon = '<i class="fa-solid fa-plus"></i>';
+ action = 'activate';
+ title = 'προσθήκη';
+ type = 'primary';
+ }
+
+ return [
+ '<button type="button" class="btn btn-xs btn-'+ type +'" title="'+ title +'"',
+ 'data-id="'+ el.id +'" data-action="'+ action +'" >',
+ icon,
+ '</button>'
+ ].join('\n');
+
+}
+
+
+
+$(document).ready(function() {
+
+ // When document is ready
+ // -------------------------------------------------------------------------
+
+
+ /** init_table
+ * --- -- -- - - -
+ * get categories
+ * constuct categories array
+ * render dataTable
+ */
+ function init_table() {
+
+ // get all categories from server (ajax)
+ $.getJSON( "/admin/get/users")
+ .done(function( json ) {
+ // then ...
+ console.log(json);
+
+ // reset categories
+ petitions.length = 0;
+
+ // construct petitions data
+ json.forEach( el => {
+ rec = {
+ id: parseInt(el.id),
+ first_name: el.first_name,
+ last_name: el.last_name,
+ email: el.email,
+ sector: el.sector,
+ status: (el.deprecated == 1)
+ ? ('<i class="fa-regular fa-eye-slash"></i> / deprecated')
+ : ('<i class="fa-regular fa-eye"></i> / ' + ((el.active == 1)
+ ? 'active'
+ : 'pending')
+ ),
+ deprecated: el.deprecated
+ }
+ rec.actions = create_actions_html(rec);
+ petitions.push(rec);
+ });
+
+
+ // destroy previous datatable table instances
+ $('#dt-petitions').dataTable().fnClearTable();
+ $('#dt-petitions').dataTable().fnDestroy();
+
+ // (re-)create categories datatable
+ table = $('#dt-petitions').DataTable({
+ language: { url: '/assets/js/DataTables/localization/Greek.json' },
+ data: petitions,
+ // ordering: false,
+ columns: [
+ { data: 'last_name' },
+ { data: 'first_name'},
+ { data: 'email' },
+ { data: 'sector' },
+ { data: 'status' },
+ { data: 'actions', class: 'dt-actions' }
+ ]
+ });
+
+ })
+ .fail(function( jqxhr, textStatus, error ) {
+ console.log( "Request Failed (" + error +")" );
+ });
+
+ }
+ init_table(); // init table on first run
+
+
+
+ /** When click to action button
+ * -------------------------------------------------------------------------
+ */
+ $('body').on('click', '.dt-actions button', event => {
+ event.preventDefault();
+ var button;
+
+ if ($(event.target).data('id')) { // click on button
+ button = $(event.target)
+
+ } else { // click on button's content
+ button = $(event.target).parent('button');
+ }
+
+ var id = button.data('id'); // user-id from data-id
+ var action = button.data('action'); // action to take
+
+ console.log(action, id);
+
+ var request = '/admin/user/'+ action +'/'+ id;
+
+ $.get(request)
+ .done(function(data) {
+ init_table();
+ });
+
+ })
+
+
+
+});
diff --git a/public/assets/media/credits.txt b/public/assets/media/credits.txt
index ba6120d..adcf74d 100644
--- a/public/assets/media/credits.txt
+++ b/public/assets/media/credits.txt
@@ -59,7 +59,6 @@ https://unsplash.com/photos/2s3fI3M1lO0
+? https://unsplash.com/photos/OF7jUVrEDJQ
++ https://unsplash.com/photos/DxRXjBQAb8I : Nykvåg, Norway -> text:#fee
++ https://unsplash.com/photos/NWANKTV5yHU : Leknes, Norway
-++ https://unsplash.com/photos/D1eFDB4CMj0 : -> text:#dcb
++ https://unsplash.com/photos/wyM1KmMUSbA : Vittangi, Sweden
++ https://unsplash.com/photos/6gVOt8qOJ08 : Ljungskile, Sweden
++ https://unsplash.com/photos/AkUR27wtaxs : Högakustenbron, Sweden -> text:#fed
@@ -192,7 +191,6 @@ winter+spring
winter
-++ https://www.freepik.com/free-photo/3d-iceberg-blue-sea_3585791.htm
++ https://www.freepik.com/free-photo/fantastic-winter-landscape-mountains-magical-sunset_9144399.htm
+++ https://www.freepik.com/free-photo/cottage-glen-etive-scotland_16462487.htm
@@ -292,7 +290,7 @@ https://www.flickr.com/photos/138402863@N02/23445581921/ !++
https://www.flickr.com/photos/78423546@N06/43429924691/ = PD
https://www.flickr.com/photos/78423546@N06/42135640880/ = PD
https://www.flickr.com/photos/78423546@N06/52780304947/ = PD
-https://www.flickr.com/photos/tomcollinsphoto/40178410432/ !++
+https://www.flickr.com/photos/tomcollinsphoto/40178410432/ !+++
https://www.flickr.com/photos/164417177@N06/44004978630/ ?
https://www.flickr.com/photos/94284791@N05/39229046194/ !
https://www.flickr.com/photos/hoanghaithinh/45678059161/
@@ -306,3 +304,12 @@ https://www.flickr.com/photos/129030830@N02/37032688484/
https://www.flickr.com/photos/drtonygeorge/1474585836/ !
*/
+
+
+
+[downloaded]
+wirestock
+Breathtaking shot of the lake wanaka in wanaka village, new zealand
+breathtaking-shot-lake-wanaka-wanaka-village-new-zealand.jpg
+https://www.freepik.com/free-photo/breathtaking-shot-lake-wanaka-wanaka-village-new-zealand_11111328.htm
+
diff --git a/public/assets/media/fall-09.webp b/public/assets/media/fall-09.webp
new file mode 100644
index 0000000..09795e1
--- /dev/null
+++ b/public/assets/media/fall-09.webp
Binary files differ
diff --git a/public/assets/media/summer-0.jpg b/public/assets/media/summer-0.jpg
deleted file mode 100644
index e4deb86..0000000
--- a/public/assets/media/summer-0.jpg
+++ /dev/null
Binary files differ
diff --git a/public/assets/media/summer-01.jpg b/public/assets/media/summer-01.jpg
deleted file mode 100644
index b769bf5..0000000
--- a/public/assets/media/summer-01.jpg
+++ /dev/null
Binary files differ
diff --git a/public/assets/media/winter-03.jpg b/public/assets/media/winter-03.jpg
deleted file mode 100644
index 383cb91..0000000
--- a/public/assets/media/winter-03.jpg
+++ /dev/null
Binary files differ
diff --git a/public/assets/media/winter-03.webp b/public/assets/media/winter-03.webp
new file mode 100644
index 0000000..aa1303e
--- /dev/null
+++ b/public/assets/media/winter-03.webp
Binary files differ
diff --git a/public/assets/media/winter-08.jpg b/public/assets/media/winter-08.jpg
deleted file mode 100644
index 291bc9d..0000000
--- a/public/assets/media/winter-08.jpg
+++ /dev/null
Binary files differ
diff --git a/public/assets/media/winter-08.webp b/public/assets/media/winter-08.webp
new file mode 100644
index 0000000..c06cc6c
--- /dev/null
+++ b/public/assets/media/winter-08.webp
Binary files differ
diff --git a/public/assets/media/winter-10.webp b/public/assets/media/winter-10.webp
new file mode 100644
index 0000000..7885773
--- /dev/null
+++ b/public/assets/media/winter-10.webp
Binary files differ