From f00e97d2943c34d569c8fdbc5249ce19d6187987 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Tue, 9 Jan 2024 22:30:03 +0100 Subject: [PATCH 01/12] fix: fix problem with URL parsing --- www/router.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/www/router.php b/www/router.php index 4f2f0d8..e65719b 100644 --- a/www/router.php +++ b/www/router.php @@ -202,7 +202,7 @@ function generate_website($SURI) { header('Etag: W/"' . $SURI . '/' . strtotime($feed['feed_ts']) . '"'); echo $feed['feed']; - } elseif(preg_match('/^\s*image/', $_SERVER['HTTP_ACCEPT'])) { + } elseif(!preg_match('/^\s*text\/html/', $_SERVER['HTTP_ACCEPT'])) { header('Location: /raw' . $SURI); exit(0); } elseif(true) { @@ -210,8 +210,9 @@ function generate_website($SURI) { } } -generate_website($_SERVER['REQUEST_URI']); +$URL_PATH = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); +generate_website($URL_PATH); -log_and_die($_SERVER['REQUEST_URI']); +log_and_die($URL_PATH); ?> From d39595d57780724f82ba6a7b3b54b63b781a74d1 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 11 Jan 2024 10:37:19 +0100 Subject: [PATCH 02/12] feat: :sparkles: make the website load for different subdomains --- docker_dev/mysql_schema.sql | 11 ++++-- www/mysql_adapter.php | 76 ++++++++++++++++++++----------------- www/post_adapter.php | 32 ++++++++-------- www/router.php | 15 +++++++- 4 files changed, 80 insertions(+), 54 deletions(-) diff --git a/docker_dev/mysql_schema.sql b/docker_dev/mysql_schema.sql index 869935a..baf0a58 100644 --- a/docker_dev/mysql_schema.sql +++ b/docker_dev/mysql_schema.sql @@ -6,6 +6,7 @@ USE dragon_fire; CREATE TABLE posts ( post_id INTEGER AUTO_INCREMENT, + host VARCHAR(64) NOT NULL, post_path VARCHAR(255) NOT NULL, post_path_depth INTEGER NOT NULL DEFAULT 0, @@ -20,9 +21,9 @@ CREATE TABLE posts ( post_content MEDIUMTEXT, PRIMARY KEY(post_id), - CONSTRAINT unique_post_path UNIQUE (post_path), + CONSTRAINT unique_post UNIQUE (host, post_path), - INDEX(post_path), + INDEX(host, post_path), INDEX(post_path_depth, post_path), INDEX(post_create_time), INDEX(post_update_time) @@ -30,6 +31,7 @@ CREATE TABLE posts ( CREATE TABLE path_access_counts ( access_time DATETIME NOT NULL, + host VARCHAR(64) NOT NULL, post_path VARCHAR(255), agent VARCHAR(255), referrer VARCHAR(255), @@ -37,10 +39,11 @@ CREATE TABLE path_access_counts ( path_access_count INTEGER DEFAULT 0, path_processing_time DOUBLE PRECISION DEFAULT 0, - PRIMARY KEY(access_time, post_path, agent, referrer) + PRIMARY KEY(access_time, host, post_path, agent, referrer) ); CREATE TABLE feed_cache ( + host VARCHAR(64) NOT NULL, search_path VARCHAR(255), export_type VARCHAR(255), @@ -48,7 +51,7 @@ CREATE TABLE feed_cache ( feed_content MEDIUMTEXT, - PRIMARY KEY(search_path, export_type) + PRIMARY KEY(host, search_path, export_type) ); INSERT INTO posts (post_path, post_path_depth, post_metadata, post_content) diff --git a/www/mysql_adapter.php b/www/mysql_adapter.php index e9bdb5d..6fc3e58 100644 --- a/www/mysql_adapter.php +++ b/www/mysql_adapter.php @@ -3,8 +3,10 @@ class MySQLAdapter { public $raw; - function __construct() { - $db_params = json_decode(file_get_contents('secrets/db.json'), true); + function __construct($SITE_CONFIG) { + $this->SITE_CONFIG = $SITE_CONFIG; + + $db_params = $SITE_CONFIG['db']; try { if(false !== getenv('MYSQL_HOST')) { @@ -14,18 +16,16 @@ class MySQLAdapter { getenv('MYSQL_PORT')); } else { - $this->raw = mysqli_connect($db_params['MYSQL_HOST'], - $db_params['MYSQL_USER'], $db_params['MYSQL_PASSWORD'], - $db_params['MYSQL_DATABASE'], - $db_params['MYSQL_PORT']); + $this->raw = mysqli_connect($db_params['host'], + $db_params['user'], $db_params['password'], + $db_params['database'], + $db_params['port']); } } catch (\Throwable $th) { echo 'Connection failed
'; echo 'Error number: ' . mysqli_connect_errno() . '
'; echo 'Error message: ' . mysqli_connect_error() . '
'; die(); - - //throw $th; } } @@ -79,12 +79,13 @@ class MySQLAdapter { $qry = " INSERT INTO posts - (post_path, post_path_depth, post_metadata, post_content) + (host, post_path, post_path_depth, post_metadata, post_content) VALUES - ( ?, ?, ?, ?) AS new + ( ?, ?, ?, ?, ?) AS new ON DUPLICATE KEY UPDATE post_path=new.post_path;"; - $this->_exec($qry, "siss", + $this->_exec($qry, "ssiss", + $this->SITE_CONFIG['HTTP_HOST'], $post_path, $path_depth, json_encode($post_metadata), @@ -110,27 +111,28 @@ class MySQLAdapter { $qry = "INSERT INTO path_access_counts (access_time, - post_path, agent, referrer, + host, post_path, agent, referrer, path_access_count, path_processing_time) VALUES ( from_unixtime(floor(unix_timestamp(CURRENT_TIMESTAMP) / 300)*300), - ?, ?, ?, 1, ? + ?, ?, ?, ?, 1, ? ) AS new ON DUPLICATE KEY UPDATE path_access_count=path_access_counts.path_access_count+1, path_processing_time=path_access_counts.path_processing_time+new.path_processing_time; "; - $this->_exec($qry, "sssd", $post_path, $agent, $referrer, $time); + $this->_exec($qry, "ssssd", $this->SITE_CONFIG['HTTP_HOST'], $post_path, $agent, $referrer, $time); if(preg_match('/^user/', $agent)) { - $this->_exec("UPDATE posts SET post_access_count=post_access_count+1 WHERE post_path=?", "s", $post_path); + $this->_exec("UPDATE posts SET post_access_count=post_access_count+1 WHERE post_path=? AND host=?", "ss", + $post_path, $this->SITE_CONFIG['HTTP_HOST']); } } function get_post_access_counters() { $qry = " - SELECT post_path, agent, path_access_count, path_processing_time + SELECT host, post_path, agent, path_access_count, path_processing_time FROM path_access_counts WHERE path_last_access_time > ( CURRENT_TIMESTAMP - INTERVAL 10 MINUTE ); "; @@ -157,7 +159,7 @@ class MySQLAdapter { function get_post_access_counters_line() { $qry = " - SELECT access_time, post_path, agent, referrer, path_access_count, path_processing_time + SELECT host, access_time, post_path, agent, referrer, path_access_count, path_processing_time FROM path_access_counts WHERE access_time < ( CURRENT_TIMESTAMP - INTERVAL 6 MINUTE ) ORDER BY access_time DESC; @@ -169,7 +171,7 @@ class MySQLAdapter { try { $data = $this->_exec($qry, "")->fetch_all(MYSQLI_ASSOC); - $data_prefix="access_metrics,host=" . $_SERVER['SERVER_NAME']; + $data_prefix="access_metrics"; $out_data = ""; @@ -180,7 +182,8 @@ class MySQLAdapter { if($path == '') { $path = '/'; } - $out_data .= $data_prefix . ",agent=".$post_data['agent'].",path=".$path.",referrer=".$post_data['referrer']; + $out_data .= $data_prefix . ",host=" . $post_data['host'] . ",agent=".$post_data['agent']; + $out_data .= ",path=".$path.",referrer=".$post_data['referrer']; $out_data .= " access_sum=" . $post_data['path_access_count'] . ",time_sum=" . $post_data['path_processing_time']; $out_data .= " " . strtotime($post_data['access_time']) . "000000000\n"; @@ -205,8 +208,8 @@ class MySQLAdapter { $this->_exec(" UPDATE posts SET post_settings_cache=NULL - WHERE post_path LIKE ?; - ", "s", $post_path . "%"); + WHERE host = ? AND post_path LIKE ?; + ", "ss", $this->SITE_CONFIG['HTTP_HOST'], $post_path . "%"); } function update_or_create_post($post_path, $post_metadata, $post_content) { @@ -219,15 +222,16 @@ class MySQLAdapter { $qry = " INSERT INTO posts - (post_path, post_path_depth, post_metadata, post_content) + (host, post_path, post_path_depth, post_metadata, post_content) VALUES - ( ?, ?, ?, ?) AS new + ( ?, ?, ?, ?, ?) AS new ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content, post_update_time=CURRENT_TIMESTAMP;"; - $this->_exec($qry, "siss", + $this->_exec($qry, "ssiss", + $this->SITE_CONFIG['HTTP_HOST'], $post_path, $path_depth, json_encode($post_metadata), @@ -240,8 +244,8 @@ class MySQLAdapter { $post_settings = $this->_exec(" SELECT post_path, post_settings_cache FROM posts - WHERE post_path = ? - ", "s", $post_path)->fetch_assoc(); + WHERE post_path = ? AND host = ? + ", "ss", $post_path, $this->SITE_CONFIG['HTTP_HOST'])->fetch_assoc(); if(!isset($post_settings)) { return []; @@ -259,8 +263,8 @@ class MySQLAdapter { $post_metadata = $this->_exec(" SELECT post_path, post_metadata FROM posts - WHERE post_path = ? - ", "s", $post_path)->fetch_assoc(); + WHERE post_path = ? AND host = ? + ", "ss", $post_path, $this->SITE_CONFIG['HTTP_HOST'])->fetch_assoc(); if(isset($post_metadata['post_metadata'])) { $post_metadata = json_decode($post_metadata['post_metadata'], true); @@ -282,12 +286,13 @@ class MySQLAdapter { $with_subposts = false, $with_settings = true) { $qry = "SELECT * - FROM posts WHERE post_path = ? + FROM posts + WHERE post_path = ? AND host = ? "; $post_path = $this->_sanitize_path($post_path); - $post_data = $this->_exec($qry, "s", $post_path)->fetch_assoc(); + $post_data = $this->_exec($qry, "ss", $post_path, $this->SITE_CONFIG['HTTP_HOST'])->fetch_assoc(); if(!isset($post_data)) { $post_data = ['found' => false]; @@ -319,12 +324,15 @@ class MySQLAdapter { $qry = "SELECT post_path, post_metadata, post_update_time FROM posts - WHERE (post_path LIKE CONCAT(?,'/%')) + WHERE + host = ? + AND (post_path LIKE CONCAT(?,'/%')) AND post_path_depth = ? - ORDER BY post_create_time DESC - LIMIT 10"; + ORDER BY post_path ASC + LIMIT 50"; - $post_data = $this->_exec($qry, "si", $path, $path_depth+1)->fetch_all(MYSQLI_ASSOC); + $post_data = $this->_exec($qry, "ssi", $this->SITE_CONFIG['HTTP_HOST'], + $path, $path_depth+1)->fetch_all(MYSQLI_ASSOC); $fn = function($data) { return $this->_normalize_post_data($data); diff --git a/www/post_adapter.php b/www/post_adapter.php index fc0297e..0e96552 100644 --- a/www/post_adapter.php +++ b/www/post_adapter.php @@ -8,10 +8,10 @@ use Laminas\Feed\Writer\Feed; class PostHandler extends MySQLAdapter { public $data_directory; - function __construct() { - parent::__construct(); + function __construct($SITE_CONFIG) { + parent::__construct($SITE_CONFIG); - $this->data_directory = 'raw'; + $this->data_directory = 'raw/' . $this->SITE_CONFIG['HTTP_HOST']; } function _normalize_post_data($post_data) { @@ -130,7 +130,8 @@ class PostHandler extends MySQLAdapter { function try_get_cached_feed($path, $export_opt) { $post_cache = $this->_exec("SELECT feed_content, feed_created_on FROM feed_cache - WHERE search_path=? AND export_type=?", "ss", $path, $export_opt)->fetch_assoc(); + WHERE host=? AND search_path=? AND export_type=?", + "sss", $this->SITE_CONFIG['HTTP_HOST'], $path, $export_opt)->fetch_assoc(); if(!isset($post_cache)) { return null; @@ -145,12 +146,12 @@ class PostHandler extends MySQLAdapter { $feed = @new Feed; $feed->setTitle("DergFeed"); - $feed->setLink("https://lucidragons.de" . $path); - $feed->setFeedLink("https://lucidragons.de/feeds/atom" . $path, "atom"); + $feed->setLink($this->SITE_CONFIG['uri_prefix'] . $path); + $feed->setFeedLink($this->SITE_CONFIG['uri_prefix'] . "/feeds/atom" . $path, "atom"); $feed->setDateModified(time()); - $feed->setDescription("DergenFeed for all your " . $path . " needs <3"); + $feed->setDescription("DergenFeed for all your " . $path . " needs"); $feed_posts = $this->_exec("SELECT post_path, @@ -158,9 +159,9 @@ class PostHandler extends MySQLAdapter { post_content, post_metadata FROM posts - WHERE (post_path = ?) OR (post_path LIKE ?) + WHERE (host = ?) AND ((post_path = ?) OR (post_path LIKE ?)) ORDER BY post_create_time DESC LIMIT 200", - "ss", $path, $path . '/%'); + "sss", $this->SITE_CONFIG['HTTP_HOST'], $path, $path . '/%'); while($row = $feed_posts->fetch_array(MYSQLI_ASSOC)) { $row = $this->_normalize_post_data($row); @@ -173,7 +174,7 @@ class PostHandler extends MySQLAdapter { $entry = $feed->createEntry(); $entry->setTitle($row['post_path'] . '> ' . $pmeta['title']); - $entry->setLink('https://lucidragons.de' . $row['post_path']); + $entry->setLink($this->SITE_CONFIG['uri_prefix'] . $row['post_path']); $entry->setDateModified(strtotime($row['post_update_time'])); $entry->setDateCreated(strtotime($row['post_create_time'])); @@ -197,12 +198,13 @@ class PostHandler extends MySQLAdapter { $feed = $this->construct_feed($path); $this->_exec("INSERT INTO feed_cache - (search_path, export_type, feed_content) + (host, search_path, export_type, feed_content) VALUES - (?, 'atom', ?), - (?, 'rss', ?)", - "ssss", $path, $feed->export('atom'), - $path, $feed->export('rss')); + (?, ?, 'atom', ?), + (?, ?, 'rss', ?)", + "ssssss", + $this->SITE_CONFIG['HTTP_HOST'], $path, $feed->export('atom'), + $this->SITE_CONFIG['HTTP_HOST'], $path, $feed->export('rss')); return $this->try_get_cached_feed($path, $export_opt); } diff --git a/www/router.php b/www/router.php index e65719b..824dc96 100644 --- a/www/router.php +++ b/www/router.php @@ -7,7 +7,20 @@ require_once 'vendor/autoload.php'; require_once 'post_adapter.php'; require_once 'fontawesome.php'; -$adapter = new PostHandler(); +use Symfony\Component\Yaml\Yaml; + +$SERVER_HOST = $_SERVER['HTTP_HOST']; +if(!preg_match('/^[\w\.]+$/', $SERVER_HOST)) { + die(); +} + +$SERVER_PREFIX = "https://" . $SERVER_HOST; + +$SITE_CONFIG = Yaml::parseFile('secrets/' . $SERVER_HOST . '.config.yml'); +$SITE_CONFIG['uri_prefix'] = $SERVER_PREFIX; +$SITE_CONFIG['HTTP_HOST'] = $SERVER_HOST; + +$adapter = new PostHandler($SITE_CONFIG); $loader = new \Twig\Loader\FilesystemLoader(['./templates', './user_content']); From c202b778e0adbce71c57423dbb3bb3307279c994 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 11 Jan 2024 14:37:06 +0100 Subject: [PATCH 03/12] feat: :sparkles: add new file metadata handling (.ext.md instead of .mddesc) --- www/.htaccess | 9 +++-- www/post_adapter.php | 56 ++++++++++++++--------------- www/templates/post_types/image.html | 4 +-- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/www/.htaccess b/www/.htaccess index d624f34..20c4100 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -3,12 +3,17 @@ AddType text/plain .md AddType text/plain .atom AddType text/plain .rss -php_value upload_max_filesize 40M -php_value post_max_size 42M +# php_value upload_max_filesize 40M +# php_value post_max_size 42M RewriteEngine On RewriteBase / +RewriteCond %{REQUEST_URI} !^/raw/ +RewriteRule ^.*\.(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$ raw/%{HTTP_HOST}%{REQUEST_URI} [L,END] + +RewriteRule ^/?raw/(.*)$ raw/%{HTTP_HOST}/$1 [L,END] + RewriteCond %{REQUEST_URI} !^/?(static|raw|robots\.txt).* RewriteRule (.*) router.php diff --git a/www/post_adapter.php b/www/post_adapter.php index 0e96552..6553995 100644 --- a/www/post_adapter.php +++ b/www/post_adapter.php @@ -30,41 +30,42 @@ class PostHandler extends MySQLAdapter { $post_meta["title"] = "root"; } - if(!isset($post_meta['type'])) { - $type = null; - $ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION); + $ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION); - $ext_mapping = [ - '' => 'directory', - 'md' => 'text/markdown', - 'png' => 'image', - 'jpg' => 'image', - 'jpeg' => 'image' - ]; - - if(isset($ext_mapping[$ext])) { - $post_meta['type'] = $ext_mapping[$ext]; - } - else { - $post_meta['type'] = '?'; - } + if(preg_match("/\.(\w+)\.md$/", $post_data['post_basename'], $ext_match)) { + $ext = $ext_match[1]; + + $post_meta['media_file'] ??= "https://" . $this->SITE_CONFIG['HTTP_HOST'] . chop($post_data['post_path'], ".md"); + } + + $ext_mapping = [ + '' => 'directory', + 'md' => 'text/markdown', + 'png' => 'image', + 'jpg' => 'image', + 'jpeg' => 'image' + ]; + + if(isset($ext_mapping[$ext])) { + $post_meta['type'] ??= $ext_mapping[$ext]; + } + else { + $post_meta['type'] ??= '?'; } - if(!isset($post_meta['icon'])) { - $icon_mapping = [ - '' => 'question', - 'text/markdown' => 'markdown', - 'directory' => 'folder', - 'image' => 'image' - ]; + $icon_mapping = [ + '' => 'question', + 'text/markdown' => 'markdown', + 'directory' => 'folder', + 'image' => 'image' + ]; - $post_meta['icon'] = $icon_mapping[$post_meta['type']] ?? 'question'; - } + $post_meta['icon'] ??= $icon_mapping[$post_meta['type']] ?? 'question'; $post_data['post_metadata'] = $post_meta; - $post_data["post_file_dir"] = '/' . $this->data_directory . $post_data["post_path"]; + $post_data["post_file_dir"] = '/raw' . $post_data["post_path"]; return $post_data; } @@ -83,7 +84,6 @@ class PostHandler extends MySQLAdapter { } function save_file($post_path, $file_path) { - $this->bump_post($post_path); move_uploaded_file($file_path, $this->data_directory . $post_path); } diff --git a/www/templates/post_types/image.html b/www/templates/post_types/image.html index 00ea107..6c386e9 100644 --- a/www/templates/post_types/image.html +++ b/www/templates/post_types/image.html @@ -16,8 +16,8 @@ {%block content_article%}
- - + +
From 2ea575f229c25fd1474f96e02ee96d05cd55f1a3 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 11 Jan 2024 16:53:37 +0100 Subject: [PATCH 04/12] feat: rework metadata loading to use site-specific config file --- www/router.php | 17 +++++++++-------- www/templates/pathed_content.html | 6 ++++-- www/templates/root.html | 14 ++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/www/router.php b/www/router.php index 824dc96..03ef15c 100644 --- a/www/router.php +++ b/www/router.php @@ -78,6 +78,7 @@ $twig->addRuntimeLoader(new class implements RuntimeLoaderInterface { function render_twig($template, $args = []) { global $twig; global $FONT_AWESOME_ARRAY; + global $SITE_CONFIG; $args['fa'] = $FONT_AWESOME_ARRAY; @@ -85,27 +86,27 @@ function render_twig($template, $args = []) { $settings = $post['settings'] ?? []; $meta = $post['post_metadata'] ?? []; - $args['banner'] ??= $settings['banners'] ?? [ - ["src"=> "/static/banner/0.png"], - ["src" => "/static/banner/1.png"] - ]; + $args['banner'] ??= $settings['banners'] ?? $SITE_CONFIG['banners']; $args['og'] = array_merge([ - "title" => $meta['title'] ?? "Dergennibble", + "site_name" => $SITE_CONFIG['opengraph']['site_name'], + "title" => $meta['title'] ?? $SITE_CONFIG['opengraph']['site_name'], "url" => $_SERVER['REQUEST_URI'], "description" => $meta['description'] ?? $settings['description'] - ?? "The softest spot to find dragons on" + ?? $SITE_CONFIG['opengraph']['description'] ], $args['og'] ?? []); if(($meta['type'] ?? '') == 'image') { - $args['og']['image'] ??= "https://lucidragons.de" . $post['post_file_dir']; + $args['og']['image'] ??= $meta['media_file']; } - $args['og']['image'] ??= 'https://lucidragons.de' . $args['banner'][0]["src"]; + $args['og']['image'] ??= $SITE_CONFIG['uri_prefix'] . $args['banner'][0]["src"]; $args['banner'] = json_encode($args['banner']); + $args['site_config'] = $SITE_CONFIG; + echo $twig->render($template, $args); } diff --git a/www/templates/pathed_content.html b/www/templates/pathed_content.html index 7ac1cdf..af5b566 100644 --- a/www/templates/pathed_content.html +++ b/www/templates/pathed_content.html @@ -3,8 +3,10 @@ {% extends "root.html" %} {% block feed_links %} - - + +{{ parent() }} + + {% endblock %} {% block second_title %} diff --git a/www/templates/root.html b/www/templates/root.html index 13ba701..e451443 100644 --- a/www/templates/root.html +++ b/www/templates/root.html @@ -1,31 +1,33 @@ - The Dergsite - {{og.title}} + {{og.site_name}} - {{og.title}} - + {% block feed_links %} - + {% endblock %} {% block extra_head %}{% endblock %} {% block opengraph_tags %} - + - + - + + + {% endblock %} + {%if age_gate %} + +
+
+

+ This website may contain content meant for an 18+ audience. +

+ + +
+
+ + + {% endif %} +
full picture -

{% block big_title %}The dergsite{%endblock%}

+

{% block big_title %}{{og.site_name}}{%endblock%}

{% block second_title %}{% endblock %}
From 614bf9d3b6297ee9fb04ca647ad4445046bbee92 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Thu, 11 Jan 2024 16:55:19 +0100 Subject: [PATCH 06/12] perf: :zap: add twig caching --- www/router.php | 2 +- www/templates/post_types/directory.html | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/www/router.php b/www/router.php index 6e29a1d..499623f 100644 --- a/www/router.php +++ b/www/router.php @@ -24,7 +24,7 @@ $adapter = new PostHandler($SITE_CONFIG); $loader = new \Twig\Loader\FilesystemLoader(['./templates', './user_content']); -$twig = new \Twig\Environment($loader,['debug' => true]); +$twig = new \Twig\Environment($loader,['cache' => 'twig_cache']); $twig->addExtension(new Twig\Extra\Markdown\MarkdownExtension()); use Twig\Extra\Markdown\DefaultMarkdown; diff --git a/www/templates/post_types/directory.html b/www/templates/post_types/directory.html index 2872ab4..8f4c405 100644 --- a/www/templates/post_types/directory.html +++ b/www/templates/post_types/directory.html @@ -12,7 +12,7 @@ Directory contents: - Name + Name Title Modified @@ -21,11 +21,11 @@ {{ fa[subpost.post_metadata.icon] | raw }} - + {{subpost.post_basename}} - {{ subpost.post_metadata.title }} + {{ subpost.post_metadata.title }} {{ subpost.post_update_time }} From 8e69a9139ff8029cea360d5117b8546e5050ca18 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:14:32 +0100 Subject: [PATCH 07/12] feat: :sparkles: stylistic tweaks for mobile compatibility --- www/fontawesome.php | 1 + www/static/dergstyle.css | 17 +- www/static/gallerystyle.css | 64 ++++++++ www/static/modest.css | 203 ++++++++++++++++++++++++ www/static/solarized-dark.css | 84 ++++++++++ www/templates/post_types/directory.html | 2 +- www/templates/root.html | 5 +- 7 files changed, 366 insertions(+), 10 deletions(-) create mode 100644 www/static/gallerystyle.css create mode 100644 www/static/modest.css create mode 100644 www/static/solarized-dark.css diff --git a/www/fontawesome.php b/www/fontawesome.php index 61f4c87..91b82d5 100644 --- a/www/fontawesome.php +++ b/www/fontawesome.php @@ -3,6 +3,7 @@ $FONT_AWESOME_ARRAY=[ 'markdown' => '', 'image' => '', + 'images' => '', 'folder' => '', 'rss' => '' ]; diff --git a/www/static/dergstyle.css b/www/static/dergstyle.css index b0798fe..ccde5fa 100644 --- a/www/static/dergstyle.css +++ b/www/static/dergstyle.css @@ -20,6 +20,7 @@ body { --highlight_2: #edd29e; --text_1: #FFFFFF; + --text_border: #A0A0A080; color: var(--text_1); background: var(--bg_1); @@ -149,11 +150,15 @@ a:hover { margin-right: 2rem; } +:target { + scroll-margin-top: 6rem; +} + #main_content_wrapper { --content-width: min(100vw, calc(20rem + 40vw)); --content-total-margin: calc(calc(100vw - var(--content-width)) / 2); - --content-padding: max(0px, min(1rem, var(--content-total-margin))); + --content-padding: max(0.5rem, min(1rem, var(--content-total-margin))); --content-margin: max(0px, calc(var(--content-total-margin) - 1rem)); padding: 0rem var(--content-padding) 1rem var(--content-padding); @@ -175,6 +180,9 @@ a:hover { top: 0px; background: var(--bg_2); + + box-shadow: 0px 5px 5px 0px #00000040; + z-index: 5; } #post_file_titles { @@ -223,13 +231,6 @@ a:hover { padding: 0.75rem; } -#main_content_wrapper article h1 { - text-align: left; - padding-left: 3vmin; - margin-bottom: 0.2rem; - - border-bottom: solid 1px darkgrey; -} #main_content_wrapper article img { display: block; diff --git a/www/static/gallerystyle.css b/www/static/gallerystyle.css new file mode 100644 index 0000000..c73ab1a --- /dev/null +++ b/www/static/gallerystyle.css @@ -0,0 +1,64 @@ +.gallery { + display: flex; + flex-direction: row; + + flex-flow: row wrap; + + justify-content: center; + + list-style-type: none; + margin-top: 1rem; + padding: 0px; +} + +.gallery li { + margin: 0.2rem; + margin-bottom: 1rem; + border: 1px solid var(--text_border); + float: left; + + border-radius: 1rem; + box-shadow: 0px 5px 5px 0px #00000040; + + background: var(--bg_2); + + height: auto; + + transition: 0.3s; + z-index: 1; +} + +.gallery li:hover { + border: 1px solid var(--text_1); + transform: scale(1.02); +} + +#main_content_wrapper .gallery img { + width: 100%; + height: 15rem; + margin: 0; + + border-radius: 1rem 1rem 0 0; + + object-fit: cover; +} + +@media screen and (max-width: 48rem) { + .gallery li { + width: 45%; + } + + #main_content_wrapper .gallery img { + height: 100%; + width: auto; + } + + #main_content_wrapper .gallery figure { + height: auto; + } +} + +.gallery figcaption { + padding: 0.1rem; + text-align: center; +} \ No newline at end of file diff --git a/www/static/modest.css b/www/static/modest.css new file mode 100644 index 0000000..d45177d --- /dev/null +++ b/www/static/modest.css @@ -0,0 +1,203 @@ +/* +modest.css, licensed under MIT license, Crafted with <3 by John Otander (@4lpine). + +Taken from: https://github.com/markdowncss/modest + +Modified to fit Dergsite needs +*/ + +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; + box-shadow: none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} + +pre, +code { + font-family: Menlo, Monaco, "Courier New", monospace; +} + +.modest-no-decoration { + text-decoration: none; +} + +html { + font-size: 14px; +} + +@media screen and (min-width: 32rem) and (max-width: 48rem) { + html { + font-size: 16px; + } +} + +@media screen and (min-width: 48rem) { + html { + font-size: 17px; + } +} + +article { + line-height: 1.5; +} + +article p, +.modest-p { + font-size: 1rem; + margin-bottom: 1.3rem; +} + +article h1, +.modest-h1, +article h2, +.modest-h2, +article h3, +.modest-h3, +article h4, +.modest-h4 { + margin: 1.5em 0 .3em; + font-weight: inherit; + line-height: 1.42; + + padding-left: 1.5rem; +} + +article > :first-child { + margin-top: 0.3rem !important; +} + +article h1, +.modest-h1 { + margin-top: 0; + font-size: 1.998rem; +} + +article h2, +.modest-h2 { + font-size: 1.427rem; +} + +article h3, +.modest-h3 { + font-size: 1.299rem; +} + +article h4, +.modest-h4 { + font-size: 1.1rem; +} + +article h5, +.modest-h5 { + font-size: 1rem; +} + +article h6, +.modest-h6 { + font-size: .88rem; +} + +article small, +.modest-small { + font-size: .707rem; +} + +/* https://github.com/mrmrs/fluidity */ + +article h1, +article h2, +article h3 { + border-bottom: 1px solid var(--text_border); + padding-bottom: .3rem; +} + +blockquote { + padding-left: 0.8rem; + margin-left: 0.8rem; + margin-right: 4em; +} + +blockquote { + border-left: 4px solid var(--text_border); + text-align: justify; +} + +pre { + border-radius: 0.5rem; + + box-shadow: 2px 5px 5px 0px #00000040; + + border-left: 4px solid #206475; + background-color: var(--bg_2); + margin-bottom: 1.3rem; + margin-left: 0.8rem; + margin-right: 4em; +} +pre code { + border-radius: 0.5rem; +} + +@media screen and (max-width: 32rem) { + pre, blockquote { + margin-right: 1.5em; + } +} + +article ul, +article ol { + padding-left: 2em; +} \ No newline at end of file diff --git a/www/static/solarized-dark.css b/www/static/solarized-dark.css new file mode 100644 index 0000000..b4c0da1 --- /dev/null +++ b/www/static/solarized-dark.css @@ -0,0 +1,84 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #002b36; + color: #839496; +} + +.hljs-comment, +.hljs-quote { + color: #586e75; +} + +/* Solarized Green */ +.hljs-keyword, +.hljs-selector-tag, +.hljs-addition { + color: #859900; +} + +/* Solarized Cyan */ +.hljs-number, +.hljs-string, +.hljs-meta .hljs-meta-string, +.hljs-literal, +.hljs-doctag, +.hljs-regexp { + color: #2aa198; +} + +/* Solarized Blue */ +.hljs-title, +.hljs-section, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #268bd2; +} + +/* Solarized Yellow */ +.hljs-attribute, +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-class .hljs-title, +.hljs-type { + color: #b58900; +} + +/* Solarized Orange */ +.hljs-symbol, +.hljs-bullet, +.hljs-subst, +.hljs-meta, +.hljs-meta .hljs-keyword, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-link { + color: #cb4b16; +} + +/* Solarized Red */ +.hljs-built_in, +.hljs-deletion { + color: #dc322f; +} + +.hljs-formula { + background: #073642; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/www/templates/post_types/directory.html b/www/templates/post_types/directory.html index 8f4c405..ffacda0 100644 --- a/www/templates/post_types/directory.html +++ b/www/templates/post_types/directory.html @@ -8,8 +8,8 @@ {%block content_article%} {% if subposts|length > 0 %} +

Directory contents:

- diff --git a/www/templates/root.html b/www/templates/root.html index 5950c0b..11f0c14 100644 --- a/www/templates/root.html +++ b/www/templates/root.html @@ -3,9 +3,12 @@ {{og.site_name}} - {{og.title}} + + + - + {% block feed_links %} From 9354f9f556d88fe5343c187b3b4e1162f8dfc5ad Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:22:11 +0100 Subject: [PATCH 08/12] feat: :sparkles: add highlighting Markdown parser <3 --- www/composer.json | 5 +- www/composer.lock | 604 +++++++++++++++++++++++-- www/dergdown.php | 39 ++ www/router.php | 9 + www/templates/post_types/image.html | 4 +- www/templates/post_types/markdown.html | 2 +- 6 files changed, 613 insertions(+), 50 deletions(-) create mode 100644 www/dergdown.php diff --git a/www/composer.json b/www/composer.json index eb01954..4edcc55 100644 --- a/www/composer.json +++ b/www/composer.json @@ -4,6 +4,9 @@ "twig/markdown-extra": "^3.6", "league/commonmark": "^2.4", "spatie/yaml-front-matter": "^2.0", - "laminas/laminas-feed": "^2.6" + "laminas/laminas-feed": "^2.6", + "erusev/parsedown": "^1.7", + "erusev/parsedown-extra": "^0.8.1", + "scrivo/highlight.php": "v9.18.1.10" } } diff --git a/www/composer.lock b/www/composer.lock index e227088..c157e3a 100644 --- a/www/composer.lock +++ b/www/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ae80529cc2442878a51f38de1f7017a4", + "content-hash": "34ef4bdab7508bbe6f60a1a56e33d08c", "packages": [ { "name": "dflydev/dot-access-data", @@ -81,6 +81,442 @@ }, "time": "2022-10-27T11:44:00+00:00" }, + { + "name": "erusev/parsedown", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" + }, + { + "name": "erusev/parsedown-extra", + "version": "0.8.1", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown-extra.git", + "reference": "91ac3ff98f0cea243bdccc688df43810f044dcef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/91ac3ff98f0cea243bdccc688df43810f044dcef", + "reference": "91ac3ff98f0cea243bdccc688df43810f044dcef", + "shasum": "" + }, + "require": { + "erusev/parsedown": "^1.7.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "ParsedownExtra": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "An extension of Parsedown that adds support for Markdown Extra.", + "homepage": "https://github.com/erusev/parsedown-extra", + "keywords": [ + "markdown", + "markdown extra", + "parsedown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown-extra/issues", + "source": "https://github.com/erusev/parsedown-extra/tree/0.8.x" + }, + "time": "2019-12-30T23:20:37+00:00" + }, + { + "name": "laminas/laminas-escaper", + "version": "2.13.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/af459883f4018d0f8a0c69c7a209daef3bf973ba", + "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "conflict": { + "zendframework/zend-escaper": "*" + }, + "require-dev": { + "infection/infection": "^0.27.0", + "laminas/laminas-coding-standard": "~2.5.0", + "maglnet/composer-require-checker": "^3.8.0", + "phpunit/phpunit": "^9.6.7", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2023-10-10T08:35:13+00:00" + }, + { + "name": "laminas/laminas-feed", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-feed.git", + "reference": "c1594cb32b117d3b409d4beee12c724cb26daa71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-feed/zipball/c1594cb32b117d3b409d4beee12c724cb26daa71", + "reference": "c1594cb32b117d3b409d4beee12c724cb26daa71", + "shasum": "" + }, + "require": { + "laminas/laminas-escaper": "~2.5", + "laminas/laminas-stdlib": "~2.5", + "laminas/laminas-zendframework-bridge": "^1.0", + "php": ">=5.5" + }, + "replace": { + "zendframework/zend-feed": "self.version" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "laminas/laminas-cache": "~2.5", + "laminas/laminas-db": "~2.5", + "laminas/laminas-http": "~2.5", + "laminas/laminas-validator": "~2.5", + "phpunit/phpunit": "~4.0", + "psr/http-message": "^1.0" + }, + "suggest": { + "laminas/laminas-cache": "Laminas\\Cache component, for optionally caching feeds between requests", + "laminas/laminas-db": "Laminas\\Db component, for use with PubSubHubbub", + "laminas/laminas-http": "Laminas\\Http for PubSubHubbub, and optionally for use with Laminas\\Feed\\Reader", + "laminas/laminas-servicemanager": "Laminas\\ServiceManager component, for easily extending ExtensionManager implementations", + "laminas/laminas-validator": "Laminas\\Validator component, for validating feeds and Atom entries in the Writer subcomponent", + "psr/http-message": "PSR-7 ^1.0, if you wish to use Laminas\\Feed\\Reader\\Http\\Psr7ResponseDecorator" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev", + "dev-develop": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Laminas\\Feed\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides functionality for consuming RSS and Atom feeds", + "homepage": "https://laminas.dev", + "keywords": [ + "feed", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-feed/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-feed/issues", + "rss": "https://github.com/laminas/laminas-feed/releases.atom", + "source": "https://github.com/laminas/laminas-feed" + }, + "time": "2019-12-31T16:50:31+00:00" + }, + { + "name": "laminas/laminas-hydrator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-hydrator.git", + "reference": "acab29a3327a70be0a653d88906655b15de15517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-hydrator/zipball/acab29a3327a70be0a653d88906655b15de15517", + "reference": "acab29a3327a70be0a653d88906655b15de15517", + "shasum": "" + }, + "require": { + "laminas/laminas-stdlib": "^2.5.1", + "laminas/laminas-zendframework-bridge": "^1.0", + "php": ">=5.5" + }, + "replace": { + "zendframework/zend-hydrator": "self.version" + }, + "require-dev": { + "laminas/laminas-eventmanager": "^2.5.1", + "laminas/laminas-filter": "^2.5.1", + "laminas/laminas-inputfilter": "^2.5.1", + "laminas/laminas-serializer": "^2.5.1", + "laminas/laminas-servicemanager": "^2.5.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0@dev" + }, + "suggest": { + "laminas/laminas-eventmanager": "^2.5.1, to support aggregate hydrator usage", + "laminas/laminas-filter": "^2.5.1, to support naming strategy hydrator usage", + "laminas/laminas-serializer": "^2.5.1, to use the SerializableStrategy", + "laminas/laminas-servicemanager": "^2.5.1, to support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Laminas\\Hydrator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://laminas.dev", + "keywords": [ + "hydrator", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-hydrator/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-hydrator/issues", + "rss": "https://github.com/laminas/laminas-hydrator/releases.atom", + "source": "https://github.com/laminas/laminas-hydrator" + }, + "time": "2019-12-31T17:06:20+00:00" + }, + { + "name": "laminas/laminas-stdlib", + "version": "2.7.4", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-stdlib.git", + "reference": "b69e2741673daabdf720bc76668448ceb1e4c537" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/b69e2741673daabdf720bc76668448ceb1e4c537", + "reference": "b69e2741673daabdf720bc76668448ceb1e4c537", + "shasum": "" + }, + "require": { + "laminas/laminas-hydrator": "~1.0", + "laminas/laminas-zendframework-bridge": "^1.0", + "php": ">=5.5" + }, + "replace": { + "zendframework/zend-stdlib": "self.version" + }, + "require-dev": { + "athletic/athletic": "~0.1", + "fabpot/php-cs-fixer": "1.7.*", + "laminas/laminas-config": "~2.5", + "laminas/laminas-eventmanager": "~2.5", + "laminas/laminas-filter": "~2.5", + "laminas/laminas-inputfilter": "~2.5", + "laminas/laminas-serializer": "~2.5", + "laminas/laminas-servicemanager": "~2.5", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "laminas/laminas-eventmanager": "To support aggregate hydrator usage", + "laminas/laminas-filter": "To support naming strategy hydrator usage", + "laminas/laminas-serializer": "Laminas\\Serializer component", + "laminas/laminas-servicemanager": "To support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Laminas\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "stdlib" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-stdlib/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-stdlib/issues", + "rss": "https://github.com/laminas/laminas-stdlib/releases.atom", + "source": "https://github.com/laminas/laminas-stdlib" + }, + "time": "2019-12-31T17:51:00+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "eb0d96c708b92177a92bc2239543d3ed523452c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/eb0d96c708b92177a92bc2239543d3ed523452c6", + "reference": "eb0d96c708b92177a92bc2239543d3ed523452c6", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.4", + "psalm/plugin-phpunit": "^0.18.0", + "squizlabs/php_codesniffer": "^3.7.1", + "vimeo/psalm": "^5.16.0" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": true, + "time": "2023-11-24T13:56:19+00:00" + }, { "name": "league/commonmark", "version": "2.4.1", @@ -333,16 +769,16 @@ }, { "name": "nette/utils", - "version": "v4.0.2", + "version": "v4.0.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "cead6637226456b35e1175cc53797dd585d85545" + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/cead6637226456b35e1175cc53797dd585d85545", - "reference": "cead6637226456b35e1175cc53797dd585d85545", + "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", "shasum": "" }, "require": { @@ -413,9 +849,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.2" + "source": "https://github.com/nette/utils/tree/v4.0.3" }, - "time": "2023-09-19T11:58:07+00:00" + "time": "2023-10-29T21:02:13+00:00" }, { "name": "psr/event-dispatcher", @@ -468,22 +904,100 @@ "time": "2019-01-08T18:20:26+00:00" }, { - "name": "spatie/yaml-front-matter", - "version": "2.0.7", + "name": "scrivo/highlight.php", + "version": "v9.18.1.10", "source": { "type": "git", - "url": "https://github.com/spatie/yaml-front-matter.git", - "reference": "f49f228994de70827ca857efffdd3bd7703aea34" + "url": "https://github.com/scrivo/highlight.php.git", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/f49f228994de70827ca857efffdd3bd7703aea34", - "reference": "f49f228994de70827ca857efffdd3bd7703aea34", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/850f4b44697a2552e892ffe71490ba2733c2fc6e", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "sabberworm/php-css-parser": "^8.3", + "symfony/finder": "^2.8|^3.4|^5.4", + "symfony/var-dumper": "^2.8|^3.4|^5.4" + }, + "suggest": { + "ext-mbstring": "Allows highlighting code with unicode characters and supports language with unicode keywords" + }, + "type": "library", + "autoload": { + "files": [ + "HighlightUtilities/functions.php" + ], + "psr-0": { + "Highlight\\": "", + "HighlightUtilities\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Geert Bergman", + "homepage": "http://www.scrivo.org/", + "role": "Project Author" + }, + { + "name": "Vladimir Jimenez", + "homepage": "https://allejo.io", + "role": "Maintainer" + }, + { + "name": "Martin Folkers", + "homepage": "https://twobrain.io", + "role": "Contributor" + } + ], + "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", + "keywords": [ + "code", + "highlight", + "highlight.js", + "highlight.php", + "syntax" + ], + "support": { + "issues": "https://github.com/scrivo/highlight.php/issues", + "source": "https://github.com/scrivo/highlight.php" + }, + "funding": [ + { + "url": "https://github.com/allejo", + "type": "github" + } + ], + "time": "2022-12-17T21:53:22+00:00" + }, + { + "name": "spatie/yaml-front-matter", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/spatie/yaml-front-matter.git", + "reference": "f2f1f749a405fafc9d6337067c92c062d51a581c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/yaml-front-matter/zipball/f2f1f749a405fafc9d6337067c92c062d51a581c", + "reference": "f2f1f749a405fafc9d6337067c92c062d51a581c", "shasum": "" }, "require": { "php": "^7.0|^8.0", - "symfony/yaml": "^3.0|^4.0|^5.0|^6.0" + "symfony/yaml": "^3.0|^4.0|^5.0|^6.0|^7.0" }, "require-dev": { "phpunit/phpunit": "^9.0" @@ -515,7 +1029,7 @@ "yaml" ], "support": { - "source": "https://github.com/spatie/yaml-front-matter/tree/2.0.7" + "source": "https://github.com/spatie/yaml-front-matter/tree/2.0.8" }, "funding": [ { @@ -527,11 +1041,11 @@ "type": "github" } ], - "time": "2022-04-06T12:03:55+00:00" + "time": "2023-12-04T10:02:52+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.3.0", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -578,7 +1092,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" }, "funding": [ { @@ -846,28 +1360,27 @@ }, { "name": "symfony/yaml", - "version": "v6.3.3", + "version": "v7.0.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add" + "reference": "0055b230c408428b9b5cde7c55659555be5c0278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0055b230c408428b9b5cde7c55659555be5c0278", + "reference": "0055b230c408428b9b5cde7c55659555be5c0278", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.2", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0" + "symfony/console": "^6.4|^7.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -898,7 +1411,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.3.3" + "source": "https://github.com/symfony/yaml/tree/v7.0.0" }, "funding": [ { @@ -914,32 +1427,32 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2023-11-07T10:26:03+00:00" }, { "name": "twig/markdown-extra", - "version": "v3.7.1", + "version": "v3.8.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", - "reference": "83dfa86a0379f784ea30bdb9c15a356b8aabf780" + "reference": "b6e4954ab60030233df5d293886b5404558daac8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/83dfa86a0379f784ea30bdb9c15a356b8aabf780", - "reference": "83dfa86a0379f784ea30bdb9c15a356b8aabf780", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/b6e4954ab60030233df5d293886b5404558daac8", + "reference": "b6e4954ab60030233df5d293886b5404558daac8", "shasum": "" }, "require": { - "php": ">=7.1.3", - "twig/twig": "^2.7|^3.0" + "php": ">=7.2.5", + "twig/twig": "^3.0" }, "require-dev": { "erusev/parsedown": "^1.7", "league/commonmark": "^1.0|^2.0", "league/html-to-markdown": "^4.8|^5.0", "michelf/php-markdown": "^1.8|^2.0", - "symfony/phpunit-bridge": "^5.4|^6.3" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -970,7 +1483,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.7.1" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.8.0" }, "funding": [ { @@ -982,30 +1495,31 @@ "type": "tidelift" } ], - "time": "2023-07-29T15:34:56+00:00" + "time": "2023-11-21T14:02:01+00:00" }, { "name": "twig/twig", - "version": "v3.7.1", + "version": "v3.8.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" + "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", - "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3" + "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" }, "type": "library", "autoload": { @@ -1041,7 +1555,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.1" + "source": "https://github.com/twigphp/Twig/tree/v3.8.0" }, "funding": [ { @@ -1053,7 +1567,7 @@ "type": "tidelift" } ], - "time": "2023-08-28T11:09:02+00:00" + "time": "2023-11-21T18:54:41+00:00" } ], "packages-dev": [], diff --git a/www/dergdown.php b/www/dergdown.php new file mode 100644 index 0000000..8380be7 --- /dev/null +++ b/www/dergdown.php @@ -0,0 +1,39 @@ + + +highlighter = new Highlighter(); + } + + protected function blockFencedCodeComplete($block) + { + if (! isset($block['element']['text']['attributes'])) { + return $block; + } + + $code = $block['element']['text']['text']; + $languageClass = $block['element']['text']['attributes']['class']; + $language = explode('-', $languageClass); + + try { + $highlighted = $this->highlighter->highlight($language[1], $code); + $block['element']['text']['attributes']['class'] = vsprintf('%s hljs %s', [ + $languageClass, + $highlighted->language, + ]); + $block['element']['text']['rawHtml'] = $highlighted->value; + unset($block['element']['text']['text']); + } catch (DomainException $e) { + } + + return $block; + } +} \ No newline at end of file diff --git a/www/router.php b/www/router.php index 499623f..7baf82a 100644 --- a/www/router.php +++ b/www/router.php @@ -6,6 +6,7 @@ require_once 'vendor/autoload.php'; require_once 'post_adapter.php'; require_once 'fontawesome.php'; +require_once 'dergdown.php'; use Symfony\Component\Yaml\Yaml; @@ -31,6 +32,12 @@ use Twig\Extra\Markdown\DefaultMarkdown; use Twig\Extra\Markdown\MarkdownRuntime; use Twig\RuntimeLoader\RuntimeLoaderInterface; +function dergdown_to_html($text) { + $Parsedown = new Dergdown(); + + return $Parsedown->text($text); +} + function deduce_user_agent() { $real_agent=$_SERVER['HTTP_USER_AGENT']; @@ -109,6 +116,8 @@ function render_twig($template, $args = []) { $args['age_gate'] = (!isset($_COOKIE['AgeConfirmed'])) && isset($SITE_CONFIG['age_gate']); + $args['content_html'] ??= dergdown_to_html($post['post_content'] ?? ''); + echo $twig->render($template, $args); } diff --git a/www/templates/post_types/image.html b/www/templates/post_types/image.html index 6c386e9..aff2115 100644 --- a/www/templates/post_types/image.html +++ b/www/templates/post_types/image.html @@ -10,8 +10,6 @@ {{ parent() }} - - {%endblock %} {%block content_article%} @@ -21,7 +19,7 @@
- {{ post.post_content|markdown_to_html }} + {{ content_html|raw }}
{%endblock%} diff --git a/www/templates/post_types/markdown.html b/www/templates/post_types/markdown.html index f874fbc..b9d147c 100644 --- a/www/templates/post_types/markdown.html +++ b/www/templates/post_types/markdown.html @@ -9,5 +9,5 @@ {%endblock %} {%block content_article%} - {{ post['post_content']|markdown_to_html }} + {{ content_html|raw }} {% endblock %} \ No newline at end of file From add698651efc2b7ce5f3aaf0a4b504159a3f8104 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:31:16 +0100 Subject: [PATCH 09/12] feat: :sparkles: add gallery page --- www/router.php | 26 ++++++++++-- www/templates/post_types/gallery.html | 59 +++++++++++++++++++++++++++ www/templates/root.dergplate | 18 -------- www/templates/root.html | 5 +++ 4 files changed, 86 insertions(+), 22 deletions(-) create mode 100644 www/templates/post_types/gallery.html delete mode 100644 www/templates/root.dergplate diff --git a/www/router.php b/www/router.php index 7baf82a..91b9779 100644 --- a/www/router.php +++ b/www/router.php @@ -99,6 +99,7 @@ function render_twig($template, $args = []) { "site_name" => $SITE_CONFIG['opengraph']['site_name'], "title" => $meta['title'] ?? $SITE_CONFIG['opengraph']['site_name'], "url" => $_SERVER['REQUEST_URI'], + "type" => "article", "description" => $meta['description'] ?? $settings['description'] ?? $SITE_CONFIG['opengraph']['description'] @@ -106,9 +107,10 @@ function render_twig($template, $args = []) { if(($meta['type'] ?? '') == 'image') { $args['og']['image'] ??= $meta['media_file']; + $args['og']['type'] = "image"; } - $args['og']['image'] ??= $SITE_CONFIG['uri_prefix'] . $args['banner'][0]["src"]; + $args['og']['image'] ??= $args['banner'][0]["src"]; $args['banner'] = json_encode($args['banner']); @@ -161,6 +163,25 @@ function try_render_post($SURI) { ]); break; + case 'gallery': + if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) { + header('Location: ' . $match[1] . '/' . $match[2]); + + die(); + } + + $search_query = $post['post_metadata']['search_tags'] ?? + ('+type:image +path:' . $post['post_path'] . '/*'); + + $search_result = $adapter->perform_post_search($search_query); + + echo render_twig('post_types/gallery.html', [ + "post" => $post, + "subposts" => $adapter->get_subposts_by_path($SURI), + "gallery_images" => $search_result['results'] + ]); + break; + case 'image': echo render_twig('post_types/image.html', [ "post" => $post, @@ -227,9 +248,6 @@ function generate_website($SURI) { header('Etag: W/"' . $SURI . '/' . strtotime($feed['feed_ts']) . '"'); echo $feed['feed']; - } elseif(!preg_match('/^\s*text\/html/', $_SERVER['HTTP_ACCEPT'])) { - header('Location: /raw' . $SURI); - exit(0); } elseif(true) { try_render_post($SURI); } diff --git a/www/templates/post_types/gallery.html b/www/templates/post_types/gallery.html new file mode 100644 index 0000000..4e96b3d --- /dev/null +++ b/www/templates/post_types/gallery.html @@ -0,0 +1,59 @@ + + +{% extends "pathed_content.html" %} + +{% block extra_head %} + + +{%endblock%} + +{%block content_article%} + {% if subposts|length > 0 %} +
Directory contents:
Name
+

Art Subfolders:

+ + + + + + + {% for subpost in subposts %} + + + + + + + {% endfor %} +
NameTitleModified
+ {{ fa[subpost.post_metadata.icon] | raw }} + + {{subpost.post_basename}} + + {{ subpost.post_metadata.title }} + + {{ subpost.post_update_time }} +
+ {% endif %} + + {{ content_html|raw }} + + {% if gallery_images|length > 0 %} + + {%else%} +

How sad. There are no images yet... What a real shame :c

+ {% endif %} +{%endblock%} diff --git a/www/templates/root.dergplate b/www/templates/root.dergplate deleted file mode 100644 index fa4e62b..0000000 --- a/www/templates/root.dergplate +++ /dev/null @@ -1,18 +0,0 @@ - - - PHP Test - - - Hello World

'; - - require 'src/templater.php'; - - $test = new TemplateFillout('test.dergplate'); - - $test->render(); - - ?> - - diff --git a/www/templates/root.html b/www/templates/root.html index 11f0c14..01a87d6 100644 --- a/www/templates/root.html +++ b/www/templates/root.html @@ -23,12 +23,17 @@ + + + + + {% endblock %} From 12d3838eaed615be6d80ea88be265c92f63b5a3f Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:32:38 +0100 Subject: [PATCH 10/12] feat: :sparkles: add post search function --- www/mysql_adapter.php | 100 ++++++++++++++++++++++++++++++++++++++---- www/router.php | 9 +++- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/www/mysql_adapter.php b/www/mysql_adapter.php index 6fc3e58..3d845b6 100644 --- a/www/mysql_adapter.php +++ b/www/mysql_adapter.php @@ -69,6 +69,14 @@ class MySQLAdapter { return $post_data; } + function _normalize_post_array($post_data) { + $post_data ??= []; + + return array_map(function($post) { + return $this->_normalize_post_data($post); + }, $post_data); + } + function bump_post($post_path, $post_metadata = [], $create_dirs = true) { $post_path = $this->_sanitize_path($post_path); $path_depth = substr_count($post_path, "/"); @@ -212,6 +220,86 @@ class MySQLAdapter { ", "ss", $this->SITE_CONFIG['HTTP_HOST'], $post_path . "%"); } + function escape_tag($tag) { + return preg_replace_callback('/[\WZ]/', function($match) { + return "Z" . ord($match[0]); + }, strtolower($tag)); + } + + function escape_search_tag($tag) { + preg_match("/^([\+\-]?)(.*?)(\*?)$/", $tag, $matches); + + if(!isset($matches[1])) { + echo "Problem with tag!"; + var_dump($tag); + } + + return $matches[1] . $this->escape_tag($matches[2]) . $matches[3]; + } + + function update_post_search_data($post_path, $post_tags) { + $post_tags []= "path:" . $post_path; + $post_tags []= "host:" . $this->SITE_CONFIG['HTTP_HOST']; + + $post_tags = array_unique($post_tags); + $post_tags = array_map(function($val) { + return $this->escape_tag($val); + }, $post_tags); + + asort($post_tags); + $post_tags = join(' ', $post_tags); + + $qry = " + INSERT INTO posts + ( host, post_path, post_tags ) + VALUES + ( ?, ?, ? ) AS new + ON DUPLICATE KEY + UPDATE post_tags=new.post_tags; + "; + + $this->_exec($qry, "sss", + $this->SITE_CONFIG['HTTP_HOST'], $post_path, $post_tags); + } + + function perform_post_search($taglist, $order = null, $limit = 20, $page = 0) { + $allowed_ordering = [ + "post_create_time" + ]; + + $qry = " + SELECT post_path, post_metadata + FROM posts + WHERE MATCH(post_tags) AGAINST (? IN BOOLEAN MODE) + "; + + if(!is_array($taglist)) { + $taglist = explode(' ', $taglist); + } + + $taglist []= '+host:' . $this->SITE_CONFIG['HTTP_HOST']; + $taglist = array_unique($taglist); + $taglist = array_map(function($key) { + return $this->escape_search_tag($key); + }, $taglist); + + $taglist = implode(' ', $taglist); + + if(isset($order) and in_array($order, $allowed_ordering)) { + $qry = $qry . " ORDER BY " . $order; + } + + $qry = $qry . " LIMIT ? OFFSET ?"; + + $search_results = $this->_exec($qry, "sii", $taglist, $limit, $limit * $page)->fetch_all(MYSQLI_ASSOC); + $search_results = [ + "query_string" => $taglist, + "results" => $this->_normalize_post_array($search_results) + ]; + + return $search_results; + } + function update_or_create_post($post_path, $post_metadata, $post_content) { $post_path = $this->_sanitize_path($post_path); $path_depth = substr_count($post_path, "/"); @@ -236,6 +324,8 @@ class MySQLAdapter { $path_depth, json_encode($post_metadata), $post_content); + + $this->update_post_search_data($post_path, $post_metadata['tags'] ?? []); } function get_settings_for_path($post_path) { @@ -294,9 +384,7 @@ class MySQLAdapter { $post_data = $this->_exec($qry, "ss", $post_path, $this->SITE_CONFIG['HTTP_HOST'])->fetch_assoc(); - if(!isset($post_data)) { - $post_data = ['found' => false]; - } + $post_data ??= ['found' => false]; $post_data['post_path'] = $post_path; $post_data = $this->_normalize_post_data($post_data); @@ -334,11 +422,7 @@ class MySQLAdapter { $post_data = $this->_exec($qry, "ssi", $this->SITE_CONFIG['HTTP_HOST'], $path, $path_depth+1)->fetch_all(MYSQLI_ASSOC); - $fn = function($data) { - return $this->_normalize_post_data($data); - }; - - $post_data = array_map($fn, $post_data); + $post_data = $this->_normalize_post_array($post_data); return $post_data; } diff --git a/www/router.php b/www/router.php index 91b9779..18c4641 100644 --- a/www/router.php +++ b/www/router.php @@ -25,7 +25,10 @@ $adapter = new PostHandler($SITE_CONFIG); $loader = new \Twig\Loader\FilesystemLoader(['./templates', './user_content']); -$twig = new \Twig\Environment($loader,['cache' => 'twig_cache']); +$twig = new \Twig\Environment($loader,[ + 'debug' => true, + 'cache' => 'twig_cache' +]); $twig->addExtension(new Twig\Extra\Markdown\MarkdownExtension()); use Twig\Extra\Markdown\DefaultMarkdown; @@ -239,6 +242,10 @@ function generate_website($SURI) { } elseif($SURI == '/api/upload') { echo $twig->render('upload.html'); + } elseif($SURI == '/api/search') { + + header('Content-Type: application/json'); + echo json_encode($adapter->perform_post_search($_GET['search_query'])); } } elseif(preg_match('/^\/feed(?:\/(rss|atom)(.*))?$/', $SURI, $match)) { $feed = $adapter->get_laminas_feed($match[2] ?? '/', $match[1] ?? 'rss'); From a65dd96f8f9dd5806bb1b41ed1a157451106bb2d Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:34:49 +0100 Subject: [PATCH 11/12] feat: rework post normalization systems --- www/post_adapter.php | 97 +++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/www/post_adapter.php b/www/post_adapter.php index 6553995..65b4ced 100644 --- a/www/post_adapter.php +++ b/www/post_adapter.php @@ -14,6 +14,51 @@ class PostHandler extends MySQLAdapter { $this->data_directory = 'raw/' . $this->SITE_CONFIG['HTTP_HOST']; } + function deduce_post_type($post_path) { + $ext = pathinfo($post_path, PATHINFO_EXTENSION); + + if(preg_match("/\.(\w+)\.md$/", $post_path, $ext_match)) { + $ext = $ext_match[1]; + } + + $ext_mapping = [ + '' => 'directory', + 'md' => 'text/markdown', + 'png' => 'image', + 'jpg' => 'image', + 'jpeg' => 'image' + ]; + + return $ext_mapping[$ext] ?? '?'; + } + + function fill_in_post_meta($post_path, $meta) { + $icon_mapping = [ + '' => 'question', + 'text/markdown' => 'markdown', + 'directory' => 'folder', + 'gallery' => 'images', + 'image' => 'image' + ]; + + $meta["title"] ??= basename($post_path); + + if($meta["title"] == "") { + $meta["title"] = "root"; + } + + if(!isset($meta['media_file']) and preg_match("/\.(\w+)\.md$/", $post_path)) { + $meta['media_file'] = "https://" . $this->SITE_CONFIG['HTTP_HOST'] . chop($post_path, ".md"); + } + + $meta['tags'] ??= []; + $meta['type'] ??= $this->deduce_post_type($post_path); + + $meta['icon'] ??= $icon_mapping[$meta['type']] ?? 'question'; + + return $meta; + } + function _normalize_post_data($post_data) { $post_data = parent::_normalize_post_data($post_data); @@ -24,46 +69,10 @@ class PostHandler extends MySQLAdapter { $post_data["post_basename"] = basename($post_data["post_path"]); $post_meta = $post_data['post_metadata']; - - $post_meta["title"] ??= basename($post_data["post_path"]); - if($post_meta["title"] == "") { - $post_meta["title"] = "root"; - } - - - $ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION); - - if(preg_match("/\.(\w+)\.md$/", $post_data['post_basename'], $ext_match)) { - $ext = $ext_match[1]; - - $post_meta['media_file'] ??= "https://" . $this->SITE_CONFIG['HTTP_HOST'] . chop($post_data['post_path'], ".md"); - } - - $ext_mapping = [ - '' => 'directory', - 'md' => 'text/markdown', - 'png' => 'image', - 'jpg' => 'image', - 'jpeg' => 'image' - ]; - if(isset($ext_mapping[$ext])) { - $post_meta['type'] ??= $ext_mapping[$ext]; - } - else { - $post_meta['type'] ??= '?'; - } - - $icon_mapping = [ - '' => 'question', - 'text/markdown' => 'markdown', - 'directory' => 'folder', - 'image' => 'image' - ]; - - $post_meta['icon'] ??= $icon_mapping[$post_meta['type']] ?? 'question'; - - $post_data['post_metadata'] = $post_meta; + $post_data['post_metadata'] = $this->fill_in_post_meta( + $post_data['post_path'], + $post_meta); $post_data["post_file_dir"] = '/raw' . $post_data["post_path"]; @@ -92,8 +101,15 @@ class PostHandler extends MySQLAdapter { $post_path = $this->_sanitize_path($post_path); $post_content = $frontmatter_post->body(); + $post_metadata = $frontmatter_post->matter(); + $post_metadata = $this->fill_in_post_meta( + $post_path, + $post_metadata); + + $post_metadata['tags'][]= 'type:' . $post_metadata['type']; + if(basename($post_path) == "README.md") { $readme_metadata = []; if(isset($post_metadata['settings'])) { @@ -119,9 +135,6 @@ class PostHandler extends MySQLAdapter { move_uploaded_file($file_path, $this->data_directory . $post_path); break; - case "mddesc": - $this->save_markdown_post(chop($post_path, '.mddesc'), file_get_contents($file_path)); - break; default: $this->save_file($post_path, $file_path); } From dfd8e299cd64535fd80102f1407215ed51f4fa92 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Mon, 22 Jan 2024 16:48:52 +0100 Subject: [PATCH 12/12] feat: small tweaks --- www/.htaccess | 6 +++++- www/static/banner.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/www/.htaccess b/www/.htaccess index 20c4100..eb86f63 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -9,11 +9,15 @@ AddType text/plain .rss RewriteEngine On RewriteBase / -RewriteCond %{REQUEST_URI} !^/raw/ +RewriteCond %{REQUEST_URI} !^/(raw|static)/ RewriteRule ^.*\.(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$ raw/%{HTTP_HOST}%{REQUEST_URI} [L,END] RewriteRule ^/?raw/(.*)$ raw/%{HTTP_HOST}/$1 [L,END] +RewriteEngine On +RewriteCond %{HTTPS} !on +RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,END] + RewriteCond %{REQUEST_URI} !^/?(static|raw|robots\.txt).* RewriteRule (.*) router.php diff --git a/www/static/banner.js b/www/static/banner.js index 7af1dc4..1dc78c1 100644 --- a/www/static/banner.js +++ b/www/static/banner.js @@ -76,7 +76,7 @@ class BannerHandler { this.bannerDOM.style.opacity = 0; } fadeIn() { - this.bannerDOM.style.opacity = 0.3; + this.bannerDOM.style.opacity = this.currentBannerData.opacity || 0.3; } loadNextBanner() {