diff --git a/CHANGELOG-2.x.md b/CHANGELOG-2.x.md index 33a61487..3fb417a6 100644 --- a/CHANGELOG-2.x.md +++ b/CHANGELOG-2.x.md @@ -9,10 +9,12 @@ * Better handling of vocations: (#345) * Load from vocations.xml (No need to manually set) * Support for Monk vocation +* Better gallery, loads images from images/gallery folder * Reworked account action logs to use a single IP column as varchar(45) for both ipv4 and ipv6 (#289) * Admin Panel: save menu collapse state (https://github.com/slawkens/myaac/commit/55da00520df7463a1d1ca41931df1598e9f2ffeb) ### Internal +* Refactor account/lost pages (#326) * Refactor OTS_Player to support more distros (#348) * Refactor PHP cache to store expiration and improve typing (https://github.com/slawkens/myaac/commit/96b8e00f4999f8b4c4c97b54b97d91c6fd7df298) * Move forum show_board code to Twig (https://github.com/slawkens/myaac/commit/e0e0e467012a5fb9979cc4387af6bad1d4540279) diff --git a/install/includes/import_base_data.php b/install/includes/import_base_data.php index 59bb923e..be55dd3c 100644 --- a/install/includes/import_base_data.php +++ b/install/includes/import_base_data.php @@ -57,16 +57,6 @@ if (NewsCategory::count() === 0) { } } -if (Gallery::count() === 0) { - Gallery::create([ - 'comment' => 'Demon', - 'image' => 'images/gallery/demon.jpg', - 'thumb' => 'images/gallery/demon_thumb.gif', - 'author' => 'MyAAC', - 'ordering' => 0, - ]); -} - if(FAQ::count() == 0) { FAQ::create([ 'question' => 'What is this?', diff --git a/install/includes/schema.sql b/install/includes/schema.sql index 9fa663af..67f3c417 100644 --- a/install/includes/schema.sql +++ b/install/includes/schema.sql @@ -207,18 +207,6 @@ CREATE TABLE IF NOT EXISTS `myaac_pages` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; -CREATE TABLE IF NOT EXISTS `myaac_gallery` -( - `id` int NOT NULL AUTO_INCREMENT, - `comment` varchar(255) NOT NULL DEFAULT '', - `image` varchar(255) NOT NULL, - `thumb` varchar(255) NOT NULL, - `author` varchar(50) NOT NULL DEFAULT '', - `ordering` int NOT NULL DEFAULT 0, - `hide` tinyint NOT NULL DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; - CREATE TABLE IF NOT EXISTS `myaac_settings` ( `id` int NOT NULL AUTO_INCREMENT, diff --git a/system/functions.php b/system/functions.php index 1dd3edf5..f6c1ea1f 100644 --- a/system/functions.php +++ b/system/functions.php @@ -517,7 +517,12 @@ function template_place_holder($type): string $ret .= $debugBarRenderer->renderHead(); } } + elseif ($type === 'head_end') { + $ret .= setting('core.html_head'); + } elseif ($type === 'body_start') { + $ret .= setting('core.html_body'); + $ret .= $twig->render('browsehappy.html.twig'); if (admin()) { @@ -528,6 +533,8 @@ function template_place_holder($type): string } } elseif($type === 'body_end') { + $ret .= setting('core.html_footer'); + $ret .= template_ga_code(); if (isset($debugBar)) { $ret .= $debugBarRenderer->render(); diff --git a/system/migrations/50-gallery.sql b/system/migrations/50-gallery.sql new file mode 100644 index 00000000..09efb653 --- /dev/null +++ b/system/migrations/50-gallery.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `myaac_gallery` +( + `id` int NOT NULL AUTO_INCREMENT, + `comment` varchar(255) NOT NULL DEFAULT '', + `image` varchar(255) NOT NULL, + `thumb` varchar(255) NOT NULL, + `author` varchar(50) NOT NULL DEFAULT '', + `ordering` int NOT NULL DEFAULT 0, + `hide` tinyint NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; diff --git a/system/migrations/50.php b/system/migrations/50.php index d6a78207..f7df11de 100644 --- a/system/migrations/50.php +++ b/system/migrations/50.php @@ -1,36 +1,16 @@ hasColumn('accounts', '2fa_type')) { - $db->addColumn('accounts', '2fa_type', "tinyint NOT NULL DEFAULT 0 AFTER `web_flags`"); - } - - if (!$db->hasColumn('accounts', '2fa_secret')) { - $db->addColumn('accounts', '2fa_secret', "varchar(16) NOT NULL DEFAULT '' AFTER `2fa_type`"); - } - - // add myaac_account_email_codes table - if (!$db->hasTable(TABLE_PREFIX . 'account_email_codes')) { - $db->exec(file_get_contents(__DIR__ . '/46-account_email_codes.sql')); + if ($db->hasTable(TABLE_PREFIX . 'gallery')) { + $db->dropTable(TABLE_PREFIX . 'gallery'); } }; $down = function () use ($db) { - if ($db->hasColumn('accounts', '2fa_type')) { - $db->dropColumn('accounts', '2fa_type'); - } - - if ($db->hasColumn('accounts', '2fa_secret')) { - $db->dropColumn('accounts', '2fa_secret'); - } - - if ($db->hasTable(TABLE_PREFIX . 'account_email_codes')) { - $db->dropTable(TABLE_PREFIX . 'account_email_codes'); + if (!$db->hasTable(TABLE_PREFIX . 'gallery')) { + $db->query(file_get_contents(__DIR__ . '/50-gallery.sql')); } }; diff --git a/system/migrations/51.php b/system/migrations/51.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/system/migrations/51.php @@ -0,0 +1 @@ +display('error_box.html.twig', array('errors' => $errors)); - } - - if(!isset($_GET['image'])) { - $twig->display('gallery.form.html.twig', array( - 'link' => getLink('gallery/' . ($action == 'edit' ? 'edit' : 'add')), - 'action' => $action, - 'id' => isset($id) ? $id : null, - 'comment' => isset($comment) ? $comment : null, - 'image' => isset($image) ? $image : null, - 'author' => isset($author) ? $author : null - )); - } - } - else - echo 'You cannot edit/add gallery items as it seems your PHP installation doesnt have GD support enabled. Visit PHP Manual for more info.'; -} - -if(isset($_GET['image'])) -{ - $image = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'gallery` WHERE `id` = ' . $db->quote($_GET['image']) . ' ORDER by `ordering` LIMIT 1;'); - if($image->rowCount() == 1) - $image = $image->fetch(); - else - { - echo 'Image with this id does not exists.'; - return; - } - - $previous_image = $db->query('SELECT `id` FROM `' . TABLE_PREFIX . 'gallery` WHERE `id` = ' . $db->quote($image['id'] - 1) . ' ORDER by `ordering`;'); - if($previous_image->rowCount() == 1) - $previous_image = $previous_image->fetch(); - else - $previous_image = NULL; - - $next_image = $db->query('SELECT `id` FROM `' . TABLE_PREFIX . 'gallery` WHERE `id` = ' . $db->quote($image['id'] + 1) . ' ORDER by `ordering`;'); - if($next_image->rowCount() == 1) - $next_image = $next_image->fetch(); - else - $next_image = NULL; - - $twig->display('gallery.get.html.twig', array( - 'previous' => $previous_image ? $previous_image['id'] : null, - 'next' => $next_image ? $next_image['id'] : null, - 'image' => $image - )); - return; -} - -$images = Cache::remember('gallery_' . ($canEdit ? '1' : '0'), 60, function () use ($db, $canEdit) { - return $db->query('SELECT `id`, `comment`, `image`, `author`, `thumb`' . - ($canEdit ? ', `hide`, `ordering`' : '') . - ' FROM `' . TABLE_PREFIX . 'gallery`' . - (!$canEdit ? ' WHERE `hide` != 1' : '') . - ' ORDER BY `ordering`;')->fetchAll(PDO::FETCH_ASSOC); + return array_map(function ($image) { + return basename($image); + }, $images); }); -$last = count($images); -if(!$last) -{ -?> - There are no images added to gallery yet. -display('gallery.html.twig', array( +$twig->display('gallery.html.twig', [ 'images' => $images, - 'last' => $last, - 'canEdit' => $canEdit -)); - -class Gallery -{ - static public function add($comment, $image, $author, &$errors) - { - global $db; - if(isset($comment[0]) && isset($image[0]) && isset($author[0])) - { - $query = - $db->query( - 'SELECT `ordering`' . - ' FROM `' . TABLE_PREFIX . 'gallery`' . - ' ORDER BY `ordering`' . ' DESC LIMIT 1' - ); - - $ordering = 0; - if($query->rowCount() > 0) { - $query = $query->fetch(); - $ordering = $query['ordering'] + 1; - } - - $pathinfo = pathinfo($image); - $extension = strtolower($pathinfo['extension']); - $thumb_filename = GALLERY_DIR . $pathinfo['filename'] . '_thumb.' . $extension; - $filename = GALLERY_DIR . $pathinfo['filename'] . '.' . $extension; - if($db->insert(TABLE_PREFIX . 'gallery', array( - 'comment' => $comment, - 'image' => $filename, 'author' => $author, - 'thumb' => $thumb_filename, - 'ordering' => $ordering))) { - if(self::generateThumb($db->lastInsertId(), $image, $errors)) - self::resize($image, 650, 500, $filename, $errors); - } - } - else - $errors[] = 'Please fill all inputs.'; - - return !count($errors); - } - - static public function get($id) { - return ModelsGallery::find($id)->toArray(); - } - - static public function update($id, $comment, $image, $author) { - $pathinfo = pathinfo($image); - $extension = strtolower($pathinfo['extension']); - $filename = GALLERY_DIR . $pathinfo['filename'] . '.' . $extension; - - if(ModelsGallery::where('id', $id)->update([ - 'comment' => $comment, - 'image' => $filename, - 'author' => $author - ])) { - if(self::generateThumb($id, $image, $errors)) - self::resize($image, 650, 500, $filename, $errors); - } - } - - static public function delete($id, &$errors) - { - if(isset($id)) - { - $row = ModelsGallery::find($id); - if($row) - if (!$row->delete()) { - $errors[] = 'Fail during delete Gallery'; - } - else - $errors[] = 'Image with id ' . $id . ' does not exists.'; - } - else - $errors[] = 'id not set'; - - return !count($errors); - } - - static public function toggleHide($id, &$errors) - { - if(isset($id)) - { - $row = ModelsGallery::find($id); - if($row) { - $row->hide = $row->hide == 1 ? 0 : 1; - if (!$row->save()) { - $errors[] = 'Fail during toggle hide Gallery'; - } - } else - $errors[] = 'Image with id ' . $id . ' does not exists.'; - } - else - $errors[] = 'id not set'; - - return !count($errors); - } - - static public function move($id, $i, &$errors) - { - global $db; - $query = self::get($id); - if($query !== false) - { - $ordering = $query['ordering'] + $i; - $old_record = $db->select(TABLE_PREFIX . 'gallery', array('ordering' => $ordering)); - if($old_record !== false) { - ModelsGallery::where('ordering', $ordering)->update([ - 'ordering' => $query['ordering'], - ]); - } - - ModelsGallery::where('id', $id)->update([ - 'ordering' => $ordering, - ]); - } - else - $errors[] = 'Image with id ' . $id . ' does not exists.'; - - return !count($errors); - } - - static public function resize($file, $new_width, $new_height, $new_file, &$errors) - { - $pathinfo = pathinfo($file); - $extension = strtolower($pathinfo['extension']); - - switch ($extension) - { - case 'gif': // GIF - $image = imagecreatefromgif($file); - break; - case 'jpg': // JPEG - case 'jpeg': - $image = imagecreatefromjpeg($file); - break; - case 'png': // PNG - $image = imagecreatefrompng($file); - break; - default: - $errors[] = 'Unsupported file format.'; - return false; - } - - $width = imagesx($image); - $height = imagesy($image); - - // create a new temporary image - $tmp_img = imagecreatetruecolor($new_width, $new_height); - - // copy and resize old image into new image - imagecopyresized($tmp_img, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - - // save thumbnail into a file - switch($extension) - { - case 'gif': - imagegif($tmp_img, $new_file); - break; - - case 'jpg': - case 'jpeg': - imagejpeg($tmp_img, $new_file); - break; - - case 'png': - imagepng($tmp_img, $new_file); - break; - } - - return true; - } - - static public function generateThumb($id, $file, &$errors) - { - $pathinfo = pathinfo($file); - $extension = strtolower($pathinfo['extension']); - $thumb_filename = GALLERY_DIR . $pathinfo['filename'] . '_thumb.' . $extension; - - if(!self::resize($file, 170, 110, $thumb_filename, $errors)) - return false; - - if(isset($id)) - { - $row = ModelsGallery::find($id); - if($row) { - $row->thumb = $thumb_filename; - $row->save(); - } else - $errors[] = 'Image with id ' . $id . ' does not exists.'; - } - else - $errors[] = 'id not set'; - - return !count($errors); - } -} +]); diff --git a/system/settings.php b/system/settings.php index 8a49a218..e667474e 100644 --- a/system/settings.php +++ b/system/settings.php @@ -156,7 +156,7 @@ return [ 'footer' => [ 'name' => 'Custom Text', 'type' => 'textarea', - 'desc' => 'Text displayed in the footer.
For example: ' . escapeHtml('
') . 'Your Server © 2023. All rights reserved.
', + 'desc' => 'Text displayed in the footer.
For example: ' . escapeHtml('
') . 'Your Server © ' . date("Y") . '. All rights reserved.
', 'default' => '', ], 'footer_load_time' => [ @@ -258,6 +258,28 @@ return [ 'desc' => 'Allow MyAAC to report anonymous usage statistics to developers? The data is sent only once per 30 days and is fully confidential. It won\'t affect the performance of your website', 'default' => true, ], + [ + 'type' => 'section', + 'title' => 'Custom HTML', + ], + 'html_head' => [ + 'name' => 'HTML Head', + 'type' => 'textarea', + 'desc' => escapeHtml('These scripts will be printed in the section. Can be, for example, Google Analytics code.'), + 'default' => '', + ], + 'html_body' => [ + 'name' => 'HTML Body', + 'type' => 'textarea', + 'desc' => escapeHtml('These scripts will be printed just below the opening tag.'), + 'default' => '', + ], + 'html_footer' => [ + 'name' => 'HTML Footer', + 'type' => 'textarea', + 'desc' => escapeHtml('These scripts will be printed above the closing tag.'), + 'default' => '', + ], [ 'type' => 'category', 'title' => 'Game', diff --git a/system/src/Commands/GiveAdminCommand.php b/system/src/Commands/GiveAdminCommand.php new file mode 100644 index 00000000..d2565783 --- /dev/null +++ b/system/src/Commands/GiveAdminCommand.php @@ -0,0 +1,50 @@ +setName('give:admin') + ->setDescription('This command adds super admin privileges to selected user') + ->addArgument('account', InputArgument::REQUIRED, 'Account E-Mail, name or id'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + require SYSTEM . 'init.php'; + + $io = new SymfonyStyle($input, $output); + + $account = new \OTS_Account(); + + $accountParam = $input->getArgument('account'); + if (str_contains($accountParam, '@')) { + $account->findByEMail($accountParam); + } + else { + if (USE_ACCOUNT_NAME || USE_ACCOUNT_NUMBER) { + $account->find($accountParam); + } + else { + $account->load($accountParam); + } + } + + if (!$account->isLoaded()) { + $io->error('Cannot find account mit supplied parameter: ' . $accountParam); + return self::FAILURE; + } + + $account->setCustomField('web_flags', 3); + $io->success('Successfully added admin privileges to ' . $accountParam . ' (E-Mail: ' . $account->getEMail() . ')'); + return self::SUCCESS; + } +} diff --git a/system/src/Models/Gallery.php b/system/src/Models/Gallery.php deleted file mode 100644 index 4e52c1f0..00000000 --- a/system/src/Models/Gallery.php +++ /dev/null @@ -1,18 +0,0 @@ - - {{ csrf() }} - {% if action == 'edit' %} - - {% endif %} - - - - - - - -
{% if action == 'edit' %}Edit{% else %}Add{% endif %} image
- - - - - - - - - - - - - - - -
Comment:
Image URL:
Author:
-
-
- -

diff --git a/system/templates/gallery.get.html.twig b/system/templates/gallery.get.html.twig deleted file mode 100644 index fa32b932..00000000 --- a/system/templates/gallery.get.html.twig +++ /dev/null @@ -1,15 +0,0 @@ -
- {% if next is not null %} - next - {% endif %} - {% if previous is not null %} - previous - {% endif %} -
- back -
-
-
- -
{{ image.comment }}
-
\ No newline at end of file diff --git a/system/templates/gallery.html.twig b/system/templates/gallery.html.twig index 49e8aafa..7ec35c1d 100644 --- a/system/templates/gallery.html.twig +++ b/system/templates/gallery.html.twig @@ -1,38 +1,31 @@ -Click on the image to enlarge.

-{% set i = 0 %} -{% for image in images %} - {% set i = i + 1 %} - - - - - {% if canEdit %} - - {% endif %} - -
- - - - {{ image.comment }} - - Edit - - - Delete - - - {% if image.hide != 1 %}Hide{% else %}Show{% endif %} - - {% if i != 1 %} - - Move up - - {% endif %} - {% if i != last %} - - Move down - - {% endif %} -
-{% endfor %} + +
+ + {% set i = 1 %} + {% for image in images %} +
+
{{ i }} / {{ images|length }}
+ +
+ + {% set i = i + 1 %} + {% endfor %} + + + + + +
+ + +
+ {% set i = 1 %} + + {% for image in images %} + + {% set i = i + 1 %} + {% endfor %} +
+ + + diff --git a/templates/kathrine/news.html.twig b/templates/kathrine/news.html.twig index 17b0779e..a3e7a12e 100644 --- a/templates/kathrine/news.html.twig +++ b/templates/kathrine/news.html.twig @@ -2,9 +2,9 @@
-
{{ date|date(config.news_date_format) }} -
+
{{ date|date(setting('core.news_date_format')) }} -
{{ title }}
- {% if author is not empty %} + {% if setting('core.news_author') and author is not empty %}
Author: {{ author }}
{% endif %}
diff --git a/templates/tibiacom/boxes/gallery.php b/templates/tibiacom/boxes/gallery.php index cee97d02..f68d6380 100644 --- a/templates/tibiacom/boxes/gallery.php +++ b/templates/tibiacom/boxes/gallery.php @@ -1,14 +1,12 @@ display('gallery.html.twig', array( - 'image' => $gallery->toArray() + 'image' => GALLERY_DIR . $configGalleryImageThumb, )); } diff --git a/templates/tibiacom/boxes/templates/gallery.html.twig b/templates/tibiacom/boxes/templates/gallery.html.twig index 7ef321ed..0e066a10 100644 --- a/templates/tibiacom/boxes/templates/gallery.html.twig +++ b/templates/tibiacom/boxes/templates/gallery.html.twig @@ -1,6 +1,6 @@
- - Screenshot of the Day + + Screenshot of the Day
diff --git a/templates/tibiacom/config.ini b/templates/tibiacom/config.ini index 1a606da1..7733627e 100644 --- a/templates/tibiacom/config.ini +++ b/templates/tibiacom/config.ini @@ -15,4 +15,4 @@ network_twitter = "tibia" background_image = "background-artwork.jpg" logo_image = "tibia-logo-artwork-top.gif" -gallery_image_id_from_database = 1 \ No newline at end of file +gallery_image_thumb = "demon_thumb.gif" diff --git a/tools/css/gallery.css b/tools/css/gallery.css new file mode 100644 index 00000000..d62384a4 --- /dev/null +++ b/tools/css/gallery.css @@ -0,0 +1,85 @@ +/* Slideshow container */ +.slideshow-container { + max-width: 1000px; + position: relative; + margin: auto; +} + +/* Hide the images by default */ +.mySlides { + display: none; +} + +/* Next & previous buttons */ +.prev, .next { + cursor: pointer; + position: absolute; + top: 50%; + width: auto; + margin-top: -22px; + padding: 16px; + color: white; + font-weight: bold; + font-size: 18px; + transition: 0.6s ease; + border-radius: 0 3px 3px 0; + user-select: none; +} + +/* Position the "next button" to the right */ +.next { + right: 0; + border-radius: 3px 0 0 3px; +} + +/* On hover, add a black background color with a little bit see-through */ +.prev:hover, .next:hover { + background-color: rgba(0,0,0,0.8); +} + +/* Caption text */ +.text { + color: #f2f2f2; + font-size: 15px; + padding: 8px 12px; + position: absolute; + bottom: 8px; + width: 100%; + text-align: center; +} + +/* Number text (1/3 etc) */ +.numbertext { + color: #f2f2f2; + font-size: 12px; + padding: 8px 12px; + position: absolute; + top: 0; +} + +/* The dots/bullets/indicators */ +.dot { + cursor: pointer; + height: 15px; + width: 15px; + margin: 0 2px; + background-color: #bbb; + border-radius: 50%; + display: inline-block; + transition: background-color 0.6s ease; +} + +.active, .dot:hover { + background-color: #717171; +} + +/* Fading animation */ +.fade-effect { + animation-name: fade-effect; + animation-duration: 1.5s; +} + +@keyframes fade-effect { + from {opacity: .4} + to {opacity: 1} +} diff --git a/tools/js/gallery.js b/tools/js/gallery.js new file mode 100644 index 00000000..8ffb4adf --- /dev/null +++ b/tools/js/gallery.js @@ -0,0 +1,28 @@ +let slideIndex = 1; +showSlides(slideIndex); + +// Next/previous controls +function plusSlides(n) { + showSlides(slideIndex += n); +} + +// Thumbnail image controls +function currentSlide(n) { + showSlides(slideIndex = n); +} + +function showSlides(n) { + let i; + let slides = document.getElementsByClassName("mySlides"); + let dots = document.getElementsByClassName("dot"); + if (n > slides.length) {slideIndex = 1} + if (n < 1) {slideIndex = slides.length} + for (i = 0; i < slides.length; i++) { + slides[i].style.display = "none"; + } + for (i = 0; i < dots.length; i++) { + dots[i].className = dots[i].className.replace(" active", ""); + } + slides[slideIndex-1].style.display = "block"; + dots[slideIndex-1].className += " active"; +} \ No newline at end of file