Compare commits
2 commits
bbc093b497
...
f8af3c5c59
Author | SHA1 | Date | |
---|---|---|---|
f8af3c5c59 | |||
143c932c88 |
7 changed files with 333 additions and 1 deletions
|
@ -55,6 +55,35 @@ CREATE TABLE dev_post_markdown (
|
|||
FULLTEXT(post_markdown)
|
||||
);
|
||||
|
||||
CREATE TABLE dev_yaps (
|
||||
yap_id INTEGER AUTO_INCREMENT,
|
||||
PRIMARY KEY(yap_id),
|
||||
|
||||
post_path VARCHAR(255) NOT NULL,
|
||||
yap_category VARCHAR(32) NOT NULL,
|
||||
yap_tag VARCHAR(40) NOT 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),
|
||||
|
||||
yap_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
yap_metadata JSON DEFAULT NULL,
|
||||
|
||||
yap_text TEXT,
|
||||
|
||||
-- Make it possible to look up changes from e.g. a commit hash inexpensively
|
||||
INDEX(yap_tag),
|
||||
-- Make it possible to look up specific post feeds efficiently (e.g. changelog)
|
||||
INDEX(post_path, yap_category, yap_created_at),
|
||||
-- Make it possible to globally look up specific feeds efficiently
|
||||
INDEX(yap_category, yap_created_at),
|
||||
-- And just in general, make searching feeds in a timeframe efficient
|
||||
INDEX(yap_created_at),
|
||||
|
||||
FULLTEXT(yap_text)
|
||||
);
|
||||
|
||||
CREATE TABLE analytics_summations (
|
||||
time_bucket DATETIME NOT NULL,
|
||||
metric VARCHAR(16) NOT NULL,
|
||||
|
|
158
www/src/db_handler/mysql_yaps_handler.php
Normal file
158
www/src/db_handler/mysql_yaps_handler.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
require_once 'db_interface.php';
|
||||
require_once 'yaps_interface.php';
|
||||
|
||||
class MySQL_YapsHandler
|
||||
implements YapsInterface {
|
||||
|
||||
private $debugging;
|
||||
|
||||
private $sql_connection;
|
||||
private $hostname;
|
||||
private $db_prefix;
|
||||
|
||||
function __construct($sql_connection, $hostname, $db_prefix) {
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
68
www/src/db_handler/yaps_interface.php
Normal file
68
www/src/db_handler/yaps_interface.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
interface YapsInterface {
|
||||
/* Yaps format:
|
||||
*
|
||||
* The yaps are even simpler versions of Postdata,
|
||||
* as they will have almost no defined metadata.
|
||||
*
|
||||
* The purpose of yaps is to provide very lightweight
|
||||
* additions to existing posts.
|
||||
*
|
||||
* The only properly defined fields are the following:
|
||||
* - Relevant Post ID
|
||||
* - yap category ("changelog", "comment", "build log", etc.)
|
||||
* - yap tag/hash (will e.g. use the Git Commit Hash for changelogs)
|
||||
* - yap creation time
|
||||
* - yap text
|
||||
* - other yap data (free-form :D)
|
||||
*
|
||||
* There will be little to no post-processing by the
|
||||
* database, as a lot is somewhat free-form.
|
||||
* No settings, no caching, etc.
|
||||
*
|
||||
* Instead, searching yaps will be a fair bit more
|
||||
* important, as they act as a lot of the feeds!
|
||||
* RSS/Atom will run over "changelog" yaps, and changelogs
|
||||
* will be displayed in most posts when present.
|
||||
* The system might also serve user comments, as well as
|
||||
* a posting alternative to social media feeds...
|
||||
* As well as a few WebMentions comments ^^'
|
||||
*
|
||||
* Oh yes, Yaps will always be ordered by time, descending.
|
||||
* It's feeds :P
|
||||
* */
|
||||
|
||||
/* Adds a yap, or overwrites/updates an existing one
|
||||
* The yap-data MUST include the following:
|
||||
* - post (string path!)
|
||||
* - tag
|
||||
* - category
|
||||
*
|
||||
* And may include:
|
||||
* - text (which is added to yap_text)
|
||||
* - created_at (if not set, NOW() is used)
|
||||
*
|
||||
* With other fields slapped into yap_metadata
|
||||
*/
|
||||
public function add_yap($yap_data);
|
||||
|
||||
/* Returns a list of yaps for the given filters.
|
||||
* - Category must always be set, but may be a "LIKE" wildcard
|
||||
* - post *may* be set. If set, only yaps for that given post are returned
|
||||
* - $since, which, if set and a valid timestamp, will return yaps after that time
|
||||
* - $limit, which should be obvious
|
||||
*
|
||||
* This function always returns an array of yaps, chronologically ordered.
|
||||
*
|
||||
* The following search args are supported:
|
||||
* - category: String, matched to the Yap Category. Can have a trailing % for LIKE search
|
||||
* - post: String, post path to look for. Can have a trailing % for LIKE search
|
||||
* - tag: Yap tag to look for.
|
||||
* - before: Datetime string. Shows yaps before the given date
|
||||
* - limit: Limit the number of returned yaps
|
||||
*/
|
||||
public function get_yaplist($args);
|
||||
}
|
||||
|
||||
?>
|
|
@ -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()) {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
36
www/templates/_dev_add_yap.html
Normal file
36
www/templates/_dev_add_yap.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
{% extends "root.html" %}
|
||||
|
||||
{% block second_title %}
|
||||
<h2> YAP SOMETHIN' </h2>
|
||||
{% endblock %}
|
||||
|
||||
{%block main_content%}
|
||||
<article>
|
||||
<form method="post" enctype="multipart/form-data"
|
||||
action="/api/add_yap"
|
||||
hx-target="#yap-result"
|
||||
hx-swap="innerHTML">
|
||||
|
||||
<label for="ACCESS_KEY"> Password: </label>
|
||||
<input type="password" id="ACCESS_KEY" name="ACCESS_KEY"/>
|
||||
|
||||
<label for="path"> Path: </label>
|
||||
<input type="text" id="path" name="path"/>
|
||||
<label for="yap_category"> Yap Category: </label>
|
||||
<input type="text" id="yap_category" name="yap_category"
|
||||
value="yap"/>
|
||||
|
||||
<textarea type="file" id="yap_text" name="yap_text">
|
||||
</textarea>
|
||||
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
|
||||
Return data:
|
||||
<code id="yap-result">
|
||||
|
||||
</code>
|
||||
</article>
|
||||
{%endblock%}
|
Loading…
Add table
Add a link
Reference in a new issue