feat: ✨ add post access usage metrics
This commit is contained in:
parent
eb87a78625
commit
94b65aec8c
3 changed files with 161 additions and 74 deletions
|
@ -26,6 +26,20 @@ CREATE TABLE posts (
|
||||||
INDEX(post_path_depth, post_path)
|
INDEX(post_path_depth, post_path)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE path_access_counts (
|
||||||
|
post_path VARCHAR(255),
|
||||||
|
agent VARCHAR(255),
|
||||||
|
|
||||||
|
path_last_access_time DATETIME NOT NULL
|
||||||
|
DEFAULT CURRENT_TIMESTAMP
|
||||||
|
ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
path_access_count INTEGER DEFAULT 0,
|
||||||
|
path_processing_time DOUBLE PRECISION DEFAULT 0,
|
||||||
|
|
||||||
|
PRIMARY KEY(post_path, agent),
|
||||||
|
INDEX(path_last_access_time)
|
||||||
|
);
|
||||||
|
|
||||||
INSERT INTO posts (post_path, post_path_depth, post_metadata, post_content)
|
INSERT INTO posts (post_path, post_path_depth, post_metadata, post_content)
|
||||||
VALUES (
|
VALUES (
|
||||||
|
|
|
@ -103,6 +103,47 @@ class MySQLAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function log_post_access($post_path, $agent, $time) {
|
||||||
|
$qry = "
|
||||||
|
INSERT INTO path_access_counts
|
||||||
|
(post_path, agent,
|
||||||
|
path_access_count,
|
||||||
|
path_processing_time)
|
||||||
|
VALUES ( ?, ?, 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, "ssd", $post_path, $agent, $time);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_post_access_counters() {
|
||||||
|
$qry = "
|
||||||
|
SELECT post_path, agent, path_access_count, path_processing_time
|
||||||
|
FROM path_access_counts
|
||||||
|
WHERE path_last_access_time > ( CURRENT_TIMESTAMP - INTERVAL 10 MINUTE );
|
||||||
|
";
|
||||||
|
|
||||||
|
$data = $this->_exec($qry, "")->fetch_all(MYSQLI_ASSOC);
|
||||||
|
|
||||||
|
$out_data = [];
|
||||||
|
|
||||||
|
foreach($data AS $post_data) {
|
||||||
|
$path = $post_data['post_path'];
|
||||||
|
|
||||||
|
$agent_data = ($out_data[$path] ?? []);
|
||||||
|
|
||||||
|
$agent_data[$post_data['agent']] = [
|
||||||
|
'count' => $post_data['path_access_count'],
|
||||||
|
'time' => round($post_data['path_processing_time'], 6)
|
||||||
|
];
|
||||||
|
|
||||||
|
$out_data[$path] = $agent_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out_data;
|
||||||
|
}
|
||||||
function update_or_create_post($post_path, $post_metadata, $post_content) {
|
function update_or_create_post($post_path, $post_metadata, $post_content) {
|
||||||
$post_path = $this->_sanitize_path($post_path);
|
$post_path = $this->_sanitize_path($post_path);
|
||||||
$path_depth = substr_count($post_path, "/");
|
$path_depth = substr_count($post_path, "/");
|
||||||
|
|
180
www/router.php
180
www/router.php
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
$data_time_start = microtime(true);
|
||||||
|
|
||||||
require_once 'vendor/autoload.php';
|
require_once 'vendor/autoload.php';
|
||||||
require_once 'post_adapter.php';
|
require_once 'post_adapter.php';
|
||||||
|
|
||||||
|
@ -32,96 +34,126 @@ $twig->addRuntimeLoader(new class implements RuntimeLoaderInterface {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$SURI = $_SERVER['REQUEST_URI'];
|
function deduce_user_agent() {
|
||||||
|
$real_agent=$_SERVER['HTTP_USER_AGENT'];
|
||||||
|
|
||||||
if(preg_match('/^\/api\/admin/', $SURI)) {
|
if(preg_match('/(?:Mozilla|Chrome|Chromium)/', $real_agent)) {
|
||||||
header('Content-Type: application/json');
|
return "web";
|
||||||
|
|
||||||
$user_api_key = '';
|
|
||||||
if(isset($_GET['api_key'])) {
|
|
||||||
$user_api_key = $_GET['api_key'];
|
|
||||||
}
|
}
|
||||||
if(isset($_POST['api_key'])) {
|
elseif(preg_match('/(?:google)/', $real_agent)) {
|
||||||
$user_api_key = $_POST['api_key'];
|
return "bot/google";
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if($user_api_key != file_get_contents('secrets/api_admin_key')) {
|
return "unidentified";
|
||||||
http_response_code(401);
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
"authorized" => false
|
|
||||||
]);
|
|
||||||
|
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($SURI = '/api/admin/upload') {
|
$user_agent = deduce_user_agent();
|
||||||
$adapter->handle_upload($_POST['post_path'], $_FILES['post_data']['tmp_name']);
|
|
||||||
|
|
||||||
echo json_encode(["ok" => true]);
|
function generate_website($SURI) {
|
||||||
}
|
global $twig;
|
||||||
} elseif(preg_match('/^\/api/', $SURI)) {
|
global $adapter;
|
||||||
if(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
|
|
||||||
|
|
||||||
|
if(preg_match('/^\/api\/admin/', $SURI)) {
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo json_encode($adapter->get_post_by_path($match[1]));
|
|
||||||
|
|
||||||
} elseif(preg_match('/^\/api\/subposts(.*)$/', $SURI, $match)) {
|
$user_api_key = '';
|
||||||
|
if(isset($_GET['api_key'])) {
|
||||||
|
$user_api_key = $_GET['api_key'];
|
||||||
|
}
|
||||||
|
if(isset($_POST['api_key'])) {
|
||||||
|
$user_api_key = $_POST['api_key'];
|
||||||
|
}
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
if($user_api_key != file_get_contents('secrets/api_admin_key')) {
|
||||||
echo json_encode(get_subposts($match[1]));
|
http_response_code(401);
|
||||||
} elseif($SURI == '/api/upload') {
|
|
||||||
|
|
||||||
echo $twig->render('upload.html');
|
echo json_encode([
|
||||||
}
|
"authorized" => false
|
||||||
} elseif(preg_match('/^\s*image/', $_SERVER['HTTP_ACCEPT'])) {
|
]);
|
||||||
header('Location: /raw' . $SURI);
|
|
||||||
exit(0);
|
|
||||||
} elseif(true) {
|
|
||||||
$post = $adapter->get_post_by_path($SURI);
|
|
||||||
|
|
||||||
if(!$post['found']) {
|
die();
|
||||||
echo $twig->render('post_types/rrror.html',[
|
}
|
||||||
|
|
||||||
|
if($SURI = '/api/admin/upload') {
|
||||||
|
$adapter->handle_upload($_POST['post_path'], $_FILES['post_data']['tmp_name']);
|
||||||
|
|
||||||
|
echo json_encode(["ok" => true]);
|
||||||
|
}
|
||||||
|
} elseif(preg_match('/^\/api/', $SURI)) {
|
||||||
|
if($SURI == '/api/post_counters') {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($adapter->get_post_access_counters());
|
||||||
|
} elseif(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($adapter->get_post_by_path($match[1]));
|
||||||
|
|
||||||
|
} elseif(preg_match('/^\/api\/subposts(.*)$/', $SURI, $match)) {
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode(get_subposts($match[1]));
|
||||||
|
} elseif($SURI == '/api/upload') {
|
||||||
|
|
||||||
|
echo $twig->render('upload.html');
|
||||||
|
}
|
||||||
|
} elseif(preg_match('/^\s*image/', $_SERVER['HTTP_ACCEPT'])) {
|
||||||
|
header('Location: /raw' . $SURI);
|
||||||
|
exit(0);
|
||||||
|
} elseif(true) {
|
||||||
|
$post = $adapter->get_post_by_path($SURI);
|
||||||
|
|
||||||
|
if(!$post['found']) {
|
||||||
|
echo $twig->render('post_types/rrror.html',[
|
||||||
|
"error_code" => '404 Hoard not found!',
|
||||||
|
"error_description" => "Well, we searched
|
||||||
|
far and wide for `" . $SURI . "` but
|
||||||
|
somehow it must have gotten lost... Sorry!",
|
||||||
|
"post" => $post
|
||||||
|
]);
|
||||||
|
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($post['post_metadata']['type'] == 'directory') {
|
||||||
|
if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) {
|
||||||
|
header('Location: ' . $match[1] . '/' . $match[2]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $twig->render('post_types/directory.html', [
|
||||||
|
"post" => $post,
|
||||||
|
"subposts" => $adapter->get_subposts_by_path($SURI)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
elseif($post['post_metadata']['type'] == 'text/markdown') {
|
||||||
|
echo $twig->render('post_types/markdown.html', [
|
||||||
|
"post" => $post
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
elseif($post['post_metadata']['type'] == 'image') {
|
||||||
|
echo $twig->render('post_types/image.html', [
|
||||||
|
"post" => $post
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo $twig->render('rrror.html',[
|
||||||
"error_code" => '404 Hoard not found!',
|
"error_code" => '404 Hoard not found!',
|
||||||
"error_description" => "Well, we searched
|
"error_description" => "Well, we searched
|
||||||
far and wide for `" . $SURI . "` but
|
far and wide for `" . $SURI . "` but
|
||||||
somehow it must have gotten lost... Sorry!",
|
somehow it must have gotten lost... Sorry!"
|
||||||
"post" => $post
|
]);
|
||||||
]);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($post['post_metadata']['type'] == 'directory') {
|
|
||||||
if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) {
|
|
||||||
header('Location: ' . $match[1] . '/' . $match[2]);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo $twig->render('post_types/directory.html', [
|
|
||||||
"post" => $post,
|
|
||||||
"subposts" => $post['subposts']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
elseif($post['post_metadata']['type'] == 'text/markdown') {
|
|
||||||
echo $twig->render('post_types/markdown.html', [
|
|
||||||
"post" => $post,
|
|
||||||
"subposts" => $post['subposts']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
elseif($post['post_metadata']['type'] == 'image') {
|
|
||||||
echo $twig->render('post_types/image.html', [
|
|
||||||
"post" => $post
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
echo $twig->render('rrror.html',[
|
|
||||||
"error_code" => '404 Hoard not found!',
|
|
||||||
"error_description" => "Well, we searched
|
|
||||||
far and wide for `" . $SURI . "` but
|
|
||||||
somehow it must have gotten lost... Sorry!"
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generate_website($_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
|
$data_time_end = microtime(true);
|
||||||
|
|
||||||
|
$adapter->log_post_access($_SERVER['REQUEST_URI'],
|
||||||
|
$user_agent,
|
||||||
|
$data_time_end - $data_time_start)
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue