Jelajahi Sumber

use sqlite db instead of files on disk

Pi 4 bulan lalu
induk
melakukan
065bbd9660

+ 1 - 0
docker-compose.yml

@@ -5,6 +5,7 @@ services:
     volumes:
       - ./home-sqlpage/:/var/www/
       - ./home-sqlpage.json:/etc/sqlpage/sqlpage.json
+      - ./home-sqlpage/sqlpage/migrations:/etc/sqlpage/migrations
     expose:
       - 8080
     networks:

+ 7 - 3
home-sqlpage/clip.sql

@@ -14,8 +14,12 @@ SET hash = CASE $hash = ''
   WHEN TRUE THEN NULL
   ELSE $hash
 END;
-SET inner = CASE $hash IS NULL
-  WHEN TRUE THEN 'sqlpage/Link.sql'
-  ELSE 'sqlpage/link.sql'
+SET content = $paste;
+SET inner = CASE COALESCE($content,'') <> '' AND COALESCE($action, '') = 'Paste'
+  WHEN TRUE THEN 'clip/save.sql'
+  ELSE CASE $hash IS NULL
+    WHEN TRUE THEN 'sqlpage/Link.sql'
+    ELSE 'sqlpage/link.sql'
+  END
 END;
 SELECT 'dynamic' AS component, sqlpage.run_sql($inner) AS properties;

+ 3 - 1
home-sqlpage/clip/form.sql

@@ -1,3 +1,5 @@
+SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/QR.sql') AS properties;
+
 SELECT 'button' AS component;
 SELECT 'Open' AS title
 , 1 AS width
@@ -16,7 +18,7 @@ SELECT 'Download' AS title
 ;
 
 SELECT 'form' AS component
-, '/clip' AS action
+, '/clip.sql' AS action
 , '' AS validate
 , 'post' AS method
 ;

+ 1 - 1
home-sqlpage/clip/open.sql

@@ -31,7 +31,7 @@ SELECT 'New Clip' AS title
 ;
 SELECT 'form' AS component
 , 'open-clip' AS id
-, '/clip' AS action
+, '/clip.sql' AS action
 , '' AS validate
 , 'get' AS method
 ;

+ 32 - 0
home-sqlpage/clip/save.sql

@@ -0,0 +1,32 @@
+SET request = json_object(
+    'method', 'POST',
+    'url', 'https://shandan.one/hash',
+    'headers', json_object(),
+    'body', json_object(
+        'data', $content,
+        'person', $tool
+    )
+);
+SET hash = sqlpage.fetch($request);
+SET fallback = 'https://shandan.one/clip/' || sqlpage.url_encode($hash);
+SET request = json_object(
+    'method', 'POST',
+    'url', 'https://shandan.one/qr',
+    'headers', json_object(),
+    'body', json_object(
+        'data', $content,
+        'fallback', $fallback
+    )
+);
+SET qr = sqlpage.fetch($request);
+SELECT 'debug' AS component;
+SELECT $hash;
+SELECT $qr;
+INSERT INTO clip (hash, content, qr, created) VALUES ($hash, $content, $qr, CURRENT_TIMESTAMP)
+ON CONFLICT DO
+UPDATE SET
+  content = excluded.content,
+  created = excluded.created,
+  qr = excluded.qr
+WHERE excluded.created > clip.created;
+SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/link.sql') AS properties;

+ 0 - 156
home-sqlpage/index.sql

@@ -1,159 +1,3 @@
-DROP TABLE IF EXISTS sqlpage_cards;
-CREATE TABLE IF NOT EXISTS sqlpage_cards (
-	link text,
-	title text,
-	top_image text,
-	description_md text,
-	color text,
-	grouping int
-);
-INSERT INTO sqlpage_cards
-VALUES
-(
-	'/news/rss.html',
-	'News Feed',
-	'',
-	'Notable events but not weather or sports',
-	'',
-	1
-),
-(
-	'/discovery/rss.html',
-	'Discovery Feed',
-	'',
-	'Cool and inspirational articles',
-	'',
-	1
-),
-(
-	'/humour/rss.html',
-	'Humour Feed',
-	'',
-	'Humourous articles, memes or anything funny',
-	'rss',
-	1
-),
-(
-	'/clip?',
-	'Clipboard',
-	'https://shandan.one/static/clip/clip-favicon_square.svg',
-	'Paste snippets to share via tiny URL',
-	'green',
-	2
-),
-(
-	'/goto?',
-	'Short URL',
-	'https://shandan.one/static/goto/chain-link2fr-3-2.svg',
-	'Make long URLs shorter and easy to type and say',
-	'pinterest',
-	2
-),
-(
-	'/upload?',
-	'Share a File',
-	'https://shandan.one/static/upload/upload-favicon_square.svg',
-	'Upload a file and generate a short URL to share easily',
-	'yellow',
-	2
-),
-(
-	'https://wol.shandan.one?location=outside',
-	'Wake a Device',
-	'',
-	'Wake a device from [home](https://wol.shandan.one?location=home) or [outside](https://wol.shandan.one?location=outside)',
-	'red',
-	3
-),
-(
-	'https://shandan.one/grocery/internal/apply.sql?groups[]=Fish,%20Meat,%20Eggs&apply=Apply&title=Trend',
-	'Trending Prices',
-	'https://shandan.one/grocery/favicon_square.svg',
-	'Plot charts showing historic price data',
-	'youtube',
-	3
-),
-(
-	'https://shandan.one/pgadmin4',
-	'pgAdmin',
-	'https://raw.githubusercontent.com/postgres/pgadmin4/c1ba645dceed5c9551a5f408e37a14d1041ee598/web/pgadmin/static/favicon.ico',
-	'Manage And access postgresql databases',
-	'azure',
-	3
-),
-(
-	'https://shandan.one/guacamole',
-	'Guacamole',
-	'https://raw.githubusercontent.com/apache/guacamole-website/main/images/logos/guac-classic-logo.svg',
-	'Remote desktop',
-	'teal',
-	3
-),
-(
-	'https://gogs.shandan.one',
-	'Gogs',
-	'https://gogs.shandan.one/img/favicon.png',
-	'Manage and access git repositories',
-	'yellow',
-	3
-),
-(
-	'https://syncthing.shandan.one',
-	'Syncthing',
-	'https://syncthing.net/img/logo-horizontal.svg',
-	'Monitor and configure file shares',
-	'blue',
-	3
-),
-(
-	'https://shandan.one/wekan',
-	'WeKan',
-	'https://raw.githubusercontent.com/wekan/wekan/master/public/logo-header.png',
-	'Kanban board
-
-Manage projects and tasks',
-	'teal',
-	3
-),
-(
-	'https://mouse.shandan.one/#remote-mouse',
-	'Remote Touchpad',
-	'https://raw.githubusercontent.com/Unrud/remote-touchpad/master/webdata/icon.png',
-	'Use device as touchpad
-
-Turn your device''s touchscreen into a remote touchpad',
-	'github',
-	3
-),
-(
-	'https://gateway.shandan.one',
-	'Gateway',
-	'https://gateway.shandan.one/favicon.ico?t=6dcc8b66',
-	'Access the gateway
-
-Manage local LAN and internet connection settings',
-	'cyan',
-	3
-),
-(
-	'https://listgarden.shandan.one',
-	'ListGarden',
-	'https://www.wikicalc.org/images/listgardenlogo48.gif',
-	'Manage RSS Feeds
-
-Publish news items and create new feeds',
-	'green',
-	3
-),
-(
-	'https://shandan.one/pyapi/random',
-	'Prayer Generator',
-	'',
-	'Generate a template prayer following the form of the model prayer outlined in Matthew&nbsp;6:9‑13 and Luke&nbsp;11:2‑4',
-	'orange',
-	3
-)
-;
 SELECT 'shell' AS component
 , 'dark' AS theme
 , 'Portal' AS title

+ 0 - 4
home-sqlpage/sqlpage/Link.sql

@@ -9,10 +9,6 @@ SELECT 'text' AS component
 </div>' AS html
 ;
 
-SET content = CASE $tool
-  WHEN 'clip' THEN $paste
-  ELSE NULL
-END;
 SET inner = CASE $hash IS NULL
   WHEN TRUE THEN $tool||'/form.sql'
   ELSE 'sqlpage/validate.sql'

+ 157 - 0
home-sqlpage/sqlpage/migrations/000_index.sql

@@ -0,0 +1,157 @@
+DROP TABLE IF EXISTS sqlpage_cards;
+CREATE TABLE IF NOT EXISTS sqlpage_cards (
+	link text,
+	title text,
+	top_image text,
+	description_md text,
+	color text,
+	grouping int
+);
+INSERT INTO sqlpage_cards
+VALUES
+(
+	'/news/rss.html',
+	'News Feed',
+	'',
+	'Notable events but not weather or sports',
+	'',
+	1
+),
+(
+	'/discovery/rss.html',
+	'Discovery Feed',
+	'',
+	'Cool and inspirational articles',
+	'',
+	1
+),
+(
+	'/humour/rss.html',
+	'Humour Feed',
+	'',
+	'Humourous articles, memes or anything funny',
+	'rss',
+	1
+),
+(
+	'/clip?',
+	'Clipboard',
+	'https://shandan.one/static/clip/clip-favicon_square.svg',
+	'Paste snippets to share via tiny URL',
+	'green',
+	2
+),
+(
+	'/goto?',
+	'Short URL',
+	'https://shandan.one/static/goto/chain-link2fr-3-2.svg',
+	'Make long URLs shorter and easy to type and say',
+	'pinterest',
+	2
+),
+(
+	'/upload?',
+	'Share a File',
+	'https://shandan.one/static/upload/upload-favicon_square.svg',
+	'Upload a file and generate a short URL to share easily',
+	'yellow',
+	2
+),
+(
+	'https://wol.shandan.one?location=outside',
+	'Wake a Device',
+	'',
+	'Wake a device from [home](https://wol.shandan.one?location=home) or [outside](https://wol.shandan.one?location=outside)',
+	'red',
+	3
+),
+(
+	'https://shandan.one/grocery/internal/apply.sql?groups[]=Fish,%20Meat,%20Eggs&apply=Apply&title=Trend',
+	'Trending Prices',
+	'https://shandan.one/grocery/favicon_square.svg',
+	'Plot charts showing historic price data',
+	'youtube',
+	3
+),
+(
+	'https://shandan.one/pgadmin4',
+	'pgAdmin',
+	'https://raw.githubusercontent.com/postgres/pgadmin4/c1ba645dceed5c9551a5f408e37a14d1041ee598/web/pgadmin/static/favicon.ico',
+	'Manage And access postgresql databases',
+	'azure',
+	3
+),
+(
+	'https://shandan.one/guacamole',
+	'Guacamole',
+	'https://raw.githubusercontent.com/apache/guacamole-website/main/images/logos/guac-classic-logo.svg',
+	'Remote desktop',
+	'teal',
+	3
+),
+(
+	'https://gogs.shandan.one',
+	'Gogs',
+	'https://gogs.shandan.one/img/favicon.png',
+	'Manage and access git repositories',
+	'yellow',
+	3
+),
+(
+	'https://syncthing.shandan.one',
+	'Syncthing',
+	'https://syncthing.net/img/logo-horizontal.svg',
+	'Monitor and configure file shares',
+	'blue',
+	3
+),
+(
+	'https://shandan.one/wekan',
+	'WeKan',
+	'https://raw.githubusercontent.com/wekan/wekan/master/public/logo-header.png',
+	'Kanban board
+
+Manage projects and tasks',
+	'teal',
+	3
+),
+(
+	'https://mouse.shandan.one/#remote-mouse',
+	'Remote Touchpad',
+	'https://raw.githubusercontent.com/Unrud/remote-touchpad/master/webdata/icon.png',
+	'Use device as touchpad
+
+Turn your device''s touchscreen into a remote touchpad',
+	'github',
+	3
+),
+(
+	'https://gateway.shandan.one',
+	'Gateway',
+	'https://gateway.shandan.one/favicon.ico?t=6dcc8b66',
+	'Access the gateway
+
+Manage local LAN and internet connection settings',
+	'cyan',
+	3
+),
+(
+	'https://listgarden.shandan.one',
+	'ListGarden',
+	'https://www.wikicalc.org/images/listgardenlogo48.gif',
+	'Manage RSS Feeds
+
+Publish news items and create new feeds',
+	'green',
+	3
+),
+(
+	'https://shandan.one/pyapi/random',
+	'Prayer Generator',
+	'',
+	'Generate a template prayer following the form of the model prayer outlined in Matthew&nbsp;6:9‑13 and Luke&nbsp;11:2‑4',
+	'orange',
+	3
+)
+;
+

+ 7 - 0
home-sqlpage/sqlpage/migrations/001_clip.sql

@@ -0,0 +1,7 @@
+DROP TABLE IF EXISTS clip;
+CREATE TABLE IF NOT EXISTS clip(
+  hash text PRIMARY KEY,
+  content text,
+  qr text,
+  created timestamp
+);

+ 7 - 22
home-sqlpage/sqlpage/validate.sql

@@ -1,30 +1,15 @@
-SET url = 'https://shandan.one/clip/validate?hash=' || sqlpage.url_encode($hash);
-SET fallback = 'https://shandan.one/clip/' || sqlpage.url_encode($hash);
-SET api_results = sqlpage.fetch($url);
-SET content = $api_results->>'o';
-SET err = $api_results->>'err';
+SET content = (SELECT content FROM clip WHERE hash = $hash);
 
-SET request = json_object(
-    'method', 'POST',
-    'url', 'https://shandan.one/qr',
-    'headers', json_object(),
-    'body', json_object(
-        'data', $content,
-        'fallback', $fallback
-    )
-);
-SET qr = sqlpage.fetch($request);
-SELECT 'dynamic' AS component, sqlpage.run_sql('sqlpage/QR.sql') AS properties;
 SET inner = CASE $err IS NULL
   WHEN TRUE THEN $tool||'/form.sql'
   ELSE 'sqlpage/status.sql'
 END;
-SET status = CASE $err IS NULL
-  WHEN TRUE THEN NULL
-  ELSE $err->>0
+SET status = CASE $content IS NULL
+  WHEN TRUE THEN '404'
+  ELSE NULL
 END;
-SET info = CASE $err IS NULL
-  WHEN TRUE THEN NULL
-  ELSE $err->>1
+SET info = CASE $content IS NULL
+  WHEN TRUE THEN 'No such '||$tool||': '||$hash
+  ELSE NULL
 END;
 SELECT 'dynamic' AS component, sqlpage.run_sql($inner) AS properties;

+ 10 - 1
rest/pyapi.py

@@ -13,7 +13,7 @@ from bottle import (
 from linkpreview import link_preview
 
 from .validate import CLIP_SIZE_LIMIT, _validate, get_file_mimetype, get_file_size, get_filename, validate, validate_file, validate_parameter, validate_url
-from .hash_util import normalize_base32
+from .hash_util import normalize_base32, blake, bytes_to_base32
 from .save import save, save_upload
 from .qr import get_qr_code
 from json import dumps, load
@@ -25,6 +25,15 @@ DOMAIN = "shandan.one"
 PORT = ""
 LOCATION = SCHEME + (f"{HOST}." if HOST else "") + DOMAIN + (f":{PORT}" if PORT else "")
 
+@route('/hash', method=['POST'])
+def get_hash():
+    data = dict(map(
+        lambda x: (x[0], x[1].encode('utf-8')),
+        load(request.body).items()
+    ))
+    _bytes = blake(**data)
+    return bytes_to_base32(_bytes)
+
 @route('/normalize', method=['GET'])
 def normalize():
     _hash = request.params.hash