diff --git a/docker_dev/mysql_schema.sql b/docker_dev/mysql_schema.sql index 3afa716..77520a8 100644 --- a/docker_dev/mysql_schema.sql +++ b/docker_dev/mysql_schema.sql @@ -55,32 +55,33 @@ CREATE TABLE dev_post_markdown ( FULLTEXT(post_markdown) ); -CREATE TABLE dev_feeds ( - post_id INTEGER NOT NULL, - feed_key VARCHAR(32), - feed_id VARCHAR(40) NOT NULL, +CREATE TABLE dev_yaps ( + yap_id INTEGER AUTO_INCREMENT, + PRIMARY KEY(yap_id), - feed_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + post_path VARCHAR(255) NOT NULL, + yap_category VARCHAR(32) NOT NULL, + yap_tag VARCHAR(40) NOT NULL, - feed_metadata JSON DEFAULT NULL, + -- Uniqueness detection based on associated path, category and tag + yap_hash CHAR(32) AS (MD5(CONCAT(post_path, yap_category, yap_tag))), + CONSTRAINT YAPS_UNIQUE UNIQUE(yap_hash), - feed_text TEXT, + yap_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + yap_metadata JSON DEFAULT NULL, --- Primary key as true ID to allow for deterministic saving/recreating - CONSTRAINT PK_FEED PRIMARY KEY(post_id, feed_key, feed_id), - FOREIGN KEY(post_id) REFERENCES dev_posts(post_id) - ON DELETE CASCADE, + yap_text TEXT, -- Make it possible to look up changes from e.g. a commit hash inexpensively - INDEX(feed_id), + INDEX(yap_tag), -- Make it possible to look up specific post feeds efficiently (e.g. changelog) - INDEX(post_id, feed_key, feed_created_at), + INDEX(post_path, yap_category, yap_created_at), -- Make it possible to globally look up specific feeds efficiently - INDEX(feed_key, feed_created_at), + INDEX(yap_category, yap_created_at), -- And just in general, make searching feeds in a timeframe efficient - INDEX(feed_created_at), + INDEX(yap_created_at), - FULLTEXT(feed_text) + FULLTEXT(yap_text) ); CREATE TABLE analytics_summations ( diff --git a/www/src/db_handler/mysql_yaps_handler.php b/www/src/db_handler/mysql_yaps_handler.php new file mode 100644 index 0000000..39ef8af --- /dev/null +++ b/www/src/db_handler/mysql_yaps_handler.php @@ -0,0 +1,158 @@ +sql_connection = $sql_connection; + $this->hostname = $hostname; + $this->db_prefix = $db_prefix; + + $this->debugging = false; + } + + private function _exec($qery, $argtypes = '', ...$args) { + $stmt = $this->sql_connection->prepare($qery); + + if($argtypes != ""){ + $stmt->bind_param($argtypes, ...$args); + } + $stmt->execute(); + + return $stmt->get_result(); + } + + public function add_yap($yap_data_ext) { + # A little copy to prevent accidentally mutating + # external data + $yap_data = $yap_data_ext; + + if(!isset($yap_data['tag'])) { + throw new Exception('Yap is missing a tag!'); + } + if(!isset($yap_data['post'])) { + throw new Exception('Yap is missing a post!'); + } + if(!isset($yap_data['category'])) { + throw new Exception('Yap is missing a category!'); + } + + var_dump($yap_data); + + $yap_tag = $yap_data['tag']; + unset($yap_data['tag']); + + $yap_post = $yap_data['post']; + unset($yap_data['post']); + $yap_post = sanitize_post_path($yap_post); + + $yap_cateogry = $yap_data['category']; + unset($yap_data['category']); + + $yap_text = $yap_data['text'] ?? null; + unset($yap_data['text']); + + date_default_timezone_set('UTC'); + + $yap_created_at = $yap_data['created_at'] ?? null; + unset($yap_data['created_at']); + + $yap_data = json_encode($yap_data); + + $qry = " + INSERT INTO {$this->db_prefix}_yaps + (`post_path`, `yap_category`, `yap_tag`, + `yap_created_at`, `yap_metadata`, `yap_text` ) + VALUES ( ?, ?, ?, + COALESCE(?, NOW()), ?, ? ) AS new + + ON DUPLICATE KEY + UPDATE + {$this->db_prefix}_yaps.yap_metadata = new.yap_metadata, + {$this->db_prefix}_yaps.yap_text = new.yap_text; + "; + + $this->_exec($qry, + "ssssss", + $yap_post, $yap_cateogry, $yap_tag, + $yap_created_at, $yap_data, $yap_text); + } + + public function get_yaplist($args = []) { + + $category = $args['category'] ?? null; + $post = $args['post'] ?? $args['path'] ?? null; + $tag = $args['tag'] ?? null; + $before = $args['before'] ?? null; + $limit = $args['limit'] ?? null; + + + $qry_where = []; + $qry_where_data = []; + $qry_where_types = ''; + + if(isset($category)) { + if($category[-1] = '%') { + $qry_where []= 'yap_category LIKE ?'; + } + else { + $qry_where []= 'yap_category = ?'; + } + $qry_where_data []= $category; + $qry_where_types .= 's'; + } + + if(isset($post)) { + if($post[-1] = '%') { + $qry_where []= 'post_path LIKE ?'; + } + else { + $qry_where []= 'post_path = ?'; + } + + $qry_where_data []= $post; + $qry_where_types .= 's'; + } + + if(isset($tag)) { + $qry_where []= 'yap_tag = ?'; + $qry_where_data [] = $tag; + $qry_where_types .= 's'; + } + + if(isset($before)) { + $qry_where []= 'yap_created_at < ?'; + $qry_where_data []= $before; + $qry_where_types .= 's'; + } + + $limit = min(max(intval($limit ?? 30), 0), 30); + + $qry_where []= 'TRUE'; + + $qry = " + SELECT * + FROM {$this->db_prefix}_yaps + WHERE + " . implode(' AND ', $qry_where) . + " ORDER BY yap_created_at DESC + LIMIT ?"; + + $yaplist = $this->_exec($qry, + $qry_where_types . "i", + ...array_merge($qry_where_data, [$limit]))->fetch_all(MYSQLI_ASSOC); + + return $yaplist; + } +} + +?> \ No newline at end of file diff --git a/www/src/db_handler/yaps_interface.php b/www/src/db_handler/yaps_interface.php new file mode 100644 index 0000000..f9a2727 --- /dev/null +++ b/www/src/db_handler/yaps_interface.php @@ -0,0 +1,68 @@ + \ No newline at end of file diff --git a/www/src/serve/api.php b/www/src/serve/api.php index 67b297c..b108ec0 100644 --- a/www/src/serve/api.php +++ b/www/src/serve/api.php @@ -36,6 +36,37 @@ switch($API_FUNCTION) { echo $analytics_adapter->pop_analytics($delete = true); break; + + case 'db_yaps': + echo json_encode($yap_adapter->get_yaplist($_GET)); + break; + + case 'add_yap': + if( !isset($_POST['path']) + or !isset($_POST['yap_category']) + or !isset($_POST['yap_text'])) { + echo json_encode([ + 'status' => 'Missing paramters (must POST path, category and a text!)' + ]); + die(); + } + + $yap_data = [ + 'post' => $_POST['path'], + 'category' => $_POST['yap_category'], + 'text' => $_POST['yap_text'] + ]; + + $yap_data['tag'] = MD5($_POST['path'] . microtime()); + + $yap_adapter->add_yap($yap_data); + + echo json_encode([ + 'status' => '200 OK', + 'yap' => $yap_data + ]); + + break; case 'upload': if(!access_can_upload()) { diff --git a/www/src/serve/post.php b/www/src/serve/post.php index 84c10a5..4c409d3 100644 --- a/www/src/serve/post.php +++ b/www/src/serve/post.php @@ -54,10 +54,15 @@ function render_post($post, $args = []) { $args); } -if($REQUEST_PATH == '/upload') { +if($REQUEST_PATH == '/upload.php') { render_root_template('upload.html'); die(); } +if($REQUEST_PATH == '/yap.php') { + render_root_template('_dev_add_yap.html'); + die(); +} + if($REQUEST_PATH == '/search/') { $search_results = []; $display_type = 'none'; diff --git a/www/src/setup/db.php b/www/src/setup/db.php index c4757bb..52c5574 100644 --- a/www/src/setup/db.php +++ b/www/src/setup/db.php @@ -2,6 +2,8 @@ require_once 'db_handler/mysql_handler.php'; require_once 'db_handler/mysql_analytics_handler.php'; +require_once 'db_handler/mysql_yaps_handler.php'; + require_once 'db_handler/post_handler.php'; $db_params = $SITE_CONFIG['db']; @@ -32,6 +34,9 @@ $sql_adapter = new MySQLHandler($db_connection, $analytics_adapter = new MySQLAnalyticsHandler($db_connection, $SITE_CONFIG['site_defaults']['uri_prefix']); +$yap_adapter = new MySQL_YapsHandler($db_connection, + $SITE_CONFIG['site_defaults']['uri_prefix'], + $db_params['prefix']); $adapter = new PostHandler($sql_adapter); diff --git a/www/templates/_dev_add_yap.html b/www/templates/_dev_add_yap.html new file mode 100644 index 0000000..15662ef --- /dev/null +++ b/www/templates/_dev_add_yap.html @@ -0,0 +1,36 @@ + + +{% extends "root.html" %} + +{% block second_title %} +

YAP SOMETHIN'

+{% endblock %} + +{%block main_content%} +
+
+ + + + + + + + + + + + +
+ + Return data: + + + +
+{%endblock%}