diff --git a/www/.htaccess b/www/.htaccess index 6c5dbf4..3ceba7d 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -1,6 +1,9 @@ AddType text/plain .md +php_value upload_max_filesize 40M +php_value post_max_size 42M + RewriteEngine On RewriteBase / diff --git a/www/mysql_adapter.php b/www/mysql_adapter.php index 74b990d..d358e68 100644 --- a/www/mysql_adapter.php +++ b/www/mysql_adapter.php @@ -4,16 +4,19 @@ use Spatie\YamlFrontMatter\YamlFrontMatter; class MySQLAdapter { public $raw; + public $data_directory; function __construct() { $this->raw = mysqli_connect('mysql', 'root', 'example', 'dragon_fire'); + $this->data_directory = 'raw'; + if (!$this->raw) { - echo 'Connection failed
'; - echo 'Error number: ' . mysqli_connect_errno() . '
'; - echo 'Error message: ' . mysqli_connect_error() . '
'; - die(); + echo 'Connection failed
'; + echo 'Error number: ' . mysqli_connect_errno() . '
'; + echo 'Error message: ' . mysqli_connect_error() . '
'; + die(); } } @@ -24,40 +27,129 @@ class MySQLAdapter { return $stmt->get_result(); } - + function _prepare_post_data($post_data) { - if($post_data == null) { - $post_data = [ - "found" => false + if($post_data == null) { + return [ + "found" => false ]; } - else { - $post_data["found"] = true; - $post_data["post_metadata"] = json_decode($post_data["post_metadata"]); - } + $post_data["found"] = true; + $post_data["post_basename"] = basename($post_data["post_path"]); + + $post_meta = json_decode($post_data["post_metadata"], true) ?? []; + + $post_meta["title"] ??= basename($post_data["post_path"]); + + if(!isset($post_meta['type'])) { + $type = null; + + $ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION); + + if($ext == '') { + $type = 'directory'; + } elseif($ext == 'md') { + $type = 'text/markdown'; + } + + $post_meta['type'] = $type; + } + + $post_data["post_content"] ??= ''; + $post_data["post_file_dir"] = '/' . $this->data_directory . $post_data["post_path"]; + + $post_data['post_metadata'] = $post_meta; + return $post_data; } - function save_markdown_post($post_path, $post_data) { - $frontmatter_post = YamlFrontMatter::parse($post_data); + function _fill_post_descriptors($post_data) { - $post_path = chop($post_path, '/'); - $path_depth = substr_count($post_path, "/"); + switch(($post_data['post_metadata']['type'] ?? '')) { + case 'directory': + $readme = $this->get_post_by_path($post_data['post_path'] . '/README.md', false); + $post_data['readme'] = $readme; + + if($readme['found']) { + $post_data['post_metadata']['title'] = $readme['post_metadata']['title']; + } + break; - $post_content = $frontmatter_post->body(); - $post_metadata = $frontmatter_post->matter(); + case 'file': + $post_data['descriptor'] = $this->get_post_by_path($post_data['post_path'] . '.md', false); + break; + } - $post_metadata['type'] = 'text/markdown'; + return $post_data; + } - var_dump($post_path, $post_content, $post_metadata); - - $qry = " + function ensure_directory($directory) { + $data_directory = $this->data_directory . $directory; + + is_dir($data_directory) || mkdir($data_directory, 0777, true); + + $insert_statement = " INSERT INTO posts (post_path, post_path_depth, post_metadata, post_content) VALUES - ( ?, ?, ?, ?) AS new - ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content;"; + (?, ?, ?, '') AS new + ON DUPLICATE KEY UPDATE post_path=new.post_path + "; + + $json_metadata = json_encode(["type" => 'directory']); + + while(strlen($directory) > 1) { + try { + echo "Inserting dir " . $directory . "\n"; + + $this->_exec($insert_statement, "sis", + $directory, substr_count($directory, '/'), + $json_metadata); + + } + catch(Exception $e) { + } + $directory = dirname($directory); + } + } + + function ensure_post_placeholder($post_path, $post_metadata) { + $post_path = chop($post_path, '/'); + $path_depth = substr_count($post_path, "/"); + + $this->ensure_directory(dirname($post_path)); + + echo "Bumping post placeholder " . $post_path . "\n"; + + $qry = " + INSERT INTO posts + (post_path, post_path_depth, post_metadata, post_content) + VALUES + ( ?, ?, ?, ?) AS new + ON DUPLICATE KEY UPDATE post_path=new.post_path;"; + + $this->_exec($qry, "siss", + $post_path, + $path_depth, + json_encode($post_metadata), + ''); + } + + function create_post_entry($post_path, $post_metadata, $post_content) { + $post_path = chop($post_path, '/'); + $path_depth = substr_count($post_path, "/"); + + $this->ensure_directory(dirname($post_path)); + + echo "Creating post entry " . $post_path . "\n"; + + $qry = " + INSERT INTO posts + (post_path, post_path_depth, post_metadata, post_content) + VALUES + ( ?, ?, ?, ?) AS new + ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content;"; $this->_exec($qry, "siss", $post_path, @@ -66,12 +158,60 @@ class MySQLAdapter { $post_content); } + function save_markdown_post($post_path, $post_data) { + $frontmatter_post = YamlFrontMatter::parse($post_data); + $post_path = chop($post_path, '/'); + + $post_content = $frontmatter_post->body(); + $post_metadata = $frontmatter_post->matter(); + + if(basename($post_path) == "README.md") { + $readme_metadata = $frontmatter_post->matter(); + $readme_metadata['type'] = $post_metadata['readme_type'] ?? 'directory'; + + $this->create_post_entry(dirname($post_path), $readme_metadata, ''); + + $post_metadata['type'] = 'text/markdown'; + } + + $post_metadata['type'] ??= 'text/markdown'; + + $this->create_post_entry($post_path, $post_metadata, $post_content); + file_put_contents($this->data_directory . $post_path, + $post_data); + + } + + function save_file($post_path, $file_path) { + $post_metadata = ["type" => 'file']; + $post_path = chop($post_path, '/'); + + $this->ensure_post_placeholder($post_path, $post_metadata, ''); + + copy($file_path, $this->data_directory . $post_path); + } + + function handle_upload($post_path, $file_path) { + $ext = pathinfo($post_path, PATHINFO_EXTENSION); + + switch($ext) { + case "md": + $this->save_markdown_post($post_path, file_get_contents($file_path)); + break; + default: + $this->save_file($post_path, $file_path); + } + } + function get_post_by_path($post_path, $with_subposts = true) { $qry = "SELECT * FROM posts WHERE post_path = ?"; $post_path = chop($post_path, '/'); - $post_data = $this->_prepare_post_data($this->_exec($qry, "s", $post_path)->fetch_assoc()); + $post_data = $this->_exec($qry, "s", $post_path)->fetch_assoc(); + $post_data = $this->_prepare_post_data($post_data); + + $post_data = $this->_fill_post_descriptors($post_data); if($with_subposts) { $post_data['subposts'] = $this->get_subposts_by_path($post_path); @@ -87,7 +227,7 @@ class MySQLAdapter { $path_depth = substr_count($path, "/"); - $qry = "SELECT post_path, post_metadata + $qry = "SELECT post_path, post_metadata, post_update_time FROM posts WHERE (post_path LIKE CONCAT(?,'/%')) AND post_path_depth = ?