Remove dormant checks and add @ mentions to comments.

This commit is contained in:
flash 2018-08-17 03:39:44 +02:00
parent 160856607d
commit 757362102f
5 changed files with 70 additions and 18 deletions

View file

@ -13,9 +13,7 @@ $usernameValidationErrors = [
'trim' => 'Your username may not start or end with spaces!',
'short' => sprintf('Your username is too short, it has to be at least %d characters!', MSZ_USERNAME_MIN_LENGTH),
'long' => sprintf("Your username is too long, it can't be longer than %d characters!", MSZ_USERNAME_MAX_LENGTH),
'double-spaces' => "Your username can't contain double spaces.",
'invalid' => 'Your username contains invalid characters.',
'spacing' => 'Please use either underscores or spaces, not both!',
'in-use' => 'This username is already taken!',
];

View file

@ -48,6 +48,20 @@ function user_password_hash(string $password): string
return password_hash($password, MSZ_USERS_PASSWORD_HASH_ALGO);
}
function user_id_from_username(string $username): int
{
$getId = Database::prepare('SELECT `user_id` FROM `msz_users` WHERE LOWER(`username`) = LOWER(:username)');
$getId->bindValue('username', $username);
return $getId->execute() ? (int)$getId->fetchColumn() : 0;
}
function user_username_from_id(int $userId): string
{
$getId = Database::prepare('SELECT `username` FROM `msz_users` WHERE `user_id` = :user_id');
$getId->bindValue('user_id', $userId);
return $getId->execute() ? (string)$getId->fetchColumn() : 'deleted';
}
define('MSZ_USER_AVATAR_FORMAT', '%d.msz');
function user_avatar_delete(int $userId): void

View file

@ -8,7 +8,8 @@ define('MSZ_USERNAME_MIN_LENGTH', 3);
define('MSZ_USERNAME_MAX_LENGTH', 16);
// Username character constraint.
define('MSZ_USERNAME_REGEX', '#^[A-Za-z0-9-_]+$#u');
define('MSZ_USERNAME_REGEX', '[A-Za-z0-9-_]+');
define('MSZ_USERNAME_REGEX_FULL', '#^' . MSZ_USERNAME_REGEX . '$#u');
// Minimum entropy value for passwords.
define('MSZ_PASSWORD_MIN_ENTROPY', 32);
@ -29,18 +30,10 @@ function user_validate_username(string $username, bool $checkInUse = false): str
return 'long';
}
if (strpos($username, ' ') !== false) {
return 'double-spaces';
}
if (!preg_match(MSZ_USERNAME_REGEX, $username)) {
if (!preg_match(MSZ_USERNAME_REGEX_FULL, $username)) {
return 'invalid';
}
if (strpos($username, '_') !== false && strpos($username, ' ') !== false) {
return 'spacing';
}
if ($checkInUse) {
$getUser = Database::prepare('
SELECT COUNT(`user_id`)

View file

@ -1,6 +1,8 @@
<?php
use Misuzu\Database;
require_once __DIR__ . '/Users/validation.php';
define('MSZ_COMMENTS_PERM_CREATE', 1);
define('MSZ_COMMENTS_PERM_EDIT_OWN', 1 << 1);
define('MSZ_COMMENTS_PERM_EDIT_ANY', 1 << 2);
@ -19,6 +21,28 @@ define('MSZ_COMMENTS_VOTE_TYPES', [
-1 => MSZ_COMMENTS_VOTE_DISLIKE,
]);
// gets parsed on post
define('MSZ_COMMENTS_MARKUP_USERNAME', '#\B(?:@{1}(' . MSZ_USERNAME_REGEX . '))#u');
// gets parsed on fetch
define('MSZ_COMMENTS_MARKUP_USER_ID', '#\B(?:@{2}([0-9]+))#u');
function comments_parse_for_store(string $text): string
{
return preg_replace_callback(MSZ_COMMENTS_MARKUP_USERNAME, function ($matches) {
return ($userId = user_id_from_username($matches[1])) < 1
? $matches[0]
: "@@{$userId}";
}, $text);
}
function comments_parse_for_display(string $text): string
{
return preg_replace_callback(MSZ_COMMENTS_MARKUP_USER_ID, function ($matches) {
return '<a href="/profile.php?u=' . $matches[1] . '">@' . user_username_from_id($matches[1]) . '</a>';
}, $text);
}
// usually this is not how you're suppose to handle permission checking,
// but in the context of comments this is fine since the same shit is used
// for every comment section.
@ -202,14 +226,25 @@ function comments_category_get(int $category, int $user, ?int $parent = null): a
$commentsCount = count($comments);
for ($i = 0; $i < $commentsCount; $i++) {
$comments[$i]['comment_html'] = nl2br(comments_parse_for_display(htmlentities($comments[$i]['comment_text'])));
$comments[$i]['comment_replies'] = comments_category_get($category, $user, $comments[$i]['comment_id']);
}
return $comments;
}
function comments_post_create(int $user, int $category, string $text, bool $pinned = false, ?int $reply = null): int
{
function comments_post_create(
int $user,
int $category,
string $text,
bool $pinned = false,
?int $reply = null,
bool $parse = true
): int {
if ($parse) {
$text = comments_parse_for_store($text);
}
$create = Database::prepare('
INSERT INTO `msz_comments_posts`
(`user_id`, `category_id`, `comment_text`, `comment_pinned`, `comment_reply_to`)
@ -236,7 +271,7 @@ function comments_post_delete(int $commentId, bool $delete = true): bool
return $deleteComment->execute();
}
function comments_post_get(int $commentId): array
function comments_post_get(int $commentId, bool $parse = true): array
{
$fetch = Database::prepare('
SELECT
@ -253,7 +288,14 @@ function comments_post_get(int $commentId): array
WHERE `comment_id` = :id
');
$fetch->bindValue('id', $commentId);
return $fetch->execute() ? $fetch->fetch(PDO::FETCH_ASSOC) : [];
$comment = $fetch->execute() ? $fetch->fetch(PDO::FETCH_ASSOC) : false;
$comment = $comment ? $comment : []; // prevent type errors
if ($comment && $parse) {
$comment['comment_html'] = nl2br(comments_parse_for_display(htmlentities($comment['comment_text'])));
}
return $comment;
}
function comments_post_exists(int $commentId): bool

View file

@ -80,7 +80,7 @@
{% endif %}
</div>
<div class="comment__text{{ comment.comment_deleted is null ? '' : ' comment__text--deleted' }}">
{{ comment.comment_deleted is null ? comment.comment_text|nl2br : 'deleted' }}
{{ comment.comment_deleted is null ? (comment.comment_html is defined ? comment.comment_html|raw : comment.comment_text|nl2br) : 'deleted' }}
</div>
{% if comment.comment_deleted is null and user is not null %}
<div class="comment__actions">
@ -347,7 +347,12 @@
var commentText = document.createElement('div');
commentText.className = 'comment__text';
commentText.textContent = comment.comment_text;
if (comment.comment_html)
commentText.innerHTML = comment.comment_html;
else
commentText.textContent = comment.comment_text;
commentContent.appendChild(commentText);
var commentActions = document.createElement('div');