diff --git a/config_example.json b/config_example.json new file mode 100644 index 0000000..59ab748 --- /dev/null +++ b/config_example.json @@ -0,0 +1,60 @@ +{ + "main": { + "url": { + "full": "https://f0ck.dev", + "domain": "f0ck.dev", + "regex": "f0ck\\.dev" + }, + "maxfilesize": 83886080, + "adminmultiplier": 3.5, + "ignored": [ + "f0ck.dev", + "f0ck.me" + ] + }, + "allowedModes": [ "sfw", "nsfw", "untagged", "all" ], + "allowedMimes": [ "audio", "image", "video" ], + "websrv": { + "port": "8080", + "paths": { + "images": "/b", + "thumbnails": "/t", + "coverarts": "/ca" + }, + "themes": [ "f0ck", "p1nk", "orange", "atmos", "amoled", "paper", "term", "iced" ], + "eps": 294, + "cache": false, + "phrases": [ + "" + ] + }, + "clients": [ + + ], + "sql": { + "host": "localhost", + "user": "f0ck", + "password": "", + "database": "f0ck", + "schema": "public", + "multipleStatements": true + }, + "admins": [ + + ], + "mimes": { + "image/png": "png", + "video/webm": "webm", + "image/gif": "gif", + "image/jpeg": "jpg", + "image/webp": "webp", + "video/mp4": "mp4", + "video/quicktime": "mp4", + "audio/mpeg": "mpg", + "audio/mp3": "mp3", + "audio/ogg": "ogg", + "audio/flac": "flac", + "audio/x-flac": "flac", + "video/x-m4v": "mp4" + } +} diff --git a/debug/autotagger.mjs b/debug/autotagger.mjs index d2bc205..8fa75e6 100644 --- a/debug/autotagger.mjs +++ b/debug/autotagger.mjs @@ -36,7 +36,7 @@ import lib from "../src/inc/lib.mjs"; db({ item_id: f.id, tag_id: tmp.nsfw ? 2 : 1, - user_id: 7 + user_id: 1 }) } `; @@ -46,8 +46,8 @@ import lib from "../src/inc/lib.mjs"; insert into "tags_assign" ${ db({ item_id: f.id, - tag_id: 8, // hentai - user_id: 7 // autotagger + tag_id: 4, // hentai + user_id: 1 // autotagger }) } `; diff --git a/f0ck.sql b/f0ck.sql new file mode 100644 index 0000000..81104de --- /dev/null +++ b/f0ck.sql @@ -0,0 +1,213 @@ +\connect "f0ck"; + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +CREATE FUNCTION public.delete_unused_tags() RETURNS trigger + LANGUAGE plpgsql + AS $$ +begin + delete from tags + where + tags.id not in (select tag_id from tags_assign) and + tags.id = OLD.tag_id and + tags.tag != 'sfw' and + tags.tag != 'nsfw' and + tags.tag != 'hentai' and + tags.tag != 'audio'; + return OLD; +end $$; + +ALTER FUNCTION public.delete_unused_tags() OWNER TO f0ck; + +CREATE FUNCTION public.fill_normalized() RETURNS trigger + LANGUAGE plpgsql + AS $$ +begin + NEW.normalized = slugify(NEW.tag); + return NEW; +end$$; + +ALTER FUNCTION public.fill_normalized() OWNER TO f0ck; + +CREATE FUNCTION public.slugify(v text) RETURNS text + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[\u0000-\u002f \u003a-\u0040\u005b-\u0060\u007b-\u00bf]+', '', 'gi')); +END; +$$; + +ALTER FUNCTION public.slugify(v text) OWNER TO f0ck; + +CREATE TABLE public.favorites ( + user_id integer NOT NULL, + item_id integer NOT NULL +); + +ALTER TABLE public.favorites OWNER TO f0ck; + +CREATE SEQUENCE public.items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER TABLE public.items_id_seq OWNER TO f0ck; + +CREATE TABLE public.items ( + id integer DEFAULT nextval('public.items_id_seq'::regclass) NOT NULL, + src character varying(255) NOT NULL, + dest character varying(40) NOT NULL, + mime character varying(100) NOT NULL, + size integer NOT NULL, + checksum character varying(255) NOT NULL, + username character varying(40) NOT NULL, + userchannel character varying(100) NOT NULL, + usernetwork character varying(40) NOT NULL, + stamp integer NOT NULL, + active boolean NOT NULL, + thumb character varying(100) +); + +ALTER TABLE public.items OWNER TO f0ck; + +COMMENT ON COLUMN public.items.src IS 'src-Link'; +COMMENT ON COLUMN public.items.dest IS 'filename'; + +CREATE SEQUENCE public.tags_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER TABLE public.tags_id_seq OWNER TO f0ck; + +CREATE TABLE public.tags ( + id integer DEFAULT nextval('public.tags_id_seq'::regclass) NOT NULL, + tag character varying(45) NOT NULL, + normalized character varying(45) NOT NULL +); + +ALTER TABLE public.tags OWNER TO f0ck; + +CREATE TABLE public.tags_alias ( + tag_orig_id integer NOT NULL, + tag_alias character varying NOT NULL +); + +ALTER TABLE public.tags_alias OWNER TO f0ck; + +CREATE TABLE public.tags_assign ( + item_id integer NOT NULL, + tag_id integer NOT NULL, + user_id integer DEFAULT 2 NOT NULL +); + +ALTER TABLE public.tags_assign OWNER TO f0ck; + +CREATE SEQUENCE public.user_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER TABLE public.user_id_seq OWNER TO f0ck; + +CREATE TABLE public."user" ( + id integer DEFAULT nextval('public.user_id_seq'::regclass) NOT NULL, + login character varying(255) NOT NULL, + "user" character varying(255) NOT NULL, + password character varying(167) NOT NULL, + level integer NOT NULL +); + +ALTER TABLE public."user" OWNER TO f0ck; + +CREATE TABLE public.user_options ( + user_id integer NOT NULL, + mode integer NOT NULL, + theme character varying(50) NOT NULL, + avatar integer DEFAULT 1 NOT NULL +); + +ALTER TABLE public.user_options OWNER TO f0ck; + +CREATE SEQUENCE public.user_sessions_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; + +ALTER TABLE public.user_sessions_id_seq OWNER TO f0ck; + +CREATE TABLE public.user_sessions ( + id integer DEFAULT nextval('public.user_sessions_id_seq'::regclass) NOT NULL, + user_id integer NOT NULL, + session character varying(32) NOT NULL, + browser character varying(255) NOT NULL, + created_at integer NOT NULL, + last_used integer NOT NULL, + last_action character varying(255) NOT NULL, + kmsi smallint DEFAULT '0'::smallint NOT NULL +); + +ALTER TABLE public.user_sessions OWNER TO f0ck; + +COPY public.items (id, src, dest, mime, size, checksum, username, userchannel, usernetwork, stamp, active, thumb) FROM stdin; +1 b761fa9339.png b761fa9339.png image/png 164 keinPlan Flummi #f0ck n0xy 1471250800 t +\. + +COPY public.tags (id, tag, normalized) FROM stdin; +1 sfw sfw +2 nsfw nsfw +3 audio audio +4 hentai hentai +\. + +COPY public.tags_assign (item_id, tag_id, user_id) FROM stdin; +1 1 1 +\. + +COPY public."user" (id, login, "user", password, level) FROM stdin; +1 autotagger autotagger f0ck you 0 +2 deleted deleted f0ck you 0 +\. + +SELECT pg_catalog.setval('public.items_id_seq', 2, true); +SELECT pg_catalog.setval('public.tags_id_seq', 5, true); +SELECT pg_catalog.setval('public.user_id_seq', 3, true); +SELECT pg_catalog.setval('public.user_sessions_id_seq', 1, true); +ALTER TABLE ONLY public.favorites ADD CONSTRAINT idx_16521_primary PRIMARY KEY (user_id, item_id); +ALTER TABLE ONLY public.items ADD CONSTRAINT idx_16526_primary PRIMARY KEY (id); +ALTER TABLE ONLY public."user" ADD CONSTRAINT idx_16554_primary PRIMARY KEY (id); +ALTER TABLE ONLY public.user_options ADD CONSTRAINT idx_16567_user_id UNIQUE (user_id); +ALTER TABLE ONLY public.user_sessions ADD CONSTRAINT idx_16572_primary PRIMARY KEY (id); +ALTER TABLE ONLY public.items ADD CONSTRAINT items_checksum UNIQUE (checksum); +ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_alias_tag_orig_id UNIQUE (tag_alias, tag_orig_id); +ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_orig_id PRIMARY KEY (tag_orig_id); +ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_tag_id_primary PRIMARY KEY (item_id, tag_id); +ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_tag_id_unique UNIQUE (item_id, tag_id); +ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_id PRIMARY KEY (id); +ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_normalized UNIQUE (normalized); +ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_tag UNIQUE (tag); +ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_user_id PRIMARY KEY (user_id); +CREATE TRIGGER tags_assign_ad AFTER DELETE ON public.tags_assign FOR EACH ROW EXECUTE FUNCTION public.delete_unused_tags(); +CREATE TRIGGER tags_bi BEFORE INSERT ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized(); +CREATE TRIGGER tags_bu BEFORE UPDATE ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized(); +ALTER TABLE ONLY public.favorites ADD CONSTRAINT favorites_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.favorites ADD CONSTRAINT favorites_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_orig_id_fkey FOREIGN KEY (tag_orig_id) REFERENCES public.tags(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE SET DEFAULT; +ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_avatar_fkey FOREIGN KEY (avatar) REFERENCES public.items(id) ON DELETE SET DEFAULT; +ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE; +ALTER TABLE ONLY public.user_sessions ADD CONSTRAINT user_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE; diff --git a/public/b/b761fa9339.png b/public/b/b761fa9339.png new file mode 100755 index 0000000..dd855a0 Binary files /dev/null and b/public/b/b761fa9339.png differ diff --git a/public/t/1.webp b/public/t/1.webp new file mode 100755 index 0000000..29a2df0 Binary files /dev/null and b/public/t/1.webp differ diff --git a/src/inc/routes/apiv2/index.mjs b/src/inc/routes/apiv2/index.mjs index 545dce7..ddc6c60 100644 --- a/src/inc/routes/apiv2/index.mjs +++ b/src/inc/routes/apiv2/index.mjs @@ -28,27 +28,46 @@ export default router => { }); }); - group.get(/\/p\/([0-9]+)/, async (req, res) => { // legacy - let eps = 100; - let id = +req.url.split[3]; - - const rows = await db` - select * - from "items" - where id < ${+id} - order by id desc - limit ${+eps} - `; - - const items = { - items: rows, - last: rows[rows.length - 1].id + group.get(/\/items\/get/, async (req, res) => { + let eps = 150; + + const opt = { + older: req.url.qs.older ?? null, + newer: req.url.qs.newer ?? null, + mode: +req.url.qs.mode ?? 0 // 0 sfw, 1 nsfw, 2 untagged, 3 all }; - + + const newest = (await db`select max(id) as id from "items"`)[0].id; + const oldest = (await db`select min(id) as id from "items"`)[0].id; + const modequery = lib.getMode(opt.mode); + + const rows = (await db` + select "items".id, "items".mime, coalesce("tags_assign".tag_id, 0) as tag_id + from "items" + left join "tags_assign" on "tags_assign".item_id = "items".id and ("tags_assign".tag_id = 1 or "tags_assign".tag_id = 2) + where + ${db.unsafe(modequery)} + ${ + opt.older + ? db`and id <= ${opt.older}` + : opt.newer + ? db`and id >= ${opt.newer}` + : db`` + } + order by id ${ + opt.newer + ? db`asc` + : db`desc` + } + limit ${eps} + `).sort((a, b) => b.id - a.id); + return res.json({ + atEnd: rows[0].id === newest, + atStart: rows[rows.length - 1].id === oldest, success: true, - items - }); + items: rows + }, 200); }); group.get(/\/item\/[0-9]+$/, async (req, res) => { @@ -152,13 +171,13 @@ export default router => { } const q = (await db` - update "tags" set ${ - db({ - tag: newtag - }, 'tag') - } - where tag = ${tagname} - returning * + update "tags" set ${ + db({ + tag: newtag + }, 'tag') + } + where tag = ${tagname} + returning * `)?.[0]; return res.json(q, tagname === newtag ? 200 : 201); // created (modified) @@ -204,6 +223,12 @@ export default router => { }); } const postid = +req.post.postid; + + if(postid <= 1) { + return res.json({ + success: false + }); + } await db` delete from "items" diff --git a/src/inc/routes/apiv2/tags.mjs b/src/inc/routes/apiv2/tags.mjs index 315930e..41f6311 100644 --- a/src/inc/routes/apiv2/tags.mjs +++ b/src/inc/routes/apiv2/tags.mjs @@ -131,6 +131,14 @@ export default router => { const postid = +req.params.postid; const tagname = decodeURIComponent(req.params.tagname); + if(tagname == 'sfw' || tagname == 'nsfw' || tagname == 'hentai' || tagname == 'audio') { + return res.json({ + success: false, + msg: 'blacklisted', + tags: await lib.getTags(postid) + }); + } + const tags = await lib.getTags(postid); const tagid = tags.filter(t => t.tag === tagname)[0]?.id ?? null; diff --git a/src/inc/sql.mjs b/src/inc/sql.mjs index c508882..91599f3 100644 --- a/src/inc/sql.mjs +++ b/src/inc/sql.mjs @@ -1,10 +1,4 @@ -//import knex from "knex"; import postgres from "postgres"; import cfg from "./config.mjs"; -const db = postgres(cfg.sql); - -if(cfg.sql.schema) - await db.unsafe(`set search_path to '${cfg.sql.schema}';`); - -export default db; +export default postgres(cfg.sql); diff --git a/src/inc/trigger/delete.mjs b/src/inc/trigger/delete.mjs index ecb29e3..eb07724 100644 --- a/src/inc/trigger/delete.mjs +++ b/src/inc/trigger/delete.mjs @@ -13,7 +13,7 @@ export default async bot => { for(let id of e.args) { id = +id; - if(id <= 0) + if(id <= 1) continue; const f0ck = await db` diff --git a/src/inc/trigger/parser.mjs b/src/inc/trigger/parser.mjs index 259d7d6..fa9f235 100644 --- a/src/inc/trigger/parser.mjs +++ b/src/inc/trigger/parser.mjs @@ -214,8 +214,8 @@ export default async bot => { insert into "tags_assign" ${ db({ item_id: f.id, - tag_id: 8, // hentai - user_id: 7 // autotagger + tag_id: 4, // hentai + user_id: 1 // autotagger }) } `; @@ -228,11 +228,11 @@ export default async bot => { db([{ item_id: itemid, tag_id: 1, - user_id: 7 + user_id: 1 }, { item_id: itemid, - tag_id: 7178, - user_id: 7 + tag_id: 3, // audio + user_id: 1 }]) } `;