Added post editing, closes #97.
This commit is contained in:
parent
3e4a8504ad
commit
e3d4d41a9a
7 changed files with 218 additions and 41 deletions
|
@ -46,6 +46,7 @@
|
|||
&__text {
|
||||
margin: 2px;
|
||||
line-height: 1.2em;
|
||||
flex: 1 1 auto;
|
||||
|
||||
@media (max-width: @site-mobile-width) {
|
||||
margin: 4px;
|
||||
|
@ -178,4 +179,31 @@
|
|||
&__parser {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
&__action {
|
||||
padding: 5px 10px;
|
||||
margin: 1px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: background-color .2s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background-color: #fff2;
|
||||
}
|
||||
}
|
||||
|
||||
&__signature {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
padding: 2px;
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
database/2018_12_30_025222_automatically_mark_edited.php
Normal file
20
database/2018_12_30_025222_automatically_mark_edited.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
namespace Misuzu\DatabaseMigrations\AutomaticallyMarkEdited;
|
||||
|
||||
use PDO;
|
||||
|
||||
function migrate_up(PDO $conn): void
|
||||
{
|
||||
$conn->exec("
|
||||
ALTER TABLE `msz_forum_posts`
|
||||
CHANGE COLUMN `post_edited` `post_edited` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP AFTER `post_created`;
|
||||
");
|
||||
}
|
||||
|
||||
function migrate_down(PDO $conn): void
|
||||
{
|
||||
$conn->exec("
|
||||
ALTER TABLE `msz_forum_posts`
|
||||
CHANGE COLUMN `post_edited` `post_edited` TIMESTAMP NULL DEFAULT NULL AFTER `post_created`;
|
||||
");
|
||||
}
|
|
@ -11,28 +11,35 @@ if (user_warning_check_restriction(user_session_current('user_id', 0))) {
|
|||
return;
|
||||
}
|
||||
|
||||
$forumPostingModes = [
|
||||
'create', 'edit', 'quote',
|
||||
'delete', 'restore', 'nuke',
|
||||
];
|
||||
|
||||
if (!empty($_POST)) {
|
||||
$mode = $_POST['post']['mode'] ?? 'create';
|
||||
$postId = max(0, (int)($_POST['post']['id'] ?? 0));
|
||||
$topicId = max(0, (int)($_POST['post']['topic'] ?? 0));
|
||||
$forumId = max(0, (int)($_POST['post']['forum'] ?? 0));
|
||||
} else {
|
||||
$mode = $_GET['m'] ?? 'create';
|
||||
$postId = max(0, (int)($_GET['p'] ?? 0));
|
||||
$topicId = max(0, (int)($_GET['t'] ?? 0));
|
||||
$forumId = max(0, (int)($_GET['f'] ?? 0));
|
||||
}
|
||||
|
||||
if (!in_array($mode, $forumPostingModes, true)) {
|
||||
echo render_error(400);
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($postId) && empty($topicId) && empty($forumId)) {
|
||||
echo render_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($postId)) {
|
||||
$getPost = db_prepare('
|
||||
SELECT `post_id`, `topic_id`
|
||||
FROM `msz_forum_posts`
|
||||
WHERE `post_id` = :post_id
|
||||
');
|
||||
$getPost->bindValue('post_id', $postId);
|
||||
$post = $getPost->execute() ? $getPost->fetch(PDO::FETCH_ASSOC) : false;
|
||||
$post = forum_post_get($postId);
|
||||
|
||||
if (isset($post['topic_id'])) { // should automatic cross-quoting be a thing? if so, check if $topicId is < 1 first
|
||||
$topicId = (int)$post['topic_id'];
|
||||
|
@ -68,7 +75,7 @@ if (empty($forum)) {
|
|||
return;
|
||||
}
|
||||
|
||||
$perms = forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $forum['forum_id'], user_session_current('user_id', 0));
|
||||
$perms = forum_perms_get_user(MSZ_FORUM_PERMS_GENERAL, $forum['forum_id'], user_session_current('user_id'));
|
||||
|
||||
if ($forum['forum_archived']
|
||||
|| !empty($topic['topic_locked'])
|
||||
|
@ -83,6 +90,19 @@ if (!forum_may_have_topics($forum['forum_type'])) {
|
|||
return;
|
||||
}
|
||||
|
||||
// edit mode stuff
|
||||
if ($mode === 'edit') {
|
||||
if (empty($post)) {
|
||||
echo render_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!perms_check($perms, $post['poster_id'] === user_session_current('user_id') ? MSZ_FORUM_PERM_EDIT_POST : MSZ_FORUM_PERM_EDIT_ANY_POST)) {
|
||||
echo render_error(403);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$notices = [];
|
||||
|
||||
if (!empty($_POST)) {
|
||||
|
@ -122,24 +142,36 @@ if (!empty($_POST)) {
|
|||
}
|
||||
|
||||
if (empty($notices)) {
|
||||
if (!empty($topic)) {
|
||||
forum_topic_bump($topic['topic_id']);
|
||||
} else {
|
||||
$topicId = forum_topic_create($forum['forum_id'], user_session_current('user_id', 0), $topicTitle);
|
||||
switch ($mode) {
|
||||
case 'create':
|
||||
if (!empty($topic)) {
|
||||
forum_topic_bump($topic['topic_id']);
|
||||
} else {
|
||||
$topicId = forum_topic_create($forum['forum_id'], user_session_current('user_id', 0), $topicTitle);
|
||||
}
|
||||
|
||||
$postId = forum_post_create(
|
||||
$topicId,
|
||||
$forum['forum_id'],
|
||||
user_session_current('user_id', 0),
|
||||
ip_remote_address(),
|
||||
$postText,
|
||||
$postParser
|
||||
);
|
||||
forum_topic_mark_read(user_session_current('user_id', 0), $topicId, $forum['forum_id']);
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
if (!forum_post_edit($postId, ip_remote_address(), $postText, $postParser)) {
|
||||
$notices[] = 'Post edit failed.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$postId = forum_post_create(
|
||||
$topicId,
|
||||
$forum['forum_id'],
|
||||
user_session_current('user_id', 0),
|
||||
ip_remote_address(),
|
||||
$postText,
|
||||
$postParser
|
||||
);
|
||||
forum_topic_mark_read(user_session_current('user_id', 0), $topicId, $forum['forum_id']);
|
||||
|
||||
header("Location: /forum/topic.php?p={$postId}#p{$postId}");
|
||||
return;
|
||||
if (empty($notices)) {
|
||||
header("Location: /forum/topic.php?p={$postId}#p{$postId}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +180,10 @@ if (!empty($topic)) {
|
|||
tpl_var('posting_topic', $topic);
|
||||
}
|
||||
|
||||
if ($mode === 'edit') { // $post is pretty much sure to be populated at this point
|
||||
tpl_var('posting_post', $post);
|
||||
}
|
||||
|
||||
// fetches additional data for simulating a forum post
|
||||
$getDisplayInfo = db_prepare('
|
||||
SELECT u.`user_country`, u.`user_created`, (
|
||||
|
@ -167,4 +203,5 @@ echo tpl_render('forum.posting', [
|
|||
'posting_forum' => $forum,
|
||||
'posting_info' => $displayInfo,
|
||||
'posting_notices' => $notices,
|
||||
'posting_mode' => $mode,
|
||||
]);
|
||||
|
|
|
@ -23,6 +23,31 @@ function forum_post_create(
|
|||
return $createPost->execute() ? db_last_insert_id() : 0;
|
||||
}
|
||||
|
||||
function forum_post_edit(
|
||||
int $postId,
|
||||
string $ipAddress,
|
||||
string $text,
|
||||
int $parser = MSZ_PARSER_PLAIN
|
||||
): bool {
|
||||
if ($postId < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updatePost = db_prepare('
|
||||
UPDATE `msz_forum_posts`
|
||||
SET `post_ip` = INET6_ATON(:post_ip),
|
||||
`post_text` = :post_text,
|
||||
`post_parse` = :post_parse
|
||||
WHERE `post_id` = :post_id
|
||||
');
|
||||
$updatePost->bindValue('post_id', $postId);
|
||||
$updatePost->bindValue('post_ip', $ipAddress);
|
||||
$updatePost->bindValue('post_text', $text);
|
||||
$updatePost->bindValue('post_parse', $parser);
|
||||
|
||||
return $updatePost->execute();
|
||||
}
|
||||
|
||||
function forum_post_find(int $postId): array
|
||||
{
|
||||
$getPostInfo = db_prepare('
|
||||
|
@ -43,7 +68,42 @@ function forum_post_find(int $postId): array
|
|||
');
|
||||
$getPostInfo->bindValue('post_id', $postId);
|
||||
|
||||
return $getPostInfo->execute() ? $getPostInfo->fetch() : [];
|
||||
return $getPostInfo->execute() ? $getPostInfo->fetch(PDO::FETCH_ASSOC) : [];
|
||||
}
|
||||
|
||||
function forum_post_get(int $postId, bool $allowDeleted = false): array
|
||||
{
|
||||
$getPost = db_prepare(sprintf(
|
||||
'
|
||||
SELECT
|
||||
p.`post_id`, p.`post_text`, p.`post_created`, p.`post_parse`,
|
||||
p.`topic_id`, p.`post_deleted`, p.`post_edited`,
|
||||
INET6_NTOA(p.`post_ip`) as `post_ip`,
|
||||
u.`user_id` as `poster_id`,
|
||||
u.`username` as `poster_name`,
|
||||
u.`user_created` as `poster_joined`,
|
||||
u.`user_country` as `poster_country`,
|
||||
COALESCE(u.`user_colour`, r.`role_colour`) as `poster_colour`,
|
||||
(
|
||||
SELECT COUNT(`post_id`)
|
||||
FROM `msz_forum_posts`
|
||||
WHERE `user_id` = p.`user_id`
|
||||
AND `post_deleted` IS NULL
|
||||
) as `poster_post_count`
|
||||
FROM `msz_forum_posts` as p
|
||||
LEFT JOIN `msz_users` as u
|
||||
ON u.`user_id` = p.`user_id`
|
||||
LEFT JOIN `msz_roles` as r
|
||||
ON r.`role_id` = u.`display_role`
|
||||
WHERE `post_id` = :post_id
|
||||
%1$s
|
||||
ORDER BY `post_id`
|
||||
',
|
||||
$allowDeleted ? '' : 'AND `post_deleted` IS NULL'
|
||||
));
|
||||
$getPost->bindValue('post_id', $postId);
|
||||
$post = $getPost->execute() ? $getPost->fetch(PDO::FETCH_ASSOC) : false;
|
||||
return $post ? $post : [];
|
||||
}
|
||||
|
||||
function forum_post_listing(int $topicId, int $offset = 0, int $take = 0, bool $showDeleted = false): array
|
||||
|
@ -86,5 +146,5 @@ function forum_post_listing(int $topicId, int $offset = 0, int $take = 0, bool $
|
|||
$getPosts->bindValue('take', $take);
|
||||
}
|
||||
|
||||
return $getPosts->execute() ? $getPosts->fetchAll() : [];
|
||||
return $getPosts->execute() ? $getPosts->fetchAll(PDO::FETCH_ASSOC) : [];
|
||||
}
|
||||
|
|
|
@ -321,19 +321,24 @@
|
|||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro forum_post_listing(posts, opening_post_id) %}
|
||||
{% macro forum_post_listing(posts, opening_post_id, user_id, perms) %}
|
||||
{% from _self import forum_post_entry %}
|
||||
|
||||
{% for post in posts %}
|
||||
{{ forum_post_entry(post, post.post_id == opening_post_id) }}
|
||||
{{ forum_post_entry(
|
||||
post,
|
||||
post.post_id == opening_post_id,
|
||||
perms|perms_check(constant('MSZ_FORUM_PERM_CREATE_POST')),
|
||||
perms|perms_check(constant(user_id == post.poster_id ? 'MSZ_FORUM_PERM_EDIT_POST' : 'MSZ_FORUM_PERM_EDIT_ANY_POST')),
|
||||
perms|perms_check(constant(user_id == post.poster_id ? 'MSZ_FORUM_PERM_DELETE_POST' : 'MSZ_FORUM_PERM_DELETE_ANY_POST'))
|
||||
) }}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro forum_post_entry(post, is_original_post, is_original_poster) %}
|
||||
{% set is_original_post = is_original_post|default(false) %}
|
||||
{% set is_original_poster = is_original_poster|default(false) %}
|
||||
{% macro forum_post_entry(post, is_original_post, can_post, can_edit, can_delete) %}
|
||||
{% set is_deleted = post.post_deleted is not null %}
|
||||
|
||||
<div class="container forum__post{% if post.post_deleted is not null %} forum__post--deleted{% endif %}" id="p{{ post.post_id }}" style="{{ post.poster_colour|html_colour('--accent-colour') }}">
|
||||
<div class="container forum__post{% if is_deleted %} forum__post--deleted{% endif %}" id="p{{ post.post_id }}" style="{{ post.poster_colour|html_colour('--accent-colour') }}">
|
||||
<div class="forum__post__info">
|
||||
<div class="forum__post__info__background"></div>
|
||||
<div class="forum__post__info__content">
|
||||
|
@ -363,6 +368,9 @@
|
|||
<div class="forum__post__details">
|
||||
<a class="forum__post__datetime" href="/forum/topic.php?t={{ post.topic_id }}#p{{ post.post_id }}">
|
||||
<time datetime="{{ post.post_created|date('c') }}" title="{{ post.post_created|date('r') }}">{{ post.post_created|time_diff }}</time>
|
||||
{% if post.post_edited is not null %}
|
||||
(edited <time datetime="{{ post.post_edited|date('c') }}" title="{{ post.post_edited|date('r') }}">{{ post.post_edited|time_diff }}</time>)
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
<a class="forum__post__id" href="/forum/topic.php?p={{ post.post_id }}#p{{ post.post_id }}">
|
||||
|
@ -373,6 +381,25 @@
|
|||
<div class="forum__post__text{% if post.post_parse == constant('MSZ_PARSER_MARKDOWN') %} markdown{% endif %}">
|
||||
{{ post.post_text|escape|parse_text(post.post_parse)|raw }}
|
||||
</div>
|
||||
|
||||
{% if can_post or can_edit or can_delete %}
|
||||
<div class="forum__post__actions">
|
||||
{% if is_deleted %}
|
||||
<a href="/forum/posting.php?p={{ post.post_id }}&m=restore" class="forum__post__action"><i class="fas fa-magic fa-fw"></i> Restore</a>
|
||||
<a href="/forum/posting.php?p={{ post.post_id }}&m=nuke" class="forum__post__action"><i class="fas fa-radiation-alt fa-fw"></i> Permanently Delete</a>
|
||||
{% else %}
|
||||
{# if can_post %}
|
||||
<a href="/forum/posting.php?p={{ post.post_id }}&m=quote" class="forum__post__action"><i class="fas fa-quote-left fa-fw"></i> Quote</a>
|
||||
{% endif #}
|
||||
{% if can_edit %}
|
||||
<a href="/forum/posting.php?p={{ post.post_id }}&m=edit" class="forum__post__action"><i class="fas fa-edit fa-fw"></i> Edit</a>
|
||||
{% endif %}
|
||||
{# if can_delete %}
|
||||
<a href="/forum/posting.php?p={{ post.post_id }}&m=delete" class="forum__post__action"><i class="far fa-trash-alt fa-fw"></i> Delete</a>
|
||||
{% endif #}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
|
|
@ -8,9 +8,14 @@
|
|||
{% block content %}
|
||||
<form method="post" action="/forum/posting.php">
|
||||
{{ input_hidden('post[' ~ (is_reply ? 'topic' : 'forum') ~ ']', is_reply ? posting_topic.topic_id : posting_forum.forum_id) }}
|
||||
{{ input_hidden('post[mode]', posting_mode) }}
|
||||
{{ input_csrf('forum_post') }}
|
||||
{{ forum_header(is_reply ? posting_topic.topic_title : input_text('post[title]', 'forum__header__input', '', 'text', 'Enter your title here...'), posting_breadcrumbs) }}
|
||||
|
||||
{% if posting_post is defined %}
|
||||
{{ input_hidden('post[id]', posting_post.post_id) }}
|
||||
{% endif %}
|
||||
|
||||
{% if posting_notices|length > 0 %}
|
||||
<div class="warning">
|
||||
<div class="warning__content">
|
||||
|
@ -21,31 +26,31 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="container forum__post" style="{{ current_user.user_colour|html_colour('--accent-colour') }}">
|
||||
<div class="container forum__post" style="{{ posting_post.poster_colour|default(current_user.user_colour)|html_colour('--accent-colour') }}">
|
||||
<div class="forum__post__info">
|
||||
<div class="forum__post__info__background"></div>
|
||||
<div class="forum__post__info__content">
|
||||
<span class="avatar forum__post__avatar" style="background-image:url('/profile.php?u={{ current_user.user_id }}&m=avatar');"></span>
|
||||
<span class="avatar forum__post__avatar" style="background-image:url('/profile.php?u={{ posting_post.poster_id|default(current_user.user_id) }}&m=avatar');"></span>
|
||||
|
||||
<span class="forum__post__username">{{ current_user.username }}</span>
|
||||
<span class="forum__post__username">{{ posting_post.poster_name|default(current_user.username) }}</span>
|
||||
|
||||
<div class="forum__post__icons">
|
||||
<div class="flag flag--{{ posting_info.user_country|lower }}" title="{{ posting_info.user_country|country_name }}"></div>
|
||||
<div class="forum__post__posts-count">{{ posting_info.user_forum_posts|number_format }} posts</div>
|
||||
<div class="flag flag--{{ posting_post.poster_country|default(posting_info.user_country)|lower }}" title="{{ posting_post.poster_country|default(posting_info.user_country)|country_name }}"></div>
|
||||
<div class="forum__post__posts-count">{{ posting_post.poster_post_count|default(posting_info.user_forum_posts)|number_format }} posts</div>
|
||||
</div>
|
||||
|
||||
<div class="forum__post__joined">
|
||||
joined <time datetime="{{ posting_info.user_created|date('c') }}" title="{{ posting_info.user_created|date('r') }}">{{ posting_info.user_created|time_diff }}</time>
|
||||
joined <time datetime="{{ posting_post.poster_joined|default(posting_info.user_created)|date('c') }}" title="{{ posting_post.poster_joined|default(posting_info.user_created)|date('r') }}">{{ posting_post.poster_joined|default(posting_info.user_created)|time_diff }}</time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="forum__post__content">
|
||||
<textarea name="post[text]" class="forum__post__text forum__post__text--edit" placeholder="Type your post content here..."></textarea>
|
||||
<textarea name="post[text]" class="forum__post__text forum__post__text--edit" placeholder="Type your post content here...">{{ posting_post.post_text|default('') }}</textarea>
|
||||
|
||||
<div class="forum__post__options">
|
||||
<div class="forum__post__settings">
|
||||
{{ input_select('post[parser]', constant('MSZ_PARSERS_NAMES'), constant('MSZ_PARSER_BBCODE'), null, null, null, 'forum__post__parser') }}
|
||||
{{ input_select('post[parser]', constant('MSZ_PARSERS_NAMES'), posting_post.post_parse|default(constant('MSZ_PARSER_BBCODE')), null, null, null, 'forum__post__parser') }}
|
||||
</div>
|
||||
|
||||
<div class="forum__post__buttons">
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
{{ forum_header(topic_info.topic_title, topic_breadcrumbs) }}
|
||||
{{ forum_topic_locked(topic_info.topic_locked, topic_info.topic_archived) }}
|
||||
{{ topic_tools }}
|
||||
{{ forum_post_listing(topic_posts, topic_info.topic_first_post_id) }}
|
||||
{{ forum_post_listing(topic_posts, topic_info.topic_first_post_id, current_user.user_id, topic_perms) }}
|
||||
{{ topic_tools }}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue