diff options
Diffstat (limited to 'public')
26 files changed, 474 insertions, 275 deletions
diff --git a/public/app/config/.gitkeep b/public/app/config/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/config/.gitkeep diff --git a/public/app/controllers/.gitkeep b/public/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/controllers/.gitkeep diff --git a/public/app/controllers/Auth.php b/public/app/controllers/Auth.php index 0570a5e..8af7513 100644 --- a/public/app/controllers/Auth.php +++ b/public/app/controllers/Auth.php @@ -180,7 +180,11 @@ class Auth { } - + /** is_connected + * checks if the user is connected + * + * @return true|false + */ public static function is_connected() { $manager = new Classroom_manager(); @@ -193,13 +197,17 @@ class Auth { return $user; } else { - echo 'user is not connected'; + // user is not connected; return false; } } - + /** logout + * + * performs a secure logout; + * regenerates session; deletes cookies; + */ public static function logout() { $userManager = new Classroom_manager(); @@ -232,7 +240,7 @@ class Auth { return true; // permision 0 is always granted } - if ($user = $this->is_connected() === flase) { // if not connected + if ($user = self::is_connected() === false) { // if not connected return false; // then no other permition is granted } @@ -340,6 +348,18 @@ class Auth { } + /** hasValidRole + * like allowRoles() but dowes not stop execution + * + * @return true|false + */ + public static function hasValidRole($allowed) + { + $manager = new Classroom_manager(); + return ($manager->isGranted($allowed)); + } + + public static function in_admin_group() { $manager = new Classroom_manager(); diff --git a/public/app/controllers/admin/Course_admin.php b/public/app/controllers/admin/Course_admin.php index c2e06f2..72ddc79 100644 --- a/public/app/controllers/admin/Course_admin.php +++ b/public/app/controllers/admin/Course_admin.php @@ -213,8 +213,10 @@ class Course_admin { ] ); - // update media's privileges - self::update_medias_privileges($post['media'], $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( @@ -222,8 +224,10 @@ class Course_admin { [ ':lesson' => $post['id'] ] ); - // update lesson's media files - self::create_medias_for_lesson($post['media'], $post['id'], $post['privilege_id']); + if (isset($post['media'])) { + // update lesson's media files + self::create_medias_for_lesson($post['media'], $post['id'], $post['privilege_id']); + } return true; } diff --git a/public/app/controllers/cli/CliContoller.php b/public/app/controllers/cli/CliContoller.php index 310e2ae..4549b50 100644 --- a/public/app/controllers/cli/CliContoller.php +++ b/public/app/controllers/cli/CliContoller.php @@ -4,9 +4,11 @@ namespace app\controllers\cli; /** CliContoller * - * Re-generate cashes of commonly used entities - * like: product categories and trendy products - * (proxy calls make use of PROXY_IGNORE_CACHE) + * A typical cli constoller; this one is used to + * re-generate cashes of commonly used entities + * with expensive queries like (ex:) categories; + * + * Proxy calls make use of PROXY_IGNORE_CACHE * * CliController calls Model methods who create * cashed data with the exact same arguments as @@ -14,8 +16,8 @@ namespace app\controllers\cli; * the Model::method(arguments) triplete creates * the same keys as via the web interface. * - * NOTE: Only Cli interface is allowed - * [if (php_sapi_name() != 'cli') return false;] + * NOTE: Only Cli interface is allowed¨ + * `if (php_sapi_name() != 'cli') return false;` * * The Cli-interfaced script can run manualy or * (most usual scenario) scheduled via a cron job @@ -37,12 +39,12 @@ class CliContoller if (php_sapi_name() != 'cli') return false; # PROXY call: - # MARKET \ ProductCategories_model::tree(): + # CMS \ Course_model::courses_struct(): # + Refresh Cache # -------------------------------------- echo textColor("Creating category_products tree Cache ... ", \NORMAL); $reply = proxy( - [\app\models\market\ProductCategories_model::class, 'tree'], + [\app\models\cms\Course_model::class, 'courses_struct'], [], \CACHE_ROOT_TTL, \PROXY_IGNORE_CACHE ); @@ -50,36 +52,4 @@ class CliContoller } - - public static function getProductCategories() - { - return \Registry::use('database')->runQuery( - "SELECT * FROM product_categories", - [] - ); - } - - - - /** (re-) cacheCategoryByUrl( url ) - * regenerate cache of a category_product - * by category's friendly url - * @param $url (string): the category's friendly url - */ - public static function cacheCategoryByUrl(string $url) - { - // Only Cli interface is allowed - if (php_sapi_name() != 'cli') return false; - - # PROXY call: - # MARKET \ ProductCategories_model::tree(): - # + Refresh Cache - # -------------------------------------- - $reply = proxy( - [\app\models\market\ProductCategories_model::class, 'categoryFromUrl'], - [ $url ], \CACHE_CATEGORY_TTL, - \PROXY_IGNORE_CACHE - ); - echo ($reply == false) ? textColor("Failed\n", \FAIL) : textColor("Done!\n", \SUCCESS); - } }
\ No newline at end of file diff --git a/public/app/controllers/cms/Course.php b/public/app/controllers/cms/Course.php index 7e53d3a..0edc832 100644 --- a/public/app/controllers/cms/Course.php +++ b/public/app/controllers/cms/Course.php @@ -21,7 +21,7 @@ class Course { * shortcut method for checking access authorization * * returns true if user belogns to the admin group - * or has the specified permition/privilege + * OR has the specified permition/privilege * * @param $privilege_id (int) * @@ -35,7 +35,7 @@ class Course { { return ( Auth::in_admin_group() - || Auth::has_Permition([ $privilege_id ]) + || Auth::hasPermition([ $privilege_id ]) ); } @@ -99,24 +99,32 @@ class Course { * ------------------------------------------------------------------------- */ + /** course + * prepare and render the course view + * + * @param $id : course id + */ + public static function course($id) + { + $id = intval($id); // course id - public static function course($id) - { + // collect all data needed for course view + // --- -- -- - - - $cache = Cache_service::courses_struct(); $tree = $cache['tree']; $breadcrumbs = $cache['breadcrumbs']; $lessons = Course_model::lessons_of_course(intval($id)); - $id = intval($id); - - // print_r($breadcrumbs); die(); // find parent_ids of current category (to open the menu tree) + // --- $course_path = []; foreach($breadcrumbs[$id]['parents'] as $key => $parent) { $course_path[] = intval($parent['id']); } - $course_path[] = intval($id); + $course_path[] = $id; + // then Render + // --- -- -- - - - Render::view('templates/course', [ 'id' => $id, 'title' => $breadcrumbs[ $id ]['rec']['label'], @@ -125,19 +133,73 @@ class Course { 'lessons' => $lessons, 'course_path' => $course_path ]); - } + } + /** LESSONS + * ------------------------------------------------------------------------ + */ + /** lesson + * + * check if user is authorized to view the content; + * if so, prepare and render the lesson view + * + * @param $id : lesson id + */ + public static function lesson($id) + { + $id = intval($id); // lesson id - /** LESSONS - * ------------------------------------------------------------------------ - */ + $lesson = Course_model::lesson($id); // get lesson + $course_id = $lesson['course_id']; // get course id + $pri_id = $lesson['privilege_id']; // privilege needed + if (self::is_admin_or_permited($pri_id)) { + // collect all data needed for course view + // --- -- -- - - - + $cache = Cache_service::courses_struct(); + $tree = $cache['tree']; + $breadcrumbs = $cache['breadcrumbs']; + + // find parent_ids of current category (to open the menu tree) + // --- + $course_path = []; + foreach($breadcrumbs[$course_id]['parents'] as $key => $parent) { + $course_path[] = intval($parent['id']); + } + $course_path[] = intval($course_id); + + // then Render + // --- -- -- - - - + Render::view('templates/lesson', [ + // main content + 'id' => $id, + 'course_id' => $course_id, + 'title' => $lesson['title'], + 'lesson' => $lesson, + // needed for side panel and breadcrunbs + 'categories' => $tree, + 'breadcrumbs' => $breadcrumbs, + 'course_path' => $course_path + ]); + + } else { // user is not authorized + Render::view('error/general', [ + 'title' => 'Δεν έχετε πρόσβαση', + 'message' => 'Θα πρέπει να αγοράσετε το πακέτο πρόσβασης ' + . $pri_id + .' για να δείτε το περιεχόμενο! + <br><br> + Αγόρασε τώρα το <button class="btn">πακέτο πρόσβασης '. $pri_id .'</button>' + ]); + } + + } diff --git a/public/app/extends/.gitkeep b/public/app/extends/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/extends/.gitkeep diff --git a/public/app/extends/Cache_service.php b/public/app/extends/Cache_service.php index e44cc8e..9aac1d0 100644 --- a/public/app/extends/Cache_service.php +++ b/public/app/extends/Cache_service.php @@ -10,15 +10,19 @@ use app\models\admin\Privilege_model; * class that gathers common source-expensive queries * and helps for performance optimization * + * when forcing cache creation the following option is used: + * $options = PROXY_IGNORE_CACHE + * */ class Cache_service { public static function courses_struct( $options = 0 ) { - return proxy( // cache-get categories + return proxy( // cache-get courses [\app\models\cms\Course_model::class, 'courses_struct'], - [], CACHE_ROOT_TTL, $options + [], CACHE_ROOT_TTL, + $options ); } @@ -26,7 +30,8 @@ class Cache_service { return proxy( [\app\models\cms\Course_model::class, 'files'], - [], CACHE_ROOT_TTL, $options + [], CACHE_ROOT_TTL, + $options ); } @@ -35,11 +40,10 @@ class Cache_service { return proxy( [\app\models\admin\Privilege_model::class, 'privileges'], - [], CACHE_ROOT_TTL, $options + [], CACHE_ROOT_TTL, + $options ); } - - }
\ No newline at end of file diff --git a/public/app/models/.gitkeep b/public/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/models/.gitkeep diff --git a/public/app/models/cms/Course_model.php b/public/app/models/cms/Course_model.php index d8a8a0e..6378226 100644 --- a/public/app/models/cms/Course_model.php +++ b/public/app/models/cms/Course_model.php @@ -244,9 +244,8 @@ class Course_model { /** lessons of course * - * @param $course_id + * @param $id (int) : course_id */ - public static function lessons_of_course($id) { // TODO: order results in some way @@ -254,11 +253,28 @@ class Course_model { return Registry::use('database')->runQuery( "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id - WHERE lesson.status = 1 AND lesson.course_id = :id", + WHERE lesson.status = 1 AND lesson.course_id = :id + ORDER BY lesson_privilege.privilege_id ASC", [':id' => $id] ); } + /** lesson + * + * @param $id (int) : lesson id + */ + public static function lesson($id) + { + // TODO: order results in some way + + return Registry::use('database')->query( + "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson + LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id + WHERE lesson.status = 1 AND lesson.id = :id", + [':id' => $id] + )->getFirst(); + } + /** files diff --git a/public/app/routes/.gitkeep b/public/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/routes/.gitkeep diff --git a/public/app/routes/backend.php b/public/app/routes/backend.php index 475f52b..ed02295 100644 --- a/public/app/routes/backend.php +++ b/public/app/routes/backend.php @@ -5,17 +5,25 @@ use app\controllers\admin\Course_admin; use app\models\admin\Privilege_model; use app\extends\Cache_service; + +/** admin pages + * ----------------------------------------------------------------------------- + * NOTE: + * All adminitration routes MUST INCLUDE an Auth::allowRoles() check + */ + // admin panel -// --- -Route::add('/admin', function () { +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/admin', function () { // admin panel Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Classroom', 'action' => 'panel', ]); }); -Route::add('/admin/panel', function () { - Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles +Route::add('/admin/panel', function () { // admin panel #2 + Auth::allowRoles([1, 2, 3]); Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Classroom', 'action' => 'panel', @@ -24,8 +32,9 @@ Route::add('/admin/panel', function () { // admin lessons -// --- -Route::add('/admin/lessons', function () { +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/admin/lessons', function () { // request admin-lessons page Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Μαθημάτων', @@ -34,12 +43,11 @@ Route::add('/admin/lessons', function () { }); -// admin categories (=courses) ///////////////////////////////////////////////// -// ----------------------------------------------------------------------------- +// admin categories (=courses) +//////////////////////////////////////////////////////////////////////////////// -// manage categories page -// --- -Route::add('/admin/categories', function () { + +Route::add('/admin/categories', function () { // manage categories page Auth::allowRoles([1, 2, 3]); Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Κεφαλαίων', @@ -48,37 +56,29 @@ Route::add('/admin/categories', function () { }); -// ajax: get all categories (courses; with breadcrumbs) -// --- -Route::add('/admin/api/categories', function () { + +Route::add('/admin/api/categories', function () { // ajax: get all courses; with breadcrumbs Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::breadcrumbs(); }); - -// ajax: add new category (course) -// --- -Route::add('/admin/api/categories/add', function () { - Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles +Route::add('/admin/api/categories/add', function () { // ajax: add new category (course) + Auth::allowRoles([1, 2, 3]); Course_admin::add_course(); }, 'post'); -// ajax: edit category (course) -// --- -Route::add('/admin/api/categories/update', function () { - Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles - Course_admin::update_course(); - }, - 'post' -); +Route::add('/admin/api/categories/update', function () { // ajax: edit category (course) + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::update_course(); +}, +'post'); -// admin privileges //////////////////////////////////////////////////////////// -// ----------------------------------------------------------------------------- +// admin privileges +//////////////////////////////////////////////////////////////////////////////// -// manage privileges page -// --- -Route::add('/admin/privileges', function () { + +Route::add('/admin/privileges', function () { // manage privileges page Auth::allowRoles([1, 2, 3]); Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Δικαιωμάτων Πρόσβασης', @@ -88,7 +88,6 @@ Route::add('/admin/privileges', function () { // ajax: get all privileges (courses; with breadcrumbs) // use proxy (cache results); send as json -// --- Route::add('/admin/api/privileges', function () { Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Render::json( Cache_service::privileges_hierarchy() ); @@ -100,13 +99,12 @@ Route::add('/admin/api/privileges', function () { -// admin lesson //////////////////////////////////////////////////////////////// -// ----------------------------------------------------------------------------- +// admin lesson +//////////////////////////////////////////////////////////////////////////////// -// new lesson // --- -Route::add('/admin/edit_lesson', function () { +Route::add('/admin/edit_lesson', function () { // new lesson form Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Render::view('admin/skeleton', [ 'title' => 'Νέο Μάθημα', @@ -114,10 +112,8 @@ Route::add('/admin/edit_lesson', function () { ]); }); -// edit lesson (give lesson-id) -// --- -Route::add('/admin/edit_lesson/([0-9]*)', function ($id) { - Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles +Route::add('/admin/edit_lesson/([0-9]*)', function ($id) { // edit lesson form + Auth::allowRoles([1, 2, 3]); Render::view('admin/skeleton', [ 'title' => 'Επεξεργασία Μαθήματος', 'action' => 'edit_lesson', @@ -125,39 +121,35 @@ Route::add('/admin/edit_lesson/([0-9]*)', function ($id) { ]); }); -// ajax: get lesson -// --- -Route::add('/admin/api/lesson/([0-9]*)', function ($id) { + +Route::add('/admin/api/lesson/([0-9]*)', function ($id) { // ajax: get lesson Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::get_lesson($id); }); -// ajax: add lesson -// --- -Route::add('/admin/api/lesson/add', function () { + +Route::add('/admin/api/lesson/add', function () { // ajax: add lesson Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::add_lesson(); }, 'post'); -// ajax: update lesson -// --- -Route::add('/admin/api/lesson/update', function () { + +Route::add('/admin/api/lesson/update', function () { // ajax: update lesson Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::update_lesson(); }, 'post'); -// ajax: get all lessons -// --- -Route::add('/admin/api/lessons', function () { + +Route::add('/admin/api/lessons', function () { // ajax: get all lessons Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::all_lessons(); }); -// admin files ///////////////////////////////////////////////////////////////// +// admin files //////////////////////////////////////////////////////////////////////////////// -Route::add('/admin/files', function () { +Route::add('/admin/files', function () { // admin-files panel Auth::allowRoles([1, 2, 3]); Render::view('admin/skeleton', [ 'title' => 'Διαχείριση Μέσων (media)', @@ -165,10 +157,9 @@ Route::add('/admin/files', function () { ]); }); -// ajax: get lesson -// --- -Route::add('/admin/api/files', function () { - Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + +Route::add('/admin/api/files', function () { // ajax: get lesson + Auth::allowRoles([1, 2, 3]); Render::json(Course_admin::files()); }); @@ -179,7 +170,3 @@ Route::add('/admin/api/file_upload', function () { Render::json(Course_admin::upload_file()); }, 'post'); - - - - diff --git a/public/app/routes/frontend.php b/public/app/routes/frontend.php index f9e74db..33fe401 100644 --- a/public/app/routes/frontend.php +++ b/public/app/routes/frontend.php @@ -6,22 +6,45 @@ use app\controllers\cms\Course; use app\models\cms\Course_model; use app\extends\Cache_service; + // Home/Welcome -// --- -Route::add('/', function() { // echo 'Welcome!'; }); - Render::view('welcome', [ // cache categories (while retrieving) +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/', function() { + Render::view('welcome', [ 'categories' => Cache_service::courses_struct()['tree'] ]); - // header('Location: /some/default/url', true, 302); + // need redirect?... header('Location: /some/default/url', true, 302); }); -// Error Pages -// --- -Route::notFound( function() { +// Error pages +//////////////////////////////////////////////////////////////////////////////// + +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;)']); -}); // 404 +}); + + + +// Common content +//////////////////////////////////////////////////////////////////////////////// + + +Route::add('/course/([0-9]*)', // request course by course-id + function($id) { Course::course($id); } +); + +Route::add('/lesson/([0-9]*)', // request lesson by lesson-id + function($id) { Course::lesson($id); } +); + +Route::add('/serve/file/([0-9a-zA-Z-_\.\/]*)', // serve file by path + function ($path) { Course::serve_file($path); } // (also ?type= is sent) +); + + @@ -42,36 +65,8 @@ Route::notFound( function() { -// Resolve urls -// --- -- -- - - - -Route::add('/course/([0-9]*)', - function($id) { Course::course($id); } -); - -Route::add('/lesson/([0-9a-f]*)/([0-9a-zA-Z-_]*)', - function($ticket, $lesson) { Lesson::show([$lesson, $ticket]); } -); - -Route::add('/media/([0-9a-f]*)/([0-9a-zA-Z-_]*)/([0-9]*)/', - function($ticket, $type, $id) { Media::serve([$type, $id, $ticket]); } -); - - -// 4-th level paths belong to products -// --- -Route::add('/about/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', - function($a, $b, $c) { Page::show([$a, $b, $c]); } -); - - -// serve file -// --- -Route::add('/serve/file/([0-9a-zA-Z-_\.\/]*)', function ($path) { - Course::serve_file($path); -}); - -/** URL-format Proposal: +/** URL-format Proposals and common Route regex solutions * ----------------------------------------------------------------------------- * * Page (almost-static content): @@ -88,80 +83,82 @@ Route::add('/serve/file/([0-9a-zA-Z-_\.\/]*)', function ($path) { * * Category * /{category}/[ {subcategory}[ /{group}]] -Route::add('/([0-9a-zA-Z-_]*)', function($a) { Category::url([$a]); }; -Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Category::url([$a, $b]); }); -Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Category::url([$a, $b, $c]); }); - * ----------------------------------------------------------------------------- - */ - +# Route::add('/([0-9a-zA-Z-_]*)', function($a) { Category::url([$a]); }; +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Category::url([$a, $b]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Category::url([$a, $b, $c]); }); + * + * othet routes used in some user-cases -/* EXAMPLES (use it for brainsrtorming) +# Route::add('/lesson/([0-9a-f]*)/([0-9a-zA-Z-_]*)', +# function($ticket, $lesson) { Lesson::show([$lesson, $ticket]); } +# ); +# +# Route::add('/media/([0-9a-f]*)/([0-9a-zA-Z-_]*)/([0-9]*)/', +# function($ticket, $type, $id) { Media::serve([$type, $id, $ticket]); } +# ); + * + * 4-th level paths belong to products +# Route::add('/about/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', +# function($a, $b, $c) { Page::show([$a, $b, $c]); } +# ); + * + * + * OTHER EXAMPLES (use it for brainsrtorming) * ----------------------------------------------------------------------------- * - // Typical Use - // --- - Route::add('/art', function() { Art::blah(); }); - Route::add('/art/db', function() { Art::fromDatabase(); }); - Route::add('/art/([0-9]*)', function($id) { Art::getInfo($id); }); - - - // Get-Post route example - // --- - Route::add('/contact-form', function() { - echo '<form method="post"><input type="text" name="test" /><input type="submit" value="send" /></form>'; - }, 'get'); + * +# // Typical Use +# // --- +# Route::add('/art', function() { Art::blah(); }); +# Route::add('/art/db', function() { Art::fromDatabase(); }); +# Route::add('/art/([0-9]*)', function($id) { Art::getInfo($id); }); + * + * Get-Post route example +# Route::add('/contact-form', function() { +# echo '<form method="post"><input type="text" name="test" /><input type="submit" value="send" /></form>'; +# }, 'get'); Route::add('/contact-form', function() { echo 'Hey! The form has been sent:<br/>'; print_r($_POST); }, 'post'); - - - // Accept number as parameter - // --- - Route::add('/foo/([0-9]*)/bar', function($var1) { - // echo $var1.' is a number!'; + * + * Accept number as parameter +# Route::add('/foo/([0-9]*)/bar', function($var1) { +# // echo $var1.' is a number!'; echo "{$var1} is a number!"; - }); - - - // About pages - // --- - Route::add('/about/([0-9a-zA-Z-_]*)', function($page) { - InfoPage::render('about/'.page); - }); - - - // handle a request like: /foo/123/bar/3254-lefki-zaxari-marata-1kg - // where first-numeric-part of last-uri-section (3254) is the product number - // --- - Route::add('/foo/([0-9]*)/bar/([0-9]*)-([0-9a-zA-Z-_]*)', function($num, $id, $name) { - echo $num .' is some nomber, id = '. $id .' and label = '. $name; - }); - - - // handle a request like: /zaxares-glykantika/lefki-zaxari-year-2022-45678 - // where last-numeric-part of last-uri-section (45678) is the product number - // --- - Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', - function($category, $subcategory, $group, $label, $id) { - Shop::product([$$category, $subcategory, $group, $label], $id); - }); - - - // last chance to resolve (some friendly url) - // --- - Route::add('/([0-9a-zA-Z-_]*)', function($a) { Resolve::uri([$a]); }); - Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Resolve::uri([$a, $b]); }); - Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Resolve::uri([$a, $b, $c]); }); - - - // Product page - // handle a request like: /pantopoleio/zaxares/lefki-zaxari/lefki-zaxari-year-2022-45678 - // where last-numeric-part of last-uri-section (45678) is the product number - // --- - Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', - function($category, $subcategory, $group, $label, $id) { - Shop::product([$$category, $subcategory, $group, $label], $id); - }); -* ------------------------------------------------------------------------------ -*/ +# }); + * + * About pages +# Route::add('/about/([0-9a-zA-Z-_]*)', function($page) { +# InfoPage::render('about/'.page); +# }); + * + * handle a request like: /foo/123/bar/3254-lefki-zaxari-marata-1kg + * where first-numeric-part of last-uri-section (3254) is the product number +# Route::add('/foo/([0-9]*)/bar/([0-9]*)-([0-9a-zA-Z-_]*)', function($num, $id, $name) { +# echo $num .' is some nomber, id = '. $id .' and label = '. $name; +# }); + * + * handle a request like: /zaxares-glykantika/lefki-zaxari-year-2022-45678 + * where last-numeric-part of last-uri-section (45678) is the product number +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', +# function($category, $subcategory, $group, $label, $id) { +# Shop::product([$$category, $subcategory, $group, $label], $id); +# }); + * + * last chance to resolve (some friendly url) +# Route::add('/([0-9a-zA-Z-_]*)', function($a) { Resolve::uri([$a]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Resolve::uri([$a, $b]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Resolve::uri([$a, $b, $c]); }); + * + * + * Product page + * handle a request like: /pantopoleio/zaxares/lefki-zaxari/lefki-zaxari-year-2022-45678 + * where last-numeric-part of last-uri-section (45678) is the product number +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', +# function($category, $subcategory, $group, $label, $id) { +# Shop::product([$$category, $subcategory, $group, $label], $id); +# }); + * + * ------------------------------------------------------------------------------ + */ diff --git a/public/app/views/.gitkeep b/public/app/views/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/public/app/views/.gitkeep diff --git a/public/app/views/components/breadcrumbs.php b/public/app/views/components/breadcrumbs.php index 90b4af9..59c0fca 100644 --- a/public/app/views/components/breadcrumbs.php +++ b/public/app/views/components/breadcrumbs.php @@ -9,8 +9,8 @@ * @param $parents : array of parent nodes * ----------------------------------------------------------------------------- */ -?> +?> <div class="breadcrumb"> <!-- home --> <a href="/">Classroom</a> diff --git a/public/app/views/components/lessons_list.php b/public/app/views/components/lessons_list.php index 1c59164..46c1f7e 100644 --- a/public/app/views/components/lessons_list.php +++ b/public/app/views/components/lessons_list.php @@ -33,6 +33,10 @@ <a href="/lesson/<?=$post['id']?>"><?=$post['title']?></a> </h3> + <?php if (in_array('level', $fieldset)) : ?> + <p class="getegory">(επίπεδο πρόσβασης <?=$post['privilege_id']?>)</p> + <?php endif; ?> + <?php if (in_array('category', $fieldset)) : ?> <p class="category"><?=$post['course_id']?></p> <?php endif; ?> diff --git a/public/app/views/components/subcategories.php b/public/app/views/components/subcategories.php index 58f53fa..5c05a94 100644 --- a/public/app/views/components/subcategories.php +++ b/public/app/views/components/subcategories.php @@ -2,7 +2,8 @@ <?php if ($breadcrumbs[ $id ]['childs'] != []) : ?> - <h5>Υποκατηγορίες</h5> + <h5>Υποκεφάλαια</h5> + <div class="category-childs"> <?php foreach($breadcrumbs[ $id ]['childs'] as $key => $child) : ?> diff --git a/public/app/views/components/top_bar.php b/public/app/views/components/top_bar.php index 0e6e437..eaffe76 100644 --- a/public/app/views/components/top_bar.php +++ b/public/app/views/components/top_bar.php @@ -1,8 +1,31 @@ +<?php +/** top bar + * ----------------------------------------------------------------------------- + * + * rendrers breadcrumbs and user menu + * + * imported variables + * --- + * @param $id : category_id of last level + * @param $label : category title of last level + * @param $parents : array of parent nodes + * ----------------------------------------------------------------------------- + */ + +// initialize variables needed if not passed +// (needed while requiring breadcrumbs) +if (!isset($id)) { + $id = 0; + $label = ""; + $parents = []; +} + +?> <div class="top-bar"> <?php // breadcrumbs //////////////////////////////////////////////////////////////////////// - Render::template("components/breadcrumbs", [ + Render::view("components/breadcrumbs", [ 'id' => $id, 'label' => $label, 'parents' => $parents diff --git a/public/app/views/error/404.php b/public/app/views/error/404.php index 89c35cc..4bbf083 100644 --- a/public/app/views/error/404.php +++ b/public/app/views/error/404.php @@ -26,6 +26,7 @@ text-align: center; justify-center: center; opacity: .33; } + .btn { font-size: 18px; padding: 4px 12px; } </style> </head> <body> diff --git a/public/app/views/error/general.php b/public/app/views/error/general.php index 74566a4..0a27e56 100644 --- a/public/app/views/error/general.php +++ b/public/app/views/error/general.php @@ -1,10 +1,19 @@ <?php /** general message template + * ----------------------------------------------------------------------------- + * renders an error with custom title and message + * + * passed values: * - * passed: - * @var $title (string): page title - * @var $message (string): message + * optional @var $title (string): title + * optional @var $message (string): message + * + * NOTE: + * if title and/or message are not passed, then defaults are used + * + * ----------------------------------------------------------------------------- */ + ?><!DOCTYPE html> <html lang="en"> <head> @@ -39,6 +48,7 @@ opacity: .33; font-size: .87em } + .btn { font-size: 18px; padding: 4px 12px; } </style> </head> <body> diff --git a/public/app/views/templates/course.php b/public/app/views/templates/course.php index 9d42297..39e177f 100644 --- a/public/app/views/templates/course.php +++ b/public/app/views/templates/course.php @@ -63,7 +63,7 @@ //////////////////////////////////////////////////// Render::view("components/lessons_list", [ 'lessons' => $lessons, - 'fieldset' => ['intro'] // ['intro', 'date'] + 'fieldset' => ['intro', 'level'] // ['intro', 'date'] ]); ?> <?php endif; ?> diff --git a/public/app/views/templates/lesson.php b/public/app/views/templates/lesson.php new file mode 100644 index 0000000..3baafd0 --- /dev/null +++ b/public/app/views/templates/lesson.php @@ -0,0 +1,72 @@ +<!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> + + + <script src="/assets/js/classroom.js"></script> + <script src="/assets/js/lesson-features.js"></script> +</body> +</html> diff --git a/public/assets/css/class.css b/public/assets/css/class.css index a65bfa2..f132241 100644 --- a/public/assets/css/class.css +++ b/public/assets/css/class.css @@ -156,7 +156,7 @@ -.classroom .post img { max-width: 100%; } +.classroom .lesson-view img { max-width: 100%; } @@ -199,7 +199,7 @@ } /* --- post: medias -- */ - +/* DEPRICATED: not needed .classroom .content--wrapper .medias { padding: 2em 0 1em; border-top: 1px solid var(--class-grey-background); @@ -212,6 +212,7 @@ font-size: 12px; color: #999; } +*/ /* --- post: tags --- */ @@ -308,18 +309,20 @@ -.classroom .post h2 { padding-bottom: 0; } +.classroom .lesson-view h2 { padding-bottom: 0; font-size: 24px; } + +.classroom .lesson-view h2 span { float:right; margin-right: -3em;} -.classroom .post h2 span { float:right; margin-right: -3em;} +.classroom .lesson-view pre { padding: 1em; background: #f5f5f6;} -.classroom .post .intro { +.classroom .lesson-view .intro { font-style: italic; font-size: 18px; color: var(--class-blue-dark); padding-bottom: 1em; } -.classroom .post .post--date { +.classroom .lesson-view .post--date { padding: 0; color: var(--class-blue); } diff --git a/public/assets/css/overides.css b/public/assets/css/overides.css index e3d5e1b..c0f6bd9 100644 --- a/public/assets/css/overides.css +++ b/public/assets/css/overides.css @@ -128,4 +128,10 @@ ul.select2-results__options li { font-size: 14px; padding: 4px 8px; } .admin-container .edit-post .post-media ul li:last-child { border-bottom: none ;} .admin-container .edit-post .post-media ul li:hover { background: #eee; } -.edit-post .post-media li .btn-xs { font-size: 14px; width: 24px; height: 24px; padding:0; }
\ No newline at end of file +.edit-post .post-media li .btn-xs { font-size: 14px; width: 24px; height: 24px; padding:0; } + +.classroom .edit-post textarea[name=body] { + min-height:320px; + font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace; + color: #333; + }
\ No newline at end of file diff --git a/public/assets/js/admin/edit_lesson.js b/public/assets/js/admin/edit_lesson.js index 89e464f..fbcfabc 100644 --- a/public/assets/js/admin/edit_lesson.js +++ b/public/assets/js/admin/edit_lesson.js @@ -201,11 +201,14 @@ $(document).ready(function() { $('input[name=id]').val(lesson.id); // id $('input[name=title]').val(lesson.title); // title $('textarea[name=intro]').val(lesson.intro); // intro - $('textarea[name=body]').val(lesson.body); // body - $('input[name=status]').prop( // status - 'checked', - ((lesson.status==1)? true : false)) - .trigger('change'); + $('textarea[name=body]').val(lesson.body); // body + $('select[name=status]').val( + (lesson.status == 0) ? '0' : "one" + ).trigger('change'); + // $('input[name=status]').prop( // status + // 'checked', + // ((lesson.status==1)? true : false)) + // .trigger('change'); // $('#post-info').html('Δημιουργία: '+post.creation_date+'<br>Τελευταία Ενημέρωση: '+ post.update_date); @@ -408,8 +411,8 @@ $(document).ready(function() { // send POST (ajax) request $.post(request, data) .done(function( data ) { - console.log(data); - //window.location.href = '/admin/lessons'; // seems ok; bach to articles + // console.log(data); + window.location.href = '/admin/lessons'; // seems ok; bach to articles }); }); diff --git a/public/assets/js/post-features.js b/public/assets/js/lesson-features.js index ca2928c..369c8f7 100644 --- a/public/assets/js/post-features.js +++ b/public/assets/js/lesson-features.js @@ -1,6 +1,5 @@ -const valid_modals = [ // supported sort-code keys - 'product', - 'store' +const valid_codeblocks = [ // supported sort-code keys + 'youtube' ]; @@ -16,6 +15,20 @@ const symbol_escapes = [ ]; +var youtube_template = ( id => { + return '<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/'+ id +'?rel=0&controls=0" title="YouTube video player" frameborder="0" allow="clipboard-write; encrypted-media; picture-in-picture; web-share" allowfullscreen></iframe>' +}); + +/* + + +<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/6EA-MIYY1bg?controls=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> + + + +*/ + + /** inject_codeblocks * --- -- -- - - - * @@ -43,17 +56,20 @@ function inject_codeblocks(code) { // parse (every) match // NOTE: // match array has 3 items; example: - // match[0] : `{{store=247; Pasalimani Market}}` - // match[1] : `store=247; Pasalimani Market` + // match[0] : `{{youtube=6EA-MIYY1bg}}` + // match[1] : `youtube=6EA-MIYY1bg` // match[3] : the (source) code string - let blockparts = unescaped_str( match[1] ).split(';'); - let main_unit = blockparts[0].replaceAll(' ','').split('='); - let target = main_unit[0].toLowerCase(); - let id = main_unit[1]; - let label = escaped_str(blockparts[1]); - if (valid_modals.includes(target)) { - let codeblock = `<a href="#" data-toggle="modal" data-target="#view-${target}" data-id="${id}" class="modal-toggler js-get_${target}">${label}</a>`; + let blockparts = unescaped_str( match[1] ).trim().split('='); + let target = blockparts[0].toLowerCase(); + let id = blockparts[1]; + // let label = escaped_str(blockparts[1]); + if (valid_codeblocks.includes(target)) { + + if (target == 'youtube') { + var codeblock = youtube_template(id); + } output = output.replaceAll(match[0], codeblock); + } }); @@ -80,15 +96,15 @@ $(document).ready(function() { /** translate short-codes to code-blocks * ------------------------------------------------------------------------- */ - var content = $('.content .article-body').html(); // get code with shorts - $('.content .article-body').html( inject_codeblocks(content) ); // put code with blocks + var content = $('.main-content .article-body').html(); // get code with shorts + $('.main-content .article-body').html( inject_codeblocks(content) ); // put code with blocks /** modal listeners * ------------------------------------------------------------------------- */ - +/* DEPRICATED: not needed // open store modal listener // --- -- -- - - - $(document).on('click', '.js-get_store', function (e) { @@ -144,5 +160,5 @@ $(document).ready(function() { }); }); - -});
\ No newline at end of file +*/ +}); |
