Clean up emoji model and sidebar. Fix some validation errors. Allow mood to be cleared.
This commit is contained in:
parent
3b8d54460c
commit
427558bd8c
@ -163,7 +163,7 @@ function create_tables(): void {
|
||||
)");
|
||||
|
||||
// mood table
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS mood (
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS emoji(
|
||||
id INTEGER PRIMARY KEY,
|
||||
emoji TEXT UNIQUE NOT NULL,
|
||||
description TEXT NOT NULL
|
||||
@ -185,7 +185,7 @@ function validate_tables(): void {
|
||||
$appTables[] = "settings";
|
||||
$appTables[] = "user";
|
||||
$appTables[] = "css";
|
||||
$appTables[] = "mood";
|
||||
$appTables[] = "emoji";
|
||||
|
||||
$db = get_db();
|
||||
|
||||
|
@ -77,6 +77,10 @@ fieldset.emoji-group {
|
||||
gap: 0.3em;
|
||||
}
|
||||
|
||||
h1.site-description {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.delete-emoji-fieldset .fieldset-items {
|
||||
display: block;
|
||||
grid-template-columns: none;
|
||||
@ -293,7 +297,7 @@ label.description {
|
||||
font-size: 1.0em;
|
||||
}
|
||||
|
||||
.pagination a {
|
||||
.tick-pagination a {
|
||||
margin: 0 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
73
src/Controller/EmojiController/EmojiController.php
Normal file
73
src/Controller/EmojiController/EmojiController.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
class EmojiController extends Controller {
|
||||
// Shows the custom emoji management page
|
||||
public function index(){
|
||||
global $config;
|
||||
$emojiList = EmojiModel::loadAll();
|
||||
|
||||
$vars = [
|
||||
'config' => $config,
|
||||
'emojiList' => $emojiList,
|
||||
];
|
||||
|
||||
$this->render("emoji.php", $vars);
|
||||
}
|
||||
|
||||
public function handlePost(): void {
|
||||
global $config;
|
||||
|
||||
switch ($_POST['action']) {
|
||||
case 'add':
|
||||
$emoji = trim($_POST['emoji']);
|
||||
$description = trim($_POST['emoji-description']);
|
||||
$this->handleAdd($emoji, $description);
|
||||
break;
|
||||
case 'delete':
|
||||
if (!empty($_POST['delete_emoji_ids'])){
|
||||
$this->handleDelete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
header('Location: ' . $config->basePath . 'admin/emoji');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function handleAdd(string $emoji, ?string $description=null): void {
|
||||
// Validate 1 visible character in the emoji
|
||||
if (extension_loaded('mbstring')) {
|
||||
// TODO - log a warning if mbstring isn't loaded
|
||||
$charCount = mb_strlen($emoji, 'UTF-8');
|
||||
if ($charCount !== 1) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the emoji is actually an emoji
|
||||
$emojiPattern = '/^[\x{1F000}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F1E0}-\x{1F1FF}\x{1F900}-\x{1F9FF}\x{1FA70}-\x{1FAFF}]$/u';
|
||||
|
||||
if (!preg_match($emojiPattern, $emoji)) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
|
||||
// emojis should have more bytes than characters
|
||||
$byteCount = strlen($emoji);
|
||||
if ($byteCount <= 1) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
|
||||
// It looks like an emoji. Let's add it.
|
||||
EmojiModel::add($emoji, $description);
|
||||
}
|
||||
|
||||
public function handleDelete(): void {
|
||||
$ids = $_POST['delete_emoji_ids'];
|
||||
|
||||
if (!empty($ids)) {
|
||||
EmojiModel::delete($ids);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,80 +15,8 @@
|
||||
$this->render("mood.php", $vars);
|
||||
}
|
||||
|
||||
// Shows the custom emoji management page
|
||||
public function showCustomEmoji(){
|
||||
global $config;
|
||||
$emojiList = MoodModel::loadAll();
|
||||
|
||||
$vars = [
|
||||
'config' => $config,
|
||||
'emojiList' => $emojiList,
|
||||
];
|
||||
|
||||
$this->render("emoji.php", $vars);
|
||||
}
|
||||
|
||||
public function handlePost(): void {
|
||||
global $config;
|
||||
|
||||
switch ($_POST['action']) {
|
||||
case 'add':
|
||||
$emoji = trim($_POST['emoji']);
|
||||
$description = trim($_POST['emoji-description']);
|
||||
$this->handleAdd($emoji, $description);
|
||||
break;
|
||||
case 'delete':
|
||||
if (!empty($_POST['delete_emoji_ids'])){
|
||||
$this->handleDelete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
header('Location: ' . $config->basePath . 'admin/emoji');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function handleAdd(string $emoji, ?string $description=null): void {
|
||||
// Validate 1 visible character in the emoji
|
||||
if (extension_loaded('mbstring')) {
|
||||
// TODO - log a warning if mbstring isn't loaded
|
||||
$charCount = mb_strlen($emoji, 'UTF-8');
|
||||
if ($charCount !== 1) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the emoji is actually an emoji
|
||||
$emojiPattern = '/^[\x{1F000}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F1E0}-\x{1F1FF}\x{1F900}-\x{1F9FF}\x{1FA70}-\x{1FAFF}]$/u';
|
||||
|
||||
if (!preg_match($emojiPattern, $emoji)) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
|
||||
// emojis should have more bytes than characters
|
||||
$byteCount = strlen($emoji);
|
||||
if ($byteCount <= 1) {
|
||||
// TODO - handle error
|
||||
return;
|
||||
}
|
||||
|
||||
// It looks like an emoji. Let's add it.
|
||||
MoodModel::add($emoji, $description);
|
||||
}
|
||||
|
||||
public function handleDelete(): void {
|
||||
$ids = $_POST['delete_emoji_ids'];
|
||||
|
||||
if (!empty($ids)) {
|
||||
$moodModel = new MoodModel();
|
||||
$moodModel->delete($ids);
|
||||
}
|
||||
}
|
||||
|
||||
public function handleSetMood(){
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' and isset($_POST['mood'])) {
|
||||
public function handlePost(){
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// ensure that the session is valid before proceeding
|
||||
if (!Session::validateCsrfToken($_POST['csrf_token'])) {
|
||||
die('Invalid CSRF token');
|
||||
@ -97,9 +25,17 @@
|
||||
// Get the data we need
|
||||
global $config;
|
||||
global $user;
|
||||
$mood = $_POST['mood'];
|
||||
|
||||
// set the mood
|
||||
switch ($_POST['action']){
|
||||
case 'set':
|
||||
$mood = $_POST['mood'];
|
||||
break;
|
||||
case 'clear':
|
||||
$mood = '';
|
||||
break;
|
||||
}
|
||||
|
||||
// set or clear the mood
|
||||
$user->mood = $mood;
|
||||
$user = $user->save();
|
||||
|
||||
@ -110,7 +46,7 @@
|
||||
}
|
||||
|
||||
private static function getEmojisWithLabels(): array {
|
||||
$customEmoji = MoodModel::loadAll();
|
||||
$customEmoji = EmojiModel::loadAll();
|
||||
|
||||
if (!empty($customEmoji)){
|
||||
$custom = [];
|
||||
|
@ -10,15 +10,15 @@ class Router {
|
||||
['admin', 'AdminController@handleSave', ['POST']],
|
||||
['admin/css', 'CssController'],
|
||||
['admin/css', 'CssController@handlePost', ['POST']],
|
||||
['admin/emoji', 'MoodController@showCustomEmoji'],
|
||||
['admin/emoji', 'MoodController@handlePost', ['POST']],
|
||||
['admin/emoji', 'EmojiController'],
|
||||
['admin/emoji', 'EmojiController@handlePost', ['POST']],
|
||||
['feed/rss', 'FeedController@rss'],
|
||||
['feed/atom', 'FeedController@atom'],
|
||||
['login', 'AuthController@showLogin'],
|
||||
['login', 'AuthController@handleLogin', ['POST']],
|
||||
['logout', 'AuthController@handleLogout', ['GET', 'POST']],
|
||||
['mood', 'MoodController'],
|
||||
['mood', 'MoodController@handleSetMood', ['POST']],
|
||||
['mood', 'MoodController@handlePost', ['POST']],
|
||||
['setup', 'AdminController@showSetup'],
|
||||
['setup', 'AdminController@handleSetup', ['POST']],
|
||||
['tick/{y}/{m}/{d}/{h}/{i}/{s}', 'TickController'],
|
||||
|
@ -1,12 +1,12 @@
|
||||
<?php
|
||||
// welp this model is overkill
|
||||
class MoodModel{
|
||||
class EmojiModel{
|
||||
// This isn't memory-efficient,
|
||||
// but I think it'll be fine on this app's scales.
|
||||
public static function loadAll(): array {
|
||||
global $db;
|
||||
|
||||
$stmt = $db->query("SELECT id, emoji, description FROM mood");
|
||||
$stmt = $db->query("SELECT id, emoji, description FROM emoji");
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ class MoodModel{
|
||||
public static function add(string $emoji, ?string $description): void{
|
||||
global $db;
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO mood (emoji, description) VALUES (?, ?)");
|
||||
$stmt = $db->prepare("INSERT INTO emoji (emoji, description) VALUES (?, ?)");
|
||||
$stmt->execute([$emoji, $description]);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ class MoodModel{
|
||||
global $db;
|
||||
|
||||
$placeholders = rtrim(str_repeat('?,', count($idsToDelete)), ',');
|
||||
$stmt = $db->prepare("DELETE FROM mood WHERE id IN ($placeholders)");
|
||||
$stmt = $db->prepare("DELETE FROM emoji WHERE id IN ($placeholders)");
|
||||
$stmt->execute($idsToDelete);
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ class HomeView {
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<section id="ticks" class="home-ticks">
|
||||
<div class="home-ticks-list">
|
||||
<main id="ticks" class="home-main">
|
||||
<div class="tick-feed">
|
||||
<?php foreach ($ticks as $tick): ?>
|
||||
<article class="tick">
|
||||
<div class="tick-time"><?= htmlspecialchars(Util::relative_time($tick['timestamp'])) ?></div>
|
||||
@ -13,7 +13,7 @@ class HomeView {
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="home-ticks-pagination">
|
||||
<div class="tick-pagination">
|
||||
<?php if ($page > 1): ?>
|
||||
<a href="?page=<?= $page - 1 ?>">« Newer</a>
|
||||
<?php endif; ?>
|
||||
@ -21,7 +21,7 @@ class HomeView {
|
||||
<a href="?page=<?= $page + 1 ?>">Older »</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
@ -33,7 +33,10 @@ class MoodView {
|
||||
<form method="post" class="emoji-form">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||
<?= $this->render_emoji_groups($emojiGroups, $currentMood) ?>
|
||||
<button type="submit">Set the mood</button>
|
||||
<div class="button-group">
|
||||
<button type="submit" name="action" value="set">Set the mood</button>
|
||||
<button type="submit" name="action" value="clear" class="clear-button">Clear mood</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
|
@ -14,8 +14,8 @@ echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
|
||||
<link rel="self"
|
||||
type="application/atom+xml"
|
||||
title="<?php echo htmlspecialchars($config->siteTitle) ?> Atom Feed"
|
||||
href="<?php echo htmlspecialchars($siteUrl . $basePath) ?>feed/atom" />
|
||||
<link rel="alternate" href="<?= $siteUrl ?>"/>
|
||||
href="<?php echo htmlspecialchars($siteUrl . $basePath) ?>feed/atom">
|
||||
<link rel="alternate" href="<?= $siteUrl ?>">
|
||||
<updated><?= $updated ?></updated>
|
||||
<id><?= $siteUrl ?></id>
|
||||
<author>
|
||||
|
@ -9,15 +9,15 @@ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
|
||||
?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>My tkr</title>
|
||||
<title><?php echo htmlspecialchars($config->siteTitle) ?> RSS Feed</title>
|
||||
<link rel="self"
|
||||
type="application/rss+xml"
|
||||
title="<?php echo htmlspecialchars($config->siteTitle) ?> RSS Feed"
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/rss/" />
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/rss/">
|
||||
<link rel="alternate"
|
||||
type="text/html"
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath) ?>" />
|
||||
<description>My tkr</description>
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath) ?>">
|
||||
<description><?php echo htmlspecialchars($config->siteDescription) ?></description>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate><?php echo date(DATE_RSS); ?></lastBuildDate>
|
||||
<?php foreach ($ticks as $tick):
|
||||
|
@ -17,11 +17,11 @@
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="<?php echo htmlspecialchars($config->siteTitle) ?> RSS Feed"
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/rss/" />
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/rss/">
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="<?php echo htmlspecialchars($config->siteTitle) ?> Atom Feed"
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/atom/" />
|
||||
href="<?php echo htmlspecialchars($config->baseUrl . $config->basePath)?>feed/atom/">
|
||||
</head>
|
||||
<body>
|
||||
<?php include TEMPLATES_DIR . '/partials/navbar.php'?>
|
||||
|
@ -5,10 +5,15 @@
|
||||
<div class="home-container">
|
||||
<section id="sidebar" class="home-sidebar">
|
||||
<div class="home-header">
|
||||
<h2 class="site-description"><?= $config->siteDescription ?></h2>
|
||||
<h1 class="site-description"><?= $config->siteDescription ?></h1>
|
||||
</div>
|
||||
<p><?= $user->about ?></p>
|
||||
<?php if (!empty($user->about)): ?>
|
||||
<p>About: <?= $user->about ?></p>
|
||||
<?php endif ?>
|
||||
<?php if (!empty($user->website)): ?>
|
||||
<p>Website: <?= Util::escape_and_linkify($user->website) ?></p>
|
||||
<?php endif ?>
|
||||
<?php if (!empty($user->mood) || Session::isLoggedIn()): ?>
|
||||
<div class="profile-row">
|
||||
<div class="mood-bar">
|
||||
<span>Current mood: <?= $user->mood ?></span>
|
||||
@ -17,6 +22,7 @@
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (Session::isLoggedIn()): ?>
|
||||
<hr/>
|
||||
<div class="profile-row">
|
||||
|
Loading…
x
Reference in New Issue
Block a user