summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile3
-rw-r--r--docker/bin/docker-entrypoint.sh4
-rw-r--r--public/app/controllers/admin/Course_admin.php93
-rw-r--r--public/app/controllers/admin/Users_admin.php42
-rw-r--r--public/app/models/admin/Privilege_model.php42
-rw-r--r--public/app/models/cms/Course_model.php3
-rw-r--r--public/app/routes/backend.php81
-rw-r--r--public/app/views/admin/admin-menu.php4
-rw-r--r--public/app/views/admin/categories.php16
-rw-r--r--public/app/views/admin/new_lesson.php144
-rw-r--r--public/app/views/admin/privileges.php93
-rw-r--r--public/assets/css/overides.css45
-rw-r--r--public/assets/js/admin/categories.js4
-rw-r--r--public/assets/js/admin/privileges.js291
-rwxr-xr-xpublic/cache/.gitkeep0
15 files changed, 828 insertions, 37 deletions
diff --git a/Dockerfile b/Dockerfile
index ef8e94e..6e76571 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -78,8 +78,7 @@ RUN locale-gen
# Manage permitions in specific directories
# ------------------------------------------------------------------------------
# (make local storage directories writable)
-# RUN chown -R www-data:www-data /var/www
-RUN chmod -R 757 /var/www/public/cache
+RUN chown -R www-data:www-data /var/www
RUN chmod -R 757 /var/www/storage
diff --git a/docker/bin/docker-entrypoint.sh b/docker/bin/docker-entrypoint.sh
index a01f3a3..f421d80 100644
--- a/docker/bin/docker-entrypoint.sh
+++ b/docker/bin/docker-entrypoint.sh
@@ -4,8 +4,6 @@
# ------------------------------------------------------------------------------
# grand to 'cache' directory writable permissions
# set file-cache directory to apache's user ownership
-chmod -R 755 /var/www/public/cache
-chown -R www-data:www-data /var/www/public/cache
chmod -R 755 /var/www/storage
chown -R www-data:www-data /var/www/storage
@@ -24,4 +22,4 @@ cp /var/www/docker/config/composer-naked.json /var/www/composer.json
# start apache
# ------------------------------------------------------------------------------
# End with running the original command
-exec /usr/sbin/apache2ctl -D FOREGROUND \ No newline at end of file
+exec /usr/sbin/apache2ctl -D FOREGROUND
diff --git a/public/app/controllers/admin/Course_admin.php b/public/app/controllers/admin/Course_admin.php
new file mode 100644
index 0000000..0e34e00
--- /dev/null
+++ b/public/app/controllers/admin/Course_admin.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace app\controllers\admin;
+
+use Registry;
+use Render;
+use app\models\cms\Course_model;
+
+class Course_admin {
+
+
+ /** breadcrumbs
+ * ---
+ * responds to ajax GET: /admin/api/categories
+ */
+ public static function breadcrumbs()
+ {
+ $tree = proxy( // cache-get categories
+ [\app\models\cms\Course_model::class, 'category_tree'],
+ [], CACHE_ROOT_TTL
+ );
+ $breadcrumbs = proxy( // cache-get breadcrumbs
+ [\app\models\cms\Course_model::class, 'breadcrumbs'],
+ [$tree], CACHE_ROOT_TTL
+ );
+ Render::json($breadcrumbs); // send as json
+ }
+
+ /** 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
+ * --- -- -- - - -
+ * Shall run if anything changes to courses
+ *
+ * @param void
+ * @return (array): the two course caches
+ */
+ public static function update_courses_cache()
+ {
+ $tree = proxy( // cache-get categories
+ [\app\models\cms\Course_model::class, 'category_tree'],
+ [], CACHE_ROOT_TTL, PROXY_IGNORE_CACHE
+ );
+ $breadcrumbs = proxy( // cache-get breadcrumbs
+ [\app\models\cms\Course_model::class, 'breadcrumbs'],
+ [$tree], CACHE_ROOT_TTL, PROXY_IGNORE_CACHE
+ );
+
+ return [
+ 'tree' => $tree,
+ 'breadcrumbs' => $breadcrumbs
+ ];
+ }
+
+} \ No newline at end of file
diff --git a/public/app/controllers/admin/Users_admin.php b/public/app/controllers/admin/Users_admin.php
new file mode 100644
index 0000000..4e335c1
--- /dev/null
+++ b/public/app/controllers/admin/Users_admin.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace app\controllers\admin;
+
+use Registry;
+use Render;
+
+
+class Users_admin {
+
+ /** privileges
+ * ---
+ * get all privileges
+ *
+ * @param void
+ * @return privileges (array)
+ */
+ public static function privileges()
+ {
+ return Registry::use('database')->runQuery(
+ "SELECT * FROM privilege",[]
+ );
+ }
+
+ /** edit privileges
+ * ---
+ */
+ public static function edit_privileges()
+ {
+ // TODO: ...
+ }
+
+
+ /** update course
+ * ---
+ */
+ public static function update_course()
+ {
+ // TODO: ...
+ }
+
+} \ No newline at end of file
diff --git a/public/app/models/admin/Privilege_model.php b/public/app/models/admin/Privilege_model.php
new file mode 100644
index 0000000..c385484
--- /dev/null
+++ b/public/app/models/admin/Privilege_model.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace app\models\admin;
+
+use Registry;
+use Render;
+
+
+class Privilege_model {
+
+ /** privileges
+ * ---
+ * get all privileges
+ *
+ * @param void
+ * @return privileges (array)
+ */
+ public static function privileges()
+ {
+ return Registry::use('database')->runQuery(
+ "SELECT * FROM privilege",[]
+ );
+ }
+
+ /** edit privileges
+ * ---
+ */
+ public static function edit_privileges()
+ {
+ // TODO: ...
+ }
+
+
+ /** update course
+ * ---
+ */
+ public static function update_course()
+ {
+ // TODO: ...
+ }
+
+} \ No newline at end of file
diff --git a/public/app/models/cms/Course_model.php b/public/app/models/cms/Course_model.php
index 4fb49c0..4740a4f 100644
--- a/public/app/models/cms/Course_model.php
+++ b/public/app/models/cms/Course_model.php
@@ -14,7 +14,7 @@ class Course_model {
public static function get_categories()
{
return Registry::use('database')->runQuery(
- "SELECT * FROM course",
+ "SELECT * FROM course ORDER BY `order`",
[]
);
}
@@ -74,6 +74,7 @@ class Course_model {
'rec' => [
'id' => $rec['id'],
'label' => $rec['label'],
+ 'order' => $rec['order'],
'parent' => $rec['parent_id']
],
'childs' => self::to_tree($dataset, $child) // recursively
diff --git a/public/app/routes/backend.php b/public/app/routes/backend.php
index 700fa14..5356407 100644
--- a/public/app/routes/backend.php
+++ b/public/app/routes/backend.php
@@ -1,7 +1,8 @@
<?php
use app\controllers\Auth;
-use app\models\cms\Course_model;
+use app\controllers\admin\Course_admin;
+use app\models\admin\Privilege_model;
// admin lessons
// ---
@@ -15,6 +16,9 @@ Route::add('/admin/lessons', function () {
// admin cateogies
+// -----------------------------------------------------------------------------
+
+// manage categories page
// ---
Route::add('/admin/categories', function () {
Auth::allowRoles([1, 2, 3]);
@@ -25,17 +29,70 @@ Route::add('/admin/categories', function () {
});
+// ajax: get all categories (courses; with breadcrumbs)
+// ---
Route::add('/admin/api/categories', function () {
+ Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles
+ Course_admin::breadcrumbs();
+});
+
+
+// ajax: add new category (course)
+// ---
+Route::add('/admin/api/category/add', function () {
+ Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles
+ Course_admin::add_course();
+ },
+ 'post'
+);
+
+// ajax: edit category (course)
+// ---
+Route::add('/admin/api/category/update', function () {
+ Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles
+ Course_admin::update_course();
+ },
+ 'post'
+);
+
+
+// admin privileges
+// -----------------------------------------------------------------------------
+
+// manage privileges page
+// ---
+Route::add('/admin/privileges', function () {
Auth::allowRoles([1, 2, 3]);
- $tree = proxy(
- [\app\models\cms\Course_model::class, 'category_tree'],
+ Render::view('admin/skeleton', [
+ 'title' => 'Διαχείριση Δικαιωμάτων Πρόσβασης',
+ 'action' => 'privileges',
+ ]);
+});
+
+// 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( proxy(
+ [\app\models\admin\Privilege_model::class, 'privileges'],
[], CACHE_ROOT_TTL
- );
-
- $breadcrumbs = proxy(
- [\app\models\cms\Course_model::class, 'breadcrumbs'],
- [$tree], CACHE_ROOT_TTL
- );
- // $breadcrumbs = Course_model::breadcrumbs($tree);
- Render::json($breadcrumbs);
-}); \ No newline at end of file
+ ));
+});
+
+// add privilege
+
+// update privilege
+
+
+
+// new lesson
+// -----------------------------------------------------------------------------
+Route::add('/admin/new_lesson', function () {
+ Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles
+ Render::view('admin/skeleton', [
+ 'title' => 'Νέο Μάθημα',
+ 'action' => 'new_lesson'
+ ]);
+});
+
diff --git a/public/app/views/admin/admin-menu.php b/public/app/views/admin/admin-menu.php
index 813420d..d7e7b09 100644
--- a/public/app/views/admin/admin-menu.php
+++ b/public/app/views/admin/admin-menu.php
@@ -16,11 +16,11 @@
$admin_options = [
- 'new' => 'Νέο Μάθημα',
+ 'new_lesson' => 'Νέο Μάθημα',
'lessons' => 'Μαθήματα',
'categories' => 'Κατηγορίες',
'pages' => 'Σελίδες',
- 'privileges' => 'Δικαιώματα',
+ 'privileges' => 'Πρόσβαση',
'users' => 'Χρήστες'
];
diff --git a/public/app/views/admin/categories.php b/public/app/views/admin/categories.php
index e33d9b0..91acec1 100644
--- a/public/app/views/admin/categories.php
+++ b/public/app/views/admin/categories.php
@@ -1,9 +1,9 @@
<!-- title bar -->
<div class="title-bar">
- <div>Διαχείριση Κατηγοριών</div>
+ <div><h5>Διαχείριση Κατηγοριών</h5></div>
<div>
<!-- Button trigger modal -->
- <button type="button" class="btn btn-success pull-right"
+ <button type="button" class="btn pull-right"
data-bs-toggle="modal" data-bs-target="#manageCategory" data-id="0">
<i class="fas fa-plus"></i> &nbsp; Νέα Κατηγορία
</button>
@@ -16,7 +16,7 @@
<div id="categories-tree">
- <table id="dt-categories" class="table table-responsive dt-table">
+ <table id="dt-categories" class="table table-responsive dt-table" style="width:100%">
<thead>
<th class="dt-breadcrumb">Κατηγορία</th>
<th class="dt-actions"></th>
@@ -48,25 +48,19 @@
<!-- modal-body -->
<div class="modal-body">
- <!-- loader
- <div class="modal-loader">
- <img src="/img/ajax-loader.gif">
- </div>
- -->
-
<!-- form fields -->
<div class="row form-group">
<label class="control-label col-sm-12" for="label">Όνομα κατηγορίας</label>
<div class="col-sm-12">
- <input class="form-control" type="text" name="label" value="" required="">
+ <input class="form-control form-control-sm" type="text" name="label" value="" required="">
</div>
</div>
<div class="row form-group">
<label class="control-label col-sm-12" for="parent_id">Γονική Κατηγορία</label>
<div class="col-sm-12">
- <select class="form-control" id="parent_id" name="parent_id" required /></select>
+ <select class="form-control form-control-sm form-select form-select-sm" id="parent_id" name="parent_id" required></select>
</div>
</div>
diff --git a/public/app/views/admin/new_lesson.php b/public/app/views/admin/new_lesson.php
new file mode 100644
index 0000000..c48fc82
--- /dev/null
+++ b/public/app/views/admin/new_lesson.php
@@ -0,0 +1,144 @@
+<?php
+// if no (lesson-)id is specified, then id=0 (new lesson)
+if (!isset($id)) $id=0;
+?>
+
+<!-- title bar -->
+<div class="title-bar">
+ <div><h5>Επεξεργασία Μαθήματος</h5></div>
+ <div>
+ <button type="button" class="btn pull-right"
+ data-toggle="modal" data-target="#editorModal" data-action="preview">
+ <i class="fas fa-search"></i> &nbsp; Προεπισκόπηση
+ </button>
+ </div>
+</div>
+
+<!-- manage -->
+<div class="manage edit-post">
+ <form>
+ <div class="row">
+
+
+ <div class="col col-8">
+
+ <!-- id (hidden) -->
+ <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' -->
+
+ <!--
+ <div class="row form-group">
+ <input type="date" name="date" value="" readonly="">
+ </div>
+ -->
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="title">Τίτλος</label>
+ <div class="col-sm-12">
+ <input class="form-control form-control-sm" type="text" name="title" value="" required="">
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="category_id">Κατηγορία</label>
+ <div class="col-sm-12">
+ <select class="form-control form-control-sm" id="category_id" name="category_id" required></select>
+ </div>
+ </div>
+
+ <!-- Post body -->
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="body">Κείμενο</label>
+ <div class="col-sm-12">
+ <textarea class="form-control form-control-sm" type="text" name="body" value="" required=""></textarea>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="col">
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="status">Κατάσταση</label>
+ <div class="col-sm-12">
+ <select class="form-control form-control-sm form-select form-select-sm" name="status" onchange="this.dataset.chosen = this.value;">
+ <option value="0">Αδημοσίευτο</option>
+ <option value="one">ΔΗΜΟΣΙΕΥΜΕΝΟ</option>
+ </select>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="privilege_id">Επίπεδο Πρόσβασης</label>
+ <div class="col-sm-12">
+ <select class="form-control form-control-sm form-select form-select-sm" name="privilege_id">
+ <option>one</option>
+ <option>two</option>
+ <option>three</option>
+ </select>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="intro">Σύντομη Περιγραφή</label>
+ <div class="col-sm-12">
+ <textarea class="form-control form-control-sm" type="text" name="intro" value=""></textarea>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="media">Αρχεία</label>
+ <div class="col-sm-12 post-media">
+
+ <!-- Button trigger modal -->
+ <button type="button" class="btn btn-sm btn-success pull-right over-bar"
+ data-toggle="modal" data-target="#editorModal" data-action="upload_file">
+ <i class="fas fa-plus"></i> &nbsp; Προσθήκη
+ </button>
+
+ <ul id="files_list">
+ </ul>
+
+ </div>
+ </div>
+
+ <?php if ($id != 0) : ?>
+ <div class="row form-group">
+ <label class="control-label col-sm-12">Πληροφορίες</label>
+ <div class="col-sm-12" id="post-info">
+ </div>
+ </div>
+ <?php endif; ?>
+
+ </div>
+
+ </div>
+
+ <div class="row">
+
+ <div class="col">
+ <hr/>
+ <!-- close | submit buttons -->
+
+ <div class="form-actions row justify-content-md-center">
+
+ <div class="col-3">
+ <button type="button" id="go-back" class="btn btn-light col-sm-12">
+ Επιστροφή
+ </button>
+ </div>
+
+ <div class="col-4">
+ <button class="btn btn-primary col-sm-12" type="submit">
+ Καταχώριση
+ </button>
+ </div>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+</div><!-- /manage -->
+
diff --git a/public/app/views/admin/privileges.php b/public/app/views/admin/privileges.php
new file mode 100644
index 0000000..587c363
--- /dev/null
+++ b/public/app/views/admin/privileges.php
@@ -0,0 +1,93 @@
+ <!-- title bar -->
+ <div class="title-bar">
+ <div><h5>Διαχείριση Επιπέδων Πρόσβασης</h5></div>
+ <div>
+ <!-- Button trigger modal -->
+ <button type="button" class="btn pull-right"
+ data-bs-toggle="modal" data-bs-target="#managePrivileges" data-id="0">
+ <i class="fas fa-plus"></i> &nbsp; Νέο Επίπεδο
+ </button>
+ </div>
+</div>
+
+<div class="manage">
+ <div class="row">
+ <div class="col-md-12">
+
+ <div id="categories-tree">
+
+ <table id="dt-privileges" class="table table-responsive dt-table" style="width:100%">
+ <thead>
+ <th class="dt-id">Κωδικός</th>
+ <th class="dt-privilege">Επίπεδο Πρόσβασης</th>
+ <th class="dt-includes">Περιλαμβάνει</th>
+ <th class="dt-actions"></th>
+ </thead>
+ </table>
+
+ </div>
+
+
+ </div>
+ </div>
+</div><!-- /manage -->
+
+
+
+<!-- MODAL for new/edit category -->
+<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 -->
+<div class="modal fade" id="managePrivileges" 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">Modal title</h4>
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+ </div><!-- /modal-header -->
+
+ <!-- modal-body -->
+ <div class="modal-body">
+
+ <!-- form fields -->
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="label">Όνομα Επιπέδου Πρόσβασης</label>
+ <div class="col-sm-12">
+ <input class="form-control form-control-sm" type="text" name="label" value="" required="">
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <label class="control-label col-sm-12" for="included_id">Περιλαμβάνει μέχρι και το Επίπεδο</label>
+ <div class="col-sm-12">
+ <select class="form-control form-control-sm form-select form-select-sm" id="included_id" name="included_id" required></select>
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' -->
+ </div>
+
+
+ </div><!-- /modal body -->
+
+ <div class="modal-footer">
+ <div class="row form-actions">
+
+ <div class="col">
+ <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button>
+ </div>
+ <div class="col">
+ <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button>
+ </div>
+
+ </div>
+ </div><!-- /modal-footer -->
+
+ </form><!-- /form -->
+
+ </div>
+ </div>
+</div>
diff --git a/public/assets/css/overides.css b/public/assets/css/overides.css
index 172d24e..0709f4d 100644
--- a/public/assets/css/overides.css
+++ b/public/assets/css/overides.css
@@ -40,13 +40,13 @@ html, body { font-family: "Roboto Slab", serif; font-weight: 400; }
.admin-container { font-size: .96em; }
.admin-container .top-bar a:hover { background: #ddd; }
-.admin-container .manage { padding: .5em .5em 1.5em .5em; }
+.admin-container .manage { padding: 1em; }
.admin-container .title-bar {
display: flex;
justify-content: space-between;
align-items: center;
- padding: 1em 8px 1em 16px;
+ padding: 1.5em 1em 1.5em 1em;
}
.admin-container .dt-table { font-size: 14px; }
@@ -58,11 +58,48 @@ html, body { font-family: "Roboto Slab", serif; font-weight: 400; }
}
.admin-container .modal .form-group { padding: .35em 0;}
-.admin-container .modal .form-control { padding: 1px 8px; border-radius: 4px; font-size: 15px; }
+/*.admin-container .modal .form-control { padding: 1px 8px; border-radius: 4px; font-size: 15px; } */
.admin-container .table > :not(caption) > * > * { padding: .35rem .35rem; }
.admin-container .table tbody tr:hover { background: #eee; }
ul.select2-results__options li { font-size: 14px; padding: 4px 8px; }
-.admin-container .modal-footer .form-actions { display: flex; } \ No newline at end of file
+.admin-container .modal-footer .form-actions { display: flex; }
+
+.admin-container .title-bar h5 { margin-bottom: 0; color: #333; }
+
+.admin-container table.dataTable { margin-top: 1em !important; margin-bottom: 1em !important;}
+
+.admin-container .title-bar .btn { border: 1px solid #7772; }
+.admin-container .title-bar .btn:hover { background: #ddd; }
+
+.admin-container form label { padding: 8px 1em 2px 1em; }
+
+.admin-container .form-control { border-radius: 4px; }
+
+.admin-container select[data-chosen='one'] {
+ font-weight: 700;
+ color: #000;
+}
+
+/* hack select2 caret styling
+ * (like bootstrap5 select caret)
+ * -----------------------------------------------------------------------------
+ */
+
+.select2-container--default .select2-selection--single .select2-selection__arrow b {
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
+ background-color: transparent;
+ background-size: contain;
+ border: none !important;
+ height: 16 !important;
+ width: 12px !important;
+ margin: auto !important;
+ top: 9px !important;
+ left: auto !important;
+ height: 14px;
+}
+.select2-container--default .select2-selection--single .select2-selection__arrow { width: 24px; }
+.select2-container--default .select2-selection--single { height: 31px; }
+ \ No newline at end of file
diff --git a/public/assets/js/admin/categories.js b/public/assets/js/admin/categories.js
index 0ff2b85..90eede3 100644
--- a/public/assets/js/admin/categories.js
+++ b/public/assets/js/admin/categories.js
@@ -119,7 +119,7 @@ $(document).ready(function() {
function init_table() {
// get all categories from server (ajax)
- $.getJSON( "/admin/api/categories?exclude=0")
+ $.getJSON( "/admin/api/categories")
.done(function( json ) {
// then ...
@@ -272,7 +272,7 @@ $(document).ready(function() {
};
// select action url (add or update)
- var request = '/admin/category?action=' + ((data.id == 0) ? 'add' : 'update');
+ var request = '/admin/api/category/' + ((data.id == 0) ? 'add' : 'update');
// send POST request
$.post(request, data)
diff --git a/public/assets/js/admin/privileges.js b/public/assets/js/admin/privileges.js
new file mode 100644
index 0000000..e4355c5
--- /dev/null
+++ b/public/assets/js/admin/privileges.js
@@ -0,0 +1,291 @@
+// Globals
+// -----------------------------------------------------------------------------
+var privileges = [];
+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;
+ };
+}
+
+/*
+// function for sorting an array by 'breadcrumb' attribute
+// --- -- -- - - -
+function compare_breadcrumb (a,b) {
+ if ( a.breadcrumb < b.breadcrumb ) { return -1; }
+ if ( a.breadcrumb > b.breadcrumb ) { return 1; }
+ return 0;
+}
+*/
+
+// return category record by category-id
+// --- -- -- - - -
+function privilege_record(id) {
+ var record = 0;
+ privileges.forEach(el => { if (el.id == id) record = el; });
+
+ return record;
+}
+
+/*
+// return children of parent
+// --- -- -- - - -
+function childs_of_parents(list) {
+ // if 'list' is integer then make it an one-item list
+ parents = (Number.isInteger(list)) ? [ list ] : list;
+
+ var childs = [];
+
+ if (parents.length == 0) { return []; }
+
+ parents.forEach( pid => {
+ categories.forEach( el => { if (el.parent == pid) childs.push(el.id)});
+ });
+
+ var grandchilds = childs_of_parents(childs);
+
+ return childs.concat(grandchilds);
+}
+*/
+
+// create actions html (edit and delete buttons)
+// --- -- -- - - -
+function create_actions_html(id) {
+
+ var del, edit;
+
+ del = "";
+
+ edit = [
+ '<button type="button" class="btn btn-sm btn-warning"',
+ 'data-bs-toggle="modal" data-bs-target="#managePrivileges"',
+ 'data-id="'+ id +'">',
+ '<i class="fas fa-pencil-alt"></i>',
+ '</button>'
+ ].join('\n');
+
+ return edit +' '+ del;
+}
+
+
+
+$(document).ready(function() {
+
+ // When document is ready
+ // -------------------------------------------------------------------------
+
+
+ /** init selec2 element (used to specify parent-category)
+ * --- -- -- - - -
+ */
+ $("#included_id").select2({
+ placeholder: 'Περιλαμβάνει τα δικαιώματα της',
+ dropdownParent: $('#managePrivileges'),
+ width: '100%',
+ // dropdownParent: "#manageCategory" // ref: https://github.com/select2/select2-bootstrap-theme/issues/41
+ });
+
+
+ /** init_table
+ * --- -- -- - - -
+ * get categories
+ * constuct categories array
+ * render dataTable
+ */
+ function init_table() {
+
+ // get all categories from server (ajax)
+ $.getJSON( "/admin/api/privileges")
+ .done(function( json ) {
+ // then ...
+
+ // reset categories
+ privileges.length = 0;
+
+ // construct (new) categories data
+ Object.keys(json).forEach( key => {
+ el = json[key];
+ privileges.push({
+ id: el.id,
+ label: el.label,
+ includes: ((el.includes == null) ? [] : el.includes),
+ included_id: ((el.included_id == null) ? 0 : el.included_id),
+ actions: create_actions_html(el.id)
+ });
+ });
+
+ // sort by breadcrumb
+ // categories.sort( compare_breadcrumb );
+
+ // destroy previous datatable table instances
+ $('#dt-privileges').dataTable().fnClearTable();
+ $('#dt-privileges').dataTable().fnDestroy();
+
+ // (re-)create categories datatable
+ table = $('#dt-privileges').DataTable({
+ language: { url: '/libs/DataTables/localization/Greek.json' },
+ data: privileges,
+ ordering: false,
+ columns: [
+ { data: 'id' },
+ { data: 'label' },
+ { data: 'includes' },
+ { data: 'actions' }
+ ]
+ });
+
+ })
+ .fail(function( jqxhr, textStatus, error ) {
+ console.log( "Request Failed (" + error +")" );
+ });
+
+ }
+ init_table(); // init table on first run
+
+
+
+ /** When modal show-up
+ * -------------------------------------------------------------------------
+ * ... prepare the manage-category form
+ * ... update select2 with possible parents
+ */
+ $('#managePrivileges').on('show.bs.modal', event => {
+ var button = $(event.relatedTarget); // Button that triggered the modal
+ var id = parseInt( button.data('id') ); // category_id from data-id
+ // var modal = $(this); // modal object
+
+ // update modal literature
+ // ---
+ $('#managePrivileges .modal-title').html( // modal title
+ (id) ? 'Ενημέρωση Επιπέδου Πρόσβασης' : 'Δημιουργία Επιπέδου Πρόσβασης'
+ );
+ $('#managePrivileges form input[name=id]').val( id ); // category id (hidden)
+ $('#managePrivileges form input[name=label]').val( // category label
+ (id) ? privilege_record(id).label : ""
+ );
+ prepare_included_element(id); // prepare <select> for parents
+ })
+
+ /** prepare_included_element()
+ * ---
+ * @param id (int) : id of selected privilege
+ * -> Get all posible included privileges
+ * -> call set_included_options() to render the options
+ */
+ function prepare_included_element(id) {
+ var may_included = [];
+
+ if (id) { // get all possible parents
+
+ // TODO:
+ // specify forbiden privilege IDs for being included
+
+ // filter privileges adn prepare possible included privileges
+ privileges.forEach( el => {
+ if (id != el.id) {
+ may_included.push({
+ id: el.id,
+ label: el.label
+ });
+ }
+ });
+ console.log(may_included);
+ set_included_options(may_included, privilege_record(id).included_id);
+
+
+ } else { // new record; all categories are possible parrents
+ privileges.forEach( el => {
+ may_included.push({
+ id: el.id,
+ label: el.label,
+ });
+ })
+ set_included_options(may_included, -1);
+ }
+ }
+
+ /** set_included_options()
+ * -> create options for parents <select>
+ * -> choose selected parent
+ * @param may_included (array): array of possible included privileges
+ * @param selected (int): selected included privilege
+ */
+ function set_included_options(may_included, selected) {
+ // sort parents by breadcrumb
+ // parents.sort( compare_breadcrumb );
+
+ // remove any olded options from select2
+ $('#included_id option').each(function() { $(this).remove(); });
+
+ // first option is the root category
+ $('#included_id').append('<option value="0">— κανένα —</option>')
+
+ // add all other parent options
+ may_included.forEach( i => {
+ $('#included_id').append(`<option value="${i.id}">${i.label}</option>`);
+ });
+
+ if (selected == -1) { // new category; remove any parent pre-selection
+ $('#included_id').val(0).trigger('change');
+
+ } else { // category exists; choose selected parent
+ $('#included_id').val(selected).trigger('change');
+ }
+ }
+
+
+
+
+ // When form is submited
+ // -------------------------------------------------------------------------
+
+ $('#manageCategory form').submit( event => {
+ event.preventDefault();
+
+ // prepare data to POST
+ var data = {
+ id: parseInt($('#manageCategory form input[name=id]').val()),
+ label: $('#manageCategory form input[name=label]').val(),
+ parent_id: parseInt($('#parent_id').select2('data')[0].id)
+ };
+
+ // select action url (add or update)
+ var request = '/admin/api/category/' + ((data.id == 0) ? 'add' : 'update');
+
+ // send POST request
+ $.post(request, data)
+ .done(function( data ) {
+
+ $('#manageCategory').modal('hide'); // when done, close modal
+
+ init_table(); // reload table of categories
+ });
+
+ });
+
+});
diff --git a/public/cache/.gitkeep b/public/cache/.gitkeep
deleted file mode 100755
index e69de29..0000000
--- a/public/cache/.gitkeep
+++ /dev/null