diff --git a/.gitignore b/.gitignore index 08eccd3..0903851 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .dbpassword +sql/spamnoticer_init.sql +todo diff --git a/chandelorean/__init__.py b/chandelorean/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jwt b/jwt new file mode 100644 index 0000000..eb31263 --- /dev/null +++ b/jwt @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY2hhbl9hcmNoaXZlciJ9.rGIKZokTDKTuQLIv8138bUby5PELfDipYYIDpJzH02c diff --git a/jwt_secret b/jwt_secret new file mode 100644 index 0000000..ddcf876 --- /dev/null +++ b/jwt_secret @@ -0,0 +1 @@ +P2Hz2dhxo2OpYy+O8WFgahtqcpdws1JVIVcJhje8KVc= diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..da91a37 --- /dev/null +++ b/settings.json @@ -0,0 +1,4 @@ +{ + "postgrest_url": "http://localhost:3000", + "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY2hhbl9hcmNoaXZlciJ9.rGIKZokTDKTuQLIv8138bUby5PELfDipYYIDpJzH02c" +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7c64415 --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +from setuptools import setup + +requires = [ + 'aiohttp', + 'aiofiles', + 'aiodns' +] + +setup( + name='chandelorean', + version='0.0.1', + description="Imageboard style forum that lets you time travel. Meant to be an archive.", + classifiers=[ + "Programming Language :: Python", + "Topic :: Internet :: WWW/HTTP", + ], + author='Zer0-', + author_email='paul_cockshott@protonmail.com', + packages=['chandelorean'], + include_package_data=True, + install_requires=requires, +) diff --git a/sql/initialize.sql b/sql/initialize.sql index 3f1a02c..e002989 100644 --- a/sql/initialize.sql +++ b/sql/initialize.sql @@ -1,5 +1,36 @@ BEGIN TRANSACTION; +-- +-- CREATE EXTENSION bktree; -- only superuser can + +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + +-- + +DROP TABLE IF EXISTS sites CASCADE; +DROP TABLE IF EXISTS boards CASCADE; +DROP TABLE IF EXISTS threads CASCADE; +DROP TABLE IF EXISTS posts CASCADE; +DROP TABLE IF EXISTS attachments CASCADE; +DROP FUNCTION IF EXISTS update_post_body_search_index; + +-- It won't let us drop roles otherwise and the IFs are to keep this script idempotent. +DO +$$BEGIN +IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'chan_archiver') THEN + EXECUTE 'REVOKE ALL PRIVILEGES ON DATABASE chan_archives FROM chan_archiver'; +END IF; +IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'chan_archive_anon') THEN + EXECUTE 'REVOKE ALL PRIVILEGES ON DATABASE chan_archives FROM chan_archive_anon'; +END IF; +END$$; + +DROP ROLE IF EXISTS chan_archiver; +DROP ROLE IF EXISTS chan_archive_anon; + CREATE TABLE IF NOT EXISTS sites ( site_id serial primary key , name text NOT NULL @@ -16,20 +47,27 @@ CREATE TABLE IF NOT EXISTS boards CREATE TABLE IF NOT EXISTS threads ( thread_id bigserial primary key + , board_thread_id bigint NOT NULL , creation_time timestamp with time zone NOT NULL , board_id int NOT NULL , CONSTRAINT board_fk FOREIGN KEY (board_id) REFERENCES boards (board_id) ON DELETE CASCADE + , CONSTRAINT unique_board_board_thread_id_constraint UNIQUE (board_id, board_thread_id) ); +CREATE INDEX threads_board_id_idx ON threads (board_id); CREATE TABLE IF NOT EXISTS posts ( post_id bigserial primary key + , board_post_id bigint NOT NULL , creation_time timestamp with time zone NOT NULL , body text , body_search_index tsvector , thread_id bigint NOT NULL + , CONSTRAINT unique_thread_board_id_constraint UNIQUE (thread_id, board_post_id) , CONSTRAINT thread_fk FOREIGN KEY (thread_id) REFERENCES threads (thread_id) ON DELETE CASCADE ); -CREATE INDEX post_body_search_idx ON posts USING GIN (body_search_index); +CREATE INDEX posts_body_search_idx ON posts USING GIN (body_search_index); +CREATE INDEX posts_thread_id_idx ON posts (thread_id); +CREATE INDEX posts_board_post_id_idx ON posts (board_post_id); CREATE OR REPLACE FUNCTION update_post_body_search_index() RETURNS trigger AS $$ BEGIN @@ -44,4 +82,44 @@ ON posts FOR EACH ROW EXECUTE FUNCTION update_post_body_search_index(); -ROLLBACK; +CREATE TABLE IF NOT EXISTS attachments + ( attachment_id bigserial primary key + , mimetype text NOT NULL + , creation_time timestamp with time zone NOT NULL + , md5_hash text NOT NULL + , phash bigint + , illegal boolean NOT NULL DEFAULT false + , post_id bigint NOT NULL + , CHECK + ( + (mimetype NOT IN ('image/jpeg', 'image/png', 'image/gif')) + OR + (phash IS NOT NULL) + ) + , CONSTRAINT post_fk FOREIGN KEY (post_id) REFERENCES posts (post_id) ON DELETE CASCADE + ); +CREATE INDEX attachments_post_id_idx ON attachments (post_id); +CREATE INDEX attachments_md5_hash_idx ON attachments (md5_hash); +CREATE INDEX attachments_phash_bktree_index ON attachments USING spgist (phash bktree_ops); + +CREATE ROLE chan_archive_anon nologin; +GRANT CONNECT ON DATABASE chan_archives TO chan_archive_anon; +GRANT SELECT ON sites TO chan_archive_anon; +GRANT SELECT ON boards TO chan_archive_anon; +GRANT SELECT ON threads TO chan_archive_anon; +GRANT SELECT ON posts TO chan_archive_anon; +GRANT SELECT ON attachments TO chan_archive_anon; +GRANT chan_archive_anon TO admin; + +CREATE ROLE chan_archiver noinherit login password 'test_password'; +GRANT CONNECT ON DATABASE chan_archives TO chan_archiver; +GRANT chan_archive_anon TO chan_archiver; +GRANT ALL ON sites TO chan_archiver; +GRANT ALL ON boards TO chan_archiver; +GRANT ALL ON threads TO chan_archiver; +GRANT ALL ON posts TO chan_archiver; +GRANT ALL ON attachments TO chan_archiver; +GRANT EXECUTE ON FUNCTION update_post_body_search_index TO chan_archiver; +GRANT chan_archiver TO admin; + +COMMIT;