diff --git a/database/2018_10_11_194124_fix_news_tables.php b/database/2018_10_11_194124_fix_news_tables.php new file mode 100644 index 00000000..a88bf424 --- /dev/null +++ b/database/2018_10_11_194124_fix_news_tables.php @@ -0,0 +1,47 @@ +exec(" + ALTER TABLE `msz_news_categories` + CHANGE COLUMN `is_hidden` `category_is_hidden` TINYINT(1) NOT NULL DEFAULT '0' AFTER `category_description`, + CHANGE COLUMN `created_at` `category_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `category_is_hidden`, + DROP COLUMN `updated_at`; + "); + + $conn->exec(" + ALTER TABLE `msz_news_posts` + CHANGE COLUMN `comment_section_id` `comment_section_id` INT(10) UNSIGNED NULL DEFAULT NULL AFTER `user_id`, + CHANGE COLUMN `is_featured` `post_is_featured` TINYINT(1) NOT NULL DEFAULT '0' AFTER `comment_section_id`, + CHANGE COLUMN `scheduled_for` `post_scheduled` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `post_text`, + CHANGE COLUMN `created_at` `post_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `post_scheduled`, + CHANGE COLUMN `updated_at` `post_updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP AFTER `post_created`, + CHANGE COLUMN `deleted_at` `post_deleted` TIMESTAMP NULL DEFAULT NULL AFTER `post_updated`, + ADD INDEX `news_posts_indices` (`post_is_featured`, `post_scheduled`, `post_created`); + "); +} + +function migrate_down(PDO $conn): void +{ + $conn->exec(" + ALTER TABLE `msz_news_posts` + CHANGE COLUMN `post_is_featured` `is_featured` TINYINT(1) NOT NULL DEFAULT '0' AFTER `category_id`, + CHANGE COLUMN `post_scheduled` `scheduled_for` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `post_text`, + CHANGE COLUMN `post_created` `created_at` TIMESTAMP NULL DEFAULT NULL AFTER `scheduled_for`, + CHANGE COLUMN `post_updated` `updated_at` TIMESTAMP NULL DEFAULT NULL AFTER `created_at`, + CHANGE COLUMN `post_deleted` `deleted_at` TIMESTAMP NULL DEFAULT NULL AFTER `updated_at`, + CHANGE COLUMN `comment_section_id` `comment_section_id` INT(10) UNSIGNED NULL DEFAULT NULL AFTER `deleted_at`, + DROP INDEX `news_posts_indices`; + "); + + $conn->exec(" + ALTER TABLE `msz_news_categories` + CHANGE COLUMN `category_is_hidden` `is_hidden` TINYINT(1) NOT NULL DEFAULT '0' AFTER `category_description`, + CHANGE COLUMN `category_created` `created_at` TIMESTAMP NULL DEFAULT NULL AFTER `is_hidden`, + ADD COLUMN `updated_at` TIMESTAMP NULL DEFAULT NULL AFTER `created_at`; + "); +} diff --git a/public/manage/news.php b/public/manage/news.php index 5727f2f3..19d0ff30 100644 --- a/public/manage/news.php +++ b/public/manage/news.php @@ -4,16 +4,24 @@ require_once '../../misuzu.php'; $newsPerms = perms_get_user(MSZ_PERMS_NEWS, user_session_current('user_id', 0)); switch ($_GET['v'] ?? null) { - case 'index': - break; - + default: case 'posts': if (!perms_check($newsPerms, MSZ_PERM_NEWS_MANAGE_POSTS)) { echo render_error(403); break; } - echo 'posts'; + $postTake = 15; + $postOffset = (int)($_GET['o'] ?? 0); + $posts = news_posts_get($postOffset, $postTake, null, false, true, false); + $postsCount = news_posts_count(null, false, true, false); + + echo tpl_render('manage.news.posts', [ + 'news_posts' => $posts, + 'posts_offset' => $postOffset, + 'posts_take' => $postTake, + 'posts_count' => $postsCount, + ]); break; case 'categories': @@ -24,9 +32,58 @@ switch ($_GET['v'] ?? null) { $catTake = 15; $catOffset = (int)($_GET['o'] ?? 0); - $cats = news_categories_get($catOffset, $catTake); + $categories = news_categories_get($catOffset, $catTake, true, false, true); + $categoryCount = news_categories_count(true); - echo 'cats'; - var_dump($cats); + echo tpl_render('manage.news.categories', [ + 'news_categories' => $categories, + 'categories_offset' => $catOffset, + 'categories_take' => $catTake, + 'categories_count' => $categoryCount, + ]); + break; + + case 'category': + $category = []; + $categoryId = (int)($_GET['c'] ?? null); + + if (!empty($_POST['category']) && csrf_verify('news_category', $_POST['csrf'] ?? '')) { + $categoryId = news_category_create( + $_POST['category']['name'] ?? null, + $_POST['category']['description'] ?? null, + !empty($_POST['category']['hidden']), + (int)($_POST['category']['id'] ?? null) + ); + } + + if ($categoryId > 0) { + $category = news_category_get($categoryId); + } + + echo tpl_render('manage.news.category', compact('category')); + break; + + case 'post': + $post = []; + $postId = (int)($_GET['p'] ?? null); + $categories = news_categories_get(0, 0, false, false, true); + + if (!empty($_POST['post']) && csrf_verify('news_post', $_POST['csrf'] ?? '')) { + $postId = news_post_create( + $_POST['post']['title'] ?? null, + $_POST['post']['text'] ?? null, + (int)($_POST['post']['category'] ?? null), + user_session_current('user_id'), + !empty($_POST['post']['featured']), + null, + (int)($_POST['post']['id'] ?? null) + ); + } + + if ($postId > 0) { + $post = news_post_get($postId); + } + + echo tpl_render('manage.news.post', compact('post', 'categories')); break; } diff --git a/public/news.php b/public/news.php index 501cfc29..a15606fc 100644 --- a/public/news.php +++ b/public/news.php @@ -43,7 +43,7 @@ if ($postId !== null) { } if ($categoryId !== null) { - $category = news_categories_single($categoryId, true); + $category = news_category_get($categoryId, true); if (!$category || $postsOffset < 0 || $postsOffset >= $category['posts_count']) { echo render_error(404); diff --git a/src/news.php b/src/news.php index a83ec526..488e26e8 100644 --- a/src/news.php +++ b/src/news.php @@ -2,11 +2,79 @@ define('MSZ_PERM_NEWS_MANAGE_POSTS', 1); define('MSZ_PERM_NEWS_MANAGE_CATEGORIES', 1 << 1); +function news_post_create( + string $title, + string $text, + int $category, + int $user, + bool $featured = false, + ?int $scheduled = null, + ?int $postId = null +): int { + if ($postId < 1) { + $post = db_prepare(' + INSERT INTO `msz_news_posts` + (`category_id`, `user_id`, `post_is_featured`, `post_title`, `post_text`, `post_scheduled`) + VALUES + (:category, :user, :featured, :title, :text, COALESCE(:scheduled, CURRENT_TIMESTAMP)) + '); + } else { + $post = db_prepare(' + UPDATE `msz_news_posts` + SET `category_id` = :category, + `user_id` = :user, + `post_is_featured` = :featured, + `post_title` = :title, + `post_text` = :text, + `post_scheduled` = COALESCE(:scheduled, `post_scheduled`) + WHERE `post_id` = :id + '); + $post->bindValue('id', $postId); + } + + $post->bindValue('title', $title); + $post->bindValue('text', $text); + $post->bindValue('category', $category); + $post->bindValue('user', $user); + $post->bindValue('featured', $featured ? 1 : 0); + $post->bindValue('scheduled', empty($scheduled) ? null : date('Y-m-d H:i:s', $scheduled)); + + return $post->execute() ? ($postId < 1 ? (int)db_last_insert_id() : $postId) : 0; +} + +function news_category_create(string $name, string $description, bool $isHidden, ?int $categoryId = null): int +{ + if ($categoryId < 1) { + $category = db_prepare(' + INSERT INTO `msz_news_categories` + (`category_name`, `category_description`, `category_is_hidden`) + VALUES + (:name, :description, :hidden) + '); + } else { + $category = db_prepare(' + UPDATE `msz_news_categories` + SET `category_name` = :name, + `category_description` = :description, + `category_is_hidden` = :hidden + WHERE `category_id` = :id + '); + $category->bindValue('id', $categoryId); + } + + $category->bindValue('name', $name); + $category->bindValue('description', $description); + $category->bindValue('hidden', $isHidden ? 1 : 0); + + return $category->execute() ? ($categoryId < 1 ? (int)db_last_insert_id() : $categoryId) : 0; +} + function news_categories_get( int $offset, int $take, bool $includePostCount = false, bool $featuredOnly = false, + bool $includeHidden = false, bool $exposeScheduled = false, bool $excludeDeleted = true ): array { @@ -16,28 +84,30 @@ function news_categories_get( $query = sprintf( ' SELECT - `category_id`, `category_name`, `is_hidden`, - `created_at`, `updated_at`, + `category_id`, `category_name`, `category_is_hidden`, + `category_created`, ( SELECT COUNT(`post_id`) FROM `msz_news_posts` WHERE %2$s %3$s %4$s ) as `posts_count` FROM `msz_news_categories` + %5$s GROUP BY `category_id` ORDER BY `category_id` DESC %1$s ', $getAll ? '' : 'LIMIT :offset, :take', - $featuredOnly ? '`is_featured`' : '1', - $exposeScheduled ? '' : 'AND `scheduled_for` < NOW()', - $excludeDeleted ? 'AND `deleted_at` IS NULL' : '' + $featuredOnly ? '`post_is_featured` != 0' : '1', + $exposeScheduled ? '' : 'AND `post_scheduled` < NOW()', + $excludeDeleted ? 'AND `post_deleted` IS NULL' : '', + $includeHidden ? '' : 'WHERE `category_is_hidden` != 0' ); } else { $query = sprintf(' SELECT - `category_id`, `category_name`, `is_hidden`, - `created_at`, `updated_at` + `category_id`, `category_name`, `category_is_hidden`, + `category_created` FROM `msz_news_categories` ORDER BY `category_id` DESC %s @@ -55,7 +125,18 @@ function news_categories_get( return $cats ? $cats : []; } -function news_categories_single( +function news_categories_count(bool $includeHidden = false): int +{ + $countCats = db_prepare(sprintf(' + SELECT COUNT(`category_id`) + FROM `msz_news_categories` + %s + ', $includeHidden ? '' : 'WHERE `category_is_hidden` = 0')); + + return $countCats->execute() ? (int)$countCats->fetchColumn() : 0; +} + +function news_category_get( int $category, bool $includePostCount = false, bool $featuredOnly = false, @@ -66,25 +147,29 @@ function news_categories_single( $query = sprintf( ' SELECT - c.`category_id`, c.`category_name`, c.`category_description`, - COUNT(p.`post_id`) AS `posts_count` - FROM `msz_news_categories` as c - LEFT JOIN `msz_news_posts` as p - ON c.`category_id` = p.`category_id` - WHERE c.`category_id` = :category %1$s %2$s %3$s - GROUP BY c.`category_id` + `category_id`, `category_name`, `category_description`, + `category_is_hidden`, `category_created`, + ( + SELECT COUNT(`post_id`) + FROM `msz_news_posts` + WHERE `category_id` = `category_id` %1$s %2$s %3$s + ) as `posts_count` + FROM `msz_news_categories` + WHERE `category_id` = :category + GROUP BY `category_id` ', - $featuredOnly ? 'AND p.`is_featured` = 1' : '', - $exposeScheduled ? '' : 'AND p.`scheduled_for` < NOW()', - $excludeDeleted ? 'AND p.`deleted_at` IS NULL' : '' + $featuredOnly ? 'AND `post_is_featured` != 0' : '', + $exposeScheduled ? '' : 'AND `post_scheduled` < NOW()', + $excludeDeleted ? 'AND `post_deleted` IS NULL' : '' ); } else { $query = ' SELECT - c.`category_id`, c.`category_name`, c.`category_description`, - FROM `msz_news_categories` as c - WHERE c.`category_id` = :category - GROUP BY c.`category_id` + `category_id`, `category_name`, `category_description`, + `category_is_hidden`, `category_created` + FROM `msz_news_categories` + WHERE `category_id` = :category + GROUP BY `category_id` '; } @@ -109,9 +194,9 @@ function news_posts_count( WHERE %1$s %2$s %3$s %4$s ', $hasCategory ? '`category_id` = :category' : '1', - $featuredOnly ? 'AND `is_featured` = 1' : '', - $exposeScheduled ? '' : 'AND `scheduled_for` < NOW()', - $excludeDeleted ? 'AND `deleted_at` IS NULL' : '' + $featuredOnly ? 'AND `post_is_featured` != 0' : '', + $exposeScheduled ? '' : 'AND `post_scheduled` < NOW()', + $excludeDeleted ? 'AND `post_deleted` IS NULL' : '' )); if ($hasCategory) { @@ -135,7 +220,8 @@ function news_posts_get( $getPosts = db_prepare(sprintf( ' SELECT - p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`, + p.`post_id`, p.`post_is_featured`, p.`post_title`, p.`post_text`, p.`comment_section_id`, + p.`post_created`, p.`post_updated`, p.`post_deleted`, p.`post_scheduled`, c.`category_id`, c.`category_name`, u.`user_id`, u.`username`, COALESCE(u.`user_colour`, r.`role_colour`) as `user_colour`, @@ -152,13 +238,13 @@ function news_posts_get( LEFT JOIN `msz_roles` as r ON u.`display_role` = r.`role_id` WHERE %5$s %2$s %3$s %4$s - ORDER BY p.`created_at` DESC + ORDER BY p.`post_created` DESC %1$s ', $getAll ? '' : 'LIMIT :offset, :take', - $featuredOnly ? 'AND p.`is_featured` = 1' : '', - $exposeScheduled ? '' : 'AND p.`scheduled_for` < NOW()', - $excludeDeleted ? 'AND p.`deleted_at` IS NULL' : '', + $featuredOnly ? 'AND p.`post_is_featured` != 0' : '', + $exposeScheduled ? '' : 'AND p.`post_scheduled` < NOW()', + $excludeDeleted ? 'AND p.`post_deleted` IS NULL' : '', $hasCategory ? 'p.`category_id` = :category' : '1' )); @@ -191,7 +277,8 @@ function news_post_get(int $postId): array { $getPost = db_prepare(' SELECT - p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`, p.`comment_section_id`, + p.`post_id`, p.`post_title`, p.`post_text`, p.`post_is_featured`, p.`post_scheduled`, + p.`post_created`, p.`post_updated`, p.`post_deleted`, p.`comment_section_id`, c.`category_id`, c.`category_name`, u.`user_id`, u.`username`, COALESCE(u.`user_colour`, r.`role_colour`) as `user_colour` diff --git a/templates/manage/general/overview.twig b/templates/manage/general/overview.twig index 7b6836eb..2ed3dd07 100644 --- a/templates/manage/general/overview.twig +++ b/templates/manage/general/overview.twig @@ -4,7 +4,8 @@
Overview
- Welcome to Manage, here you can manage things. +

Welcome to Manage, here you can manage things.

+

Please teach me how to give a shit about management panel. -flashwave

{% endblock %} diff --git a/templates/manage/news/categories.twig b/templates/manage/news/categories.twig new file mode 100644 index 00000000..8e88f119 --- /dev/null +++ b/templates/manage/news/categories.twig @@ -0,0 +1,21 @@ +{% extends 'manage/news/master.twig' %} +{% from 'macros.twig' import pagination %} + +{% block manage_content %} +
+
Categories
+ + New Category + + {% for cat in news_categories %} +

+ {{ cat.category_id }} + {{ cat.category_name }}, + {{ cat.category_is_hidden }}, + {{ cat.category_created }} +

+ {% endfor %} + + {{ pagination(categories_count, categories_take, categories_offset, '?v=categories') }} +
+{% endblock %} diff --git a/templates/manage/news/category.twig b/templates/manage/news/category.twig new file mode 100644 index 00000000..d8829bb0 --- /dev/null +++ b/templates/manage/news/category.twig @@ -0,0 +1,31 @@ +{% extends 'manage/news/master.twig' %} + +{% set is_new = category|length < 1 %} + +{% block manage_content %} +
+
{{ is_new ? 'New Category' : 'Editing ' ~ category.category_name }}
+ + {{ 'news_category'|csrf|raw }} + + + + + + + + + + + + + + + + + +
Name
Description
Is Hidden
+ + +
+{% endblock %} diff --git a/templates/manage/news/post.twig b/templates/manage/news/post.twig new file mode 100644 index 00000000..ba7a2640 --- /dev/null +++ b/templates/manage/news/post.twig @@ -0,0 +1,41 @@ +{% extends 'manage/news/master.twig' %} + +{% set is_new = post|length < 1 %} + +{% block manage_content %} +
+
{{ is_new ? 'New Post' : 'Editing ' ~ post.post_title }}
+ + {{ 'news_post'|csrf|raw }} + + + + + + + + + + + + + + + + + + + + + +
Name
Category + +
Is Featured
+ + +
+{% endblock %} diff --git a/templates/manage/news/posts.twig b/templates/manage/news/posts.twig new file mode 100644 index 00000000..40b88c17 --- /dev/null +++ b/templates/manage/news/posts.twig @@ -0,0 +1,27 @@ +{% extends 'manage/news/master.twig' %} +{% from 'macros.twig' import pagination %} + +{% block manage_content %} +
+
News Posts
+ + New Post + + {% for post in news_posts %} +

+ {{ post.post_id }} + Cat: {{ post.category_id }} + {{ post.post_is_featured }}, + {{ post.user_id }}, + {{ post.post_title }}, + {{ post.post_scheduled }}, + {{ post.post_created }}, + {{ post.post_updated }}, + {{ post.post_deleted }}, + {{ post.comment_section_id }} +

+ {% endfor %} + + {{ pagination(posts_count, posts_take, posts_offset, '?v=categories') }} +
+{% endblock %} diff --git a/templates/news/macros.twig b/templates/news/macros.twig index 51f49b5f..734bb206 100644 --- a/templates/news/macros.twig +++ b/templates/news/macros.twig @@ -22,8 +22,8 @@
- diff --git a/templates/news/post.twig b/templates/news/post.twig index 393fdfa5..b9b2fa13 100644 --- a/templates/news/post.twig +++ b/templates/news/post.twig @@ -36,22 +36,21 @@
Posted
-
- {# TODO: make this work - {% if post.updated_at is defined %} + {% if post.post_updated|date('U') > post.post_created|date('U') %}
Updated
-
- {{ post.updated_at }} -
+
- {% endif %} #} + {% endif %}