diff --git a/Makefile b/Makefile index 0c8ed9d..582eae6 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,8 @@ built_parts=$(part_files:src/%=$(app_root)/%) built_pages=$(page_files:src/pages/%.etlua=$(app_root)/pages/%.etlua) built_sql=$(sql_files:src/sql/%.sql=$(app_root)/sql/%.sql) built=$(built_files) $(built_sql) $(built_pages) $(built_tests) +sql_create_table_files=$(sql_files:src/sql/create_table_%.sql=doc/schema/%.dot) +sql_docs=$(sql_create_table_files) initscript=/lib/systemd/system/smr.service config=$(conf_path)/smr.conf built_bin=$(smr_bin_path)/smr.so @@ -170,14 +172,17 @@ test: $(built) ## run the unit tests $(Q)$(CD) $(app_root) && busted -v --no-keep-going --exclude-tags "slow,todo,working" cov: $(built) ## code coverage (based on unit tests) - $(Q)$(RM) $(kore_chroot)/luacov.stats.out - $(Q)$(CD) $(kore_chroot) && busted -v -c --no-keep-going --exclude-tags slow - $(Q)$(CD) $(kore_chroot) && luacov endpoints/ - $(Q)$(ECHO) "open kore_chroot/luacov.report.out to view coverage results." + $(Q)$(RM) $(app_root)/luacov.stats.out + $(Q)$(CD) $(app_root) && busted -v -c --no-keep-going --exclude-tags "slow,todo,working" + $(Q)$(CD) $(app_root) && luacov endpoints/ + $(Q)$(ECHO) "open $(app_root)/luacov.report.out to view coverage results." -doc: +$(sql_docs) : doc/schema/%.dot : src/sql/create_table_%.sql + cat $< | tools/doc_sql.sh > $@ + +doc: $(sql_docs) rm -rf .trblcache - ~/Programs/trbldoc/trbldoc.sh src + ~/Programs/trbldoc/trbldoc.sh doc src README.md cd .trblcache/built && python3 -m http.server .PHONY: doc diff --git a/README.md b/README.md index 557bf7b..94e814d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ concerns with pastebin.com taking down certain kinds of content. SMR aims to be small, fast, and secure. It is built on top of [Kore](https://kore.io), using [luajit](https://luajit.org) to expose a Lua programming environment. It uses [sqlite3](https://sqlite.org) as it's database. SMR is implemented in about -4k SLOC and is expected to never exceed 5k SLOC. Contributions welcome. +5k SLOC. Contributions welcome. Language|files|blank|comment|code :-------|-------:|-------:|-------:|-------: diff --git a/doc/hooks.md b/doc/hooks.md index a2ecde2..4bdb3ca 100644 --- a/doc/hooks.md +++ b/doc/hooks.md @@ -1,3 +1,6 @@ +!{ md +@file doc/hooks + # Hooks Various functions that are exposed to the lua environment. These functions may be detoured to effect their behavior. @@ -17,4 +20,4 @@ authenticate(data :: table) :: number | nil, string ``` Called when a user attempts to log in. Return a number, userid if the login is successful, or nil and an error message if the login is not successful. By default, smr puts "user" and "passfile" fields into the data table. - +!} diff --git a/doc/schema/.gitignore b/doc/schema/.gitignore new file mode 100644 index 0000000..cf65889 --- /dev/null +++ b/doc/schema/.gitignore @@ -0,0 +1 @@ +*.dot diff --git a/src/lua/db.lua b/src/lua/db.lua index b1e3ff2..8d7304f 100644 --- a/src/lua/db.lua +++ b/src/lua/db.lua @@ -7,6 +7,13 @@ Does most of the database interaction. Creates default empty database during configure() Notably, holds a connection to the open sqlite3 database in .conn ]] + +--[[ sh +@name sql/table +echo "digraph schema {" \ + "$(cat doc/schema/*.dot)" \ + "}" | dot -Tsvg +]] local sql = require("lsqlite3") local queries = require("queries") diff --git a/src/sql/create_table_authors.sql b/src/sql/create_table_authors.sql index 24fe2eb..c3f37e5 100644 --- a/src/sql/create_table_authors.sql +++ b/src/sql/create_table_authors.sql @@ -1,11 +1,18 @@ /* md @name sql/table/authors -If/when an author deletes their account, all posts +If an author deletes their account, all posts and comments by that author are also deleted (on delete cascade) this is intentional. This also means that all comments by other users on a post an author makes will also be deleted. */ + +/* sh +@name sql/table/authors +echo "digraph authors {" \ + "$(cat doc/schema/authors.dot)" \ + "}" | dot -Tsvg +*/ CREATE TABLE IF NOT EXISTS authors ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT UNIQUE ON CONFLICT FAIL, diff --git a/src/sql/create_table_comments.sql b/src/sql/create_table_comments.sql index 565bbdd..5f0928f 100644 --- a/src/sql/create_table_comments.sql +++ b/src/sql/create_table_comments.sql @@ -1,9 +1,19 @@ -/* +/* md +@name sql/table/comments Comments on a post. When an author deletes their account or the posts this comment is posted on is deleted, this comment will also be deleted. */ + +/* sh +@name sql/table/comments +echo "digraph comments{" \ + "$(cat doc/schema/authors.dot)" \ + "$(cat doc/schema/posts.dot)" \ + "$(cat doc/schema/comments.dot)" \ + "}" | dot -Tsvg +*/ CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, postid REFERENCES posts(id) ON DELETE CASCADE, diff --git a/src/sql/create_table_images.sql b/src/sql/create_table_images.sql index c72b5ba..20f712e 100644 --- a/src/sql/create_table_images.sql +++ b/src/sql/create_table_images.sql @@ -1,6 +1,15 @@ -/* +/* md +@name sql/table/images We may want to store images one day. This is unused for now */ + +/* sh +@name sql/table/images +echo "digraph images {" \ + "$(cat doc/schema/images.dot)" \ + "$(cat doc/schema/authors.dot)" \ + "}" | dot -Tsvg +*/ CREATE TABLE IF NOT EXISTS images ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT, diff --git a/src/sql/create_table_posts.sql b/src/sql/create_table_posts.sql index b898960..352f65c 100644 --- a/src/sql/create_table_posts.sql +++ b/src/sql/create_table_posts.sql @@ -1,4 +1,5 @@ -/* +/* md +@name sql/table/posts If/when an author delets their account, all posts and comments by that author are also deleted (on delete cascade) this is intentional. This also @@ -9,6 +10,14 @@ Post text uses zlib compression Unlisted hashes are SHAv3 521 */ + +/* sh +@name sql/table/posts +echo "digraph comments{" \ + "$(cat doc/schema/authors.dot)" \ + "$(cat doc/schema/posts.dot)" \ + "}" | dot -Tsvg +*/ CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, post_text BLOB, diff --git a/src/sql/create_table_raw_text.sql b/src/sql/create_table_raw_text.sql index 5ca8c51..0513d41 100644 --- a/src/sql/create_table_raw_text.sql +++ b/src/sql/create_table_raw_text.sql @@ -1,7 +1,18 @@ -/* -Store the raw text so people can download it later, maybe -we can use it for "download as image" or "download as pdf" -in the future too. Stil stored zlib compressed +/* md +@name sql/table/raw_text +Store the raw text. +Used so people can edit their posts and get their original uploaded text. +Also used so users can download it, +maybe we can use it for "download as image" or "download as pdf" in the future. +Stored zlib compressed +*/ + +/* sh +@name sql/table/raw_text +echo "digraph comments{" \ + "$(cat doc/schema/raw_text.dot)" \ + "$(cat doc/schema/posts.dot)" \ + "}" | dot -Tsvg */ CREATE TABLE IF NOT EXISTS raw_text ( id INTEGER PRIMARY KEY REFERENCES posts(id) ON DELETE CASCADE, diff --git a/src/sql/create_table_session.sql b/src/sql/create_table_session.sql index d956250..8381d9d 100644 --- a/src/sql/create_table_session.sql +++ b/src/sql/create_table_session.sql @@ -1,10 +1,19 @@ -/* +/* md +@name sql/table/sessions Store a cookie for logged in users. Logged in users can edit their own posts, edit their biographies, and post stories and comment under their own name. -TODO: WE can hash the "key" so that even if the database gets +TODO: We can hash the "key" so that even if the database gets dumped, a hacker can't cookie-steal with only read access to the db. */ + +/* sh +@name sql/table/sessions +echo "digraph comments{" \ + "$(cat doc/schema/sessions.dot)" \ + "$(cat doc/schema/authors.dot)" \ + "}" | dot -Tsvg +*/ CREATE TABLE IF NOT EXISTS sessions ( key TEXT PRIMARY KEY, author REFERENCES authors(id) ON DELETE CASCADE, diff --git a/src/sql/create_table_tags.sql b/src/sql/create_table_tags.sql index 5066343..576b063 100644 --- a/src/sql/create_table_tags.sql +++ b/src/sql/create_table_tags.sql @@ -2,6 +2,46 @@ Tags on a post A post's tags are deleted if the post is deleted. */ +/* dot -Tsvg +@name db/schema/tags +digraph tags { +tags [ + shape="plaintext" + label=< + + + + + + + + + + + + + + + + +
tags
PKidINT, AUTOINCREMENT, NOT NULL
FKpostidON DELETE CASCADE
tagTEXT
> + +]; +posts [ + shape="plaintext" + label=< + + + + + + + +
posts
PKidINT, AUTOINCREMENT, NOT NULL
...
> +]; + tags:postid -> posts:id +} +*/ CREATE TABLE IF NOT EXISTS tags ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, postid REFERENCES posts(id) ON DELETE CASCADE, diff --git a/src/sql/insert_comment.sql b/src/sql/insert_comment.sql index 3986b31..897c2e3 100644 --- a/src/sql/insert_comment.sql +++ b/src/sql/insert_comment.sql @@ -1,4 +1,6 @@ -/* Add a new comment to a story */ +/* +Add a new comment to a story +*/ INSERT INTO comments( postid, author, diff --git a/src/sql/select_author_index.sql b/src/sql/select_author_index.sql index 1bae09c..34e5b71 100644 --- a/src/sql/select_author_index.sql +++ b/src/sql/select_author_index.sql @@ -1,4 +1,6 @@ -/* Get the data we need to display a particular author's latest stories */ +/* +Get the data we need to display a particular author's latest stories +*/ SELECT posts.id, diff --git a/src/sql/select_comments.sql b/src/sql/select_comments.sql index d147f79..23fa233 100644 --- a/src/sql/select_comments.sql +++ b/src/sql/select_comments.sql @@ -1,4 +1,6 @@ -/* Retreive comments on a story */ +/* +Retreive comments on a story +*/ SELECT authors.name, comments.isanon, diff --git a/src/sql/select_site_index.sql b/src/sql/select_site_index.sql index 48954e0..1761ecc 100644 --- a/src/sql/select_site_index.sql +++ b/src/sql/select_site_index.sql @@ -1,4 +1,6 @@ -/* Select the data we need to display the on the front page */ +/* +Select the data we need to display the on the front page +*/ SELECT posts.id, posts.post_title, diff --git a/src/sql/update_views.sql b/src/sql/update_views.sql index 685f6fe..e12a383 100644 --- a/src/sql/update_views.sql +++ b/src/sql/update_views.sql @@ -1,2 +1,4 @@ -/* Update the view counter when someone reads a story */ +/* +Update the view counter when someone reads a story +*/ UPDATE posts SET views = views + 1 WHERE id = :id; diff --git a/tools/doc_sql.sh b/tools/doc_sql.sh new file mode 100755 index 0000000..a0bb5de --- /dev/null +++ b/tools/doc_sql.sh @@ -0,0 +1,70 @@ +#!/bin/bash -ex + +# Tool for documenting sql with graphviz +# Usage: +# $ cat sql_file.sql | tools/doc_sql.sh -flags -passed -to -dot > output_file.svg +# Outputs a subgraph and some edges that can be grouped togeather in a full graph + +flags=$@ +input_file=$(cat -) +# First, find the table name +table_name=$(echo "${input_file}" "SELECT name FROM sqlite_master WHERE type='table';" | sqlite3 | head -n 1) +# And get the data we need to display +table_schema=$(echo "${input_file}" " +SELECT + info.name, + info.type, + info.pk, + info.\"notnull\", + fk_from.\"from\" AS fk_from_col, + fk_from.\"on_delete\" AS fk_on_delete, + fk_from.\"table\" AS fk_from_tbl, + fk_from.\"to\" AS fk_from_to +FROM + pragma_table_info('$table_name') info + LEFT JOIN pragma_foreign_key_list('$table_name') fk_from + ON fk_from.\"from\" = info.\"name\" +ORDER BY + info.\"notnull\" DESC +;" | sqlite3 ) +table_pk_1=$(echo "$table_schema" | head -n 1) +table_pk=$(echo "$table_schema" | head -n 1 | awk ' +BEGIN {FS="|"} +{print $1} +') +#foreign_keys=$(echo "${input_file}" "pragma foreign_key_list('$table_name');" | sqlite3) + +echo "$table_name [" +echo " shape=\"plaintext\"" +echo " label=<" +echo " " +echo "$table_schema" | awk ' +BEGIN {FS="|"} +{ + if ($4) + print ""; + else if ($5) + print ""; + else + print ""; + print ""; + printf ""; + else + printf ">"; + if($2) + print $2; + else + print $2 "ON DELETE CASCADE"; + print ""; +}' +echo "
" $table_name "
PK
FK
" $1 "
> ];" +echo "$table_schema" | awk -v "table_name=$table_name" -v "table_pk=$table_pk" ' +BEGIN {FS="|"} +{ + if ($5) { + print table_name ":" $5 "->" $7 ":" $8 ; + } +} +'