1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-24 08:46:24 -07:00

Upgrade Go version in vagrant and Docker, readd sqlite3 for real this time

requires intervention for vagrant to add the updated Go repo
This commit is contained in:
Eggbertx 2022-08-30 11:30:59 -07:00
parent 3fa042167e
commit 9107269a39
21 changed files with 1464 additions and 592 deletions

View file

@ -183,9 +183,6 @@ def set_vars(goos=""):
if goos != "":
os.environ["GOOS"] = goos
if os.getenv("CGO_ENABLED") is None:
# CGO_ENABLED is not explicitly enabled, disable it
os.environ["CGO_ENABLED"] = "0"
gcos, gcos_status = run_cmd("go env GOOS", print_output=False)
exe, exe_status = run_cmd("go env GOEXE", print_output=False)

View file

@ -18,6 +18,7 @@ import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
var (

View file

@ -4,19 +4,21 @@ from os import path
class macro():
""" Use a macro like this {exact macro name} """
def __init__(self, macroname, postgres, mysql):
def __init__(self, macroname, postgres, mysql, sqlite3):
self.macroname = macroname
self.postgres = postgres
self.mysql = mysql
self.sqlite3 = sqlite3
# macros
macros = [
macro(
"serial pk","BIGSERIAL PRIMARY KEY",
"BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY"),
macro("fk to serial", "BIGINT", "BIGINT"),
macro("drop fk", "DROP CONSTRAINT", "DROP FOREIGN KEY")
"BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY",
"INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"),
macro("fk to serial", "BIGINT", "BIGINT", "BIGINT"),
macro("drop fk", "DROP CONSTRAINT", "DROP FOREIGN KEY", "DROP CONSTRAINT")
]
@ -48,11 +50,13 @@ def dofile(filestart):
postgresProcessed = compileOutIfs(masterfile, "POSTGRES")
mysqlProcessed = compileOutIfs(masterfile, "MYSQL")
sqlite3Processed = compileOutIfs(masterfile, "SQLITE3")
for item in macros:
macroCode = "{" + item.macroname + "}"
postgresProcessed = postgresProcessed.replace(macroCode, item.postgres)
mysqlProcessed = mysqlProcessed.replace(macroCode, item.mysql)
sqlite3Processed = sqlite3Processed.replace(macroCode, item.sqlite3)
error = hasError(postgresProcessed)
error = error or hasError(mysqlProcessed)
@ -60,6 +64,9 @@ def dofile(filestart):
with open(filestart + "postgres.sql", 'w') as i:
i.write(postgresProcessed)
with open(filestart + "sqlite3.sql", 'w') as i:
i.write(sqlite3Processed)
with open(filestart + "mysql.sql", 'w') as i:
i.write(mysqlProcessed)

View file

@ -1,4 +1,4 @@
FROM golang:1.13.9-alpine3.11
FROM golang:1.16-alpine3.15
RUN apk --no-cache add \
postgresql-client \
@ -13,7 +13,7 @@ RUN apk --no-cache add \
bash
RUN mkdir -p /root/bin \
&& ln -s /usr/lib/go-1.13/bin/* /root/bin/ \
&& ln -s /usr/lib/go-1.16/bin/* /root/bin/ \
&& export PATH=$PATH:/root/bin \
&& echo "export PATH=$PATH:/root/bin" >> /root/.bashrc \
&& rm -f /etc/nginx/sites-enabled/* /etc/nginx/sites-available/* \
@ -27,8 +27,8 @@ WORKDIR /opt/gochan
COPY build.py .
RUN ./build.py dependencies
RUN rm /etc/nginx/conf.d/default.conf
COPY sample-configs/gochan-fastcgi.nginx /etc/nginx/conf.d/gochan.conf
RUN rm -f /etc/nginx/http.d/default.conf
COPY sample-configs/gochan-fastcgi.nginx /etc/nginx/http.d/gochan.conf
COPY sample-configs/gochan.example.json /etc/gochan/gochan.json
# Get all
@ -42,7 +42,6 @@ EXPOSE 9000
CMD ls -la /opt/gochan && ls -la && ls -la .. && sed -i /etc/gochan/gochan.json \
-e 's/"Port": 8080/"Port": 9000/' \
-e 's/"UseFastCGI": false/"UseFastCGI": true/' \
-e 's/"DomainRegex": ".*"/"DomainRegex": "(https|http):\\\/\\\/(.*)\\\/(.*)"/' \
-e 's#"DocumentRoot": "html"#"DocumentRoot": "/srv/gochan"#' \
-e 's#"TemplateDir": "templates"#"TemplateDir": "/usr/share/gochan/templates"#' \
-e 's#"LogDir": "log"#"LogDir": "/var/log/gochan"#' \
@ -52,6 +51,7 @@ CMD ls -la /opt/gochan && ls -la && ls -la .. && sed -i /etc/gochan/gochan.json
-e "s/\"DBname\".*/\"DBname\": \"${DATABASE_NAME}\",/" \
-e "s/\"DBusername\".*/\"DBusername\": \"${DATABASE_USER}\",/" \
-e "s/\"DBpassword\".*/\"DBpassword\": \"${DATABASE_PASSWORD}\",/" \
&& mkdir -p /etc/ssl/private \
&& openssl req -x509 -nodes -days 7305 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt -subj "/CN=127.0.0.1" \
&& ./build.py \
&& ./build.py install \

13
go.mod
View file

@ -1,6 +1,6 @@
module github.com/gochan-org/gochan
go 1.13
go 1.16
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
@ -9,13 +9,14 @@ require (
github.com/frustra/bbcode v0.0.0-20201127003707-6ef347fbe1c8
github.com/go-sql-driver/mysql v1.6.0
github.com/gochan-org/gzlog v1.0.2
github.com/lib/pq v1.10.2
github.com/mojocn/base64Captcha v1.3.4
github.com/lib/pq v1.10.6
github.com/mattn/go-sqlite3 v1.14.15
github.com/mojocn/base64Captcha v1.3.5
github.com/tdewolff/minify v2.3.6+incompatible
github.com/tdewolff/parse v2.3.4+incompatible // indirect
github.com/tdewolff/test v1.0.6 // indirect
github.com/tdewolff/test v1.0.7 // indirect
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
layeh.com/gopher-luar v1.0.10
)

20
go.sum
View file

@ -17,14 +17,22 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mojocn/base64Captcha v1.3.4 h1:9+MZzjNSfBHniYOIpoP4xyDDPCXy14JIjsEFf89PlNw=
github.com/mojocn/base64Captcha v1.3.4/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY=
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ=
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
@ -32,21 +40,33 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/9
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
layeh.com/gopher-luar v1.0.10 h1:55b0mpBhN9XSshEd2Nz6WsbYXctyBT35azk4POQNSXo=
layeh.com/gopher-luar v1.0.10/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=

271
initdb_sqlite3.sql Normal file
View file

@ -0,0 +1,271 @@
-- Gochan master template for new database script
-- Contains macros in the form [curlybrace open]macro text[curlybrace close]
-- Macros are substituted by build_initdb.py to the supported database files. Must not contain extra spaces
-- Versioning numbering goes by whole numbers. Upgrade script migrate existing databases between versions
-- Foreign and unique constraints must be named so they can be dropped.
-- MYSQL requires constraint names to be unique globally, hence the long constraint names.
-- Database version: 1
CREATE TABLE DBPREFIXdatabase_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);
CREATE TABLE DBPREFIXsections(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);
CREATE TABLE DBPREFIXboards(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES DBPREFIXsections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);
CREATE TABLE DBPREFIXthreads(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE
);
CREATE INDEX thread_deleted_index ON DBPREFIXthreads(is_deleted);
CREATE TABLE DBPREFIXposts(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES DBPREFIXthreads(id) ON DELETE CASCADE
);
CREATE INDEX top_post_index ON DBPREFIXposts(is_top_post);
CREATE TABLE DBPREFIXfiles(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);
CREATE TABLE DBPREFIXstaff(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);
CREATE TABLE DBPREFIXsessions(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXboard_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);
CREATE TABLE DBPREFIXannouncements(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXip_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES DBPREFIXposts(id) ON DELETE SET NULL
);
CREATE TABLE DBPREFIXip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXip_ban_appeals(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES DBPREFIXip_ban_appeals(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXreports(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXreports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES DBPREFIXreports(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXfilename_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXusername_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXfile_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXwordfilters(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
);
INSERT INTO DBPREFIXdatabase_version(component, version)
VALUES('gochan', 1);

View file

@ -2,7 +2,6 @@ package config
import (
"encoding/json"
"flag"
"io/ioutil"
"net"
"reflect"
@ -66,7 +65,7 @@ var (
}
boardConfigs = map[string]BoardConfig{}
acceptedDrivers = []string{"mysql", "postgres"}
acceptedDrivers = []string{"mysql", "postgres", "sqlite3"}
)
type GochanConfig struct {
@ -410,11 +409,7 @@ func GetBoardConfig(board string) *BoardConfig {
}
func GetDebugMode() bool {
if flag.Lookup("test.v") != nil {
// running with go test
return true
}
return cfg.SystemCriticalConfig.DebugMode
return cfg.testing || cfg.SystemCriticalConfig.DebugMode
}
func GetVersion() *GochanVersion {

View file

@ -2,6 +2,7 @@ package config
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
@ -125,6 +126,92 @@ func ParseJSON(ba []byte) (*GochanConfig, []MissingField, error) {
// InitConfig loads and parses gochan.json on startup and verifies its contents
func InitConfig(versionStr string) {
if flag.Lookup("test.v") != nil {
// create a dummy config for testing if we're using go test
cfg = &GochanConfig{
testing: true,
SystemCriticalConfig: SystemCriticalConfig{
ListenIP: "127.0.0.1",
Port: 8080,
UseFastCGI: true,
DebugMode: true,
DocumentRoot: "html",
TemplateDir: "templates",
LogDir: "",
DBtype: "sqlmock",
DBhost: "127.0.0.1:3306",
DBname: "gochan",
DBusername: "gochan",
DBpassword: "",
DBprefix: "gc_",
SiteDomain: "127.0.0.1",
WebRoot: "/",
RandomSeed: "abcd",
Version: ParseVersion(versionStr),
},
SiteConfig: SiteConfig{
Username: "gochan",
FirstPage: []string{"index.html", "firstrun.html", "1.html"},
Lockdown: false,
LockdownMessage: "This imageboard has temporarily disabled posting. We apologize for the inconvenience",
SiteName: "Gochan",
SiteSlogan: "Gochan testing",
MinifyHTML: true,
MinifyJS: true,
EnableAppeals: true,
MaxLogDays: 14,
Verbosity: 1,
MaxRecentPosts: 3,
RecentPostsWithNoFile: false,
},
BoardConfig: BoardConfig{
Sillytags: []string{"Admin", "Mod", "Janitor", "Dweeb", "Kick me", "Troll", "worst pony"},
UseSillytags: false,
Styles: []Style{
{Name: "Pipes", Filename: "pipes.css"},
{Name: "BunkerChan", Filename: "bunkerchan.css"},
{Name: "Burichan", Filename: "burichan.css"},
{Name: "Clear", Filename: "clear.css"},
{Name: "Dark", Filename: "dark.css"},
{Name: "Photon", Filename: "photon.css"},
{Name: "Yotsuba", Filename: "yotsuba.css"},
{Name: "Yotsuba B", Filename: "yotsubab.css"},
{Name: "Windows 9x", Filename: "win9x.css"},
},
DefaultStyle: "pipes.css",
PostConfig: PostConfig{
NewThreadDelay: 30,
ReplyDelay: 7,
ThreadsPerPage: 15,
PostsPerThreadPage: 50,
RepliesOnBoardPage: 3,
StickyRepliesOnBoardPage: 1,
BanColors: []string{
"admin:#0000A0",
"somemod:blue",
},
BanMessage: "USER WAS BANNED FOR THIS POST",
EnableEmbeds: true,
EmbedWidth: 200,
EmbedHeight: 164,
ImagesOpenNewTab: true,
NewTabOnOutlinks: true,
},
UploadConfig: UploadConfig{
ThumbWidth: 200,
ThumbHeight: 200,
ThumbWidthReply: 125,
ThumbHeightReply: 125,
ThumbWidthCatalog: 50,
ThumbHeightCatalog: 50,
},
DateTimeFormat: "Mon, January 02, 2006 3:04 PM",
},
}
return
}
cfgPath = gcutil.FindResource(
"gochan.json",
"/usr/local/etc/gochan/gochan.json",

47
pkg/gcsql/boards_test.go Normal file
View file

@ -0,0 +1,47 @@
package gcsql
import (
"database/sql"
"testing"
"github.com/DATA-DOG/go-sqlmock"
"github.com/gochan-org/gochan/pkg/config"
)
func TestCreateBoard(t *testing.T) {
// set up boards
sqm.ExpectPrepare(prepTestQueryString(
`SELECT id FROM gc_sections WHERE name = 'Main'`,
)).ExpectQuery().WillReturnError(sql.ErrNoRows)
sqm.ExpectPrepare(prepTestQueryString(
`SELECT COALESCE(MAX(position) + 1, 0) FROM gc_sections`,
)).ExpectQuery().WillReturnRows(sqlmock.NewRows([]string{"a"}).AddRow(0))
sqm.ExpectPrepare(prepTestQueryString(
`INSERT INTO gc_sections (name, abbreviation, hidden, position) VALUES (?,?,?,?)`,
)).ExpectExec().WithArgs("Main", "Main", false, 0).WillReturnResult(sqlmock.NewResult(1, 1))
sqm.ExpectPrepare(prepTestQueryString(
`SELECT id FROM gc_sections WHERE position = ?`,
)).ExpectQuery().WithArgs(0).WillReturnRows(
sqlmock.NewRows([]string{"id"}).AddRow(1),
)
sqm.ExpectPrepare(prepTestQueryString(`INSERT INTO gc_boards (
navbar_position, dir, uri, title, subtitle, description, max_file_size, max_threads, default_style, locked, anonymous_name, force_anonymous, autosage_after, no_images_after, max_message_length, min_message_length, allow_embeds, redirect_to_thread, require_file, enable_catalog, section_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)).ExpectExec().WithArgs(
0, "test", "test", "Testing board", "Board for testing stuff", "/test/ board description",
10000, 300, config.GetBoardConfig("").DefaultStyle, false, "Anonymous", false, 200, 500,
8192, 1, false, false, false, true, 1,
).WillReturnResult(sqlmock.NewResult(1, 1))
sqm.ExpectPrepare(prepTestQueryString(
`SELECT id FROM gc_boards WHERE dir = ?`,
)).ExpectQuery().WithArgs("test").WillReturnRows(
sqlmock.NewRows([]string{"id"}).AddRow(1),
)
err := CreateDefaultBoardIfNoneExist()
if err != nil {
t.Fatalf("Failed creating default board if none exists: %s", err.Error())
}
if err = sqm.ExpectationsWereMet(); err != nil {
t.Fatal(err.Error())
}
}

View file

@ -67,12 +67,13 @@ func RunSQLFile(path string) error {
return nil
}
// TODO: get gocha-migration working so this doesn't have to sit here
// TODO: get gochan-migration working so this doesn't have to sit here
func tmpSqlAdjust() error {
// first update the crappy wordfilter table structure
var err error
var query string
if gcdb.driver == "mysql" {
switch gcdb.driver {
case "mysql":
query = `SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'wordfilters_staff_id_fk'
AND TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'DBPREFIXwordfilters'`
@ -85,8 +86,10 @@ func tmpSqlAdjust() error {
if numConstraints > 0 {
query = `ALTER TABLE DBPREFIXwordfilters DROP FOREIGN KEY IF EXISTS wordfilters_board_id_fk`
}
} else {
case "postgres":
query = `ALTER TABLE DBPREFIXwordfilters DROP CONSTRAINT IF EXISTS board_id_fk`
case "sqlite3":
return nil
}
if _, err = gcdb.ExecSQL(query); err != nil {
return err

View file

@ -16,6 +16,7 @@ const (
Error text: %s`
mysqlConnStr = "%s:%s@tcp(%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci"
postgresConnStr = "postgres://%s:%s@%s/%s?sslmode=disable"
sqlite3ConnStr = "file:%s?_auth&_auth_user=%s&_auth_pass=%s&_auth_crypt=sha1"
)
type GCDB struct {
@ -70,6 +71,7 @@ func (db *GCDB) PrepareSQL(query string, tx *sql.Tx) (*sql.Stmt, error) {
/*
ExecSQL automatically escapes the given values and caches the statement
Example:
var intVal int
var stringVal string
result, err := db.ExecSQL("INSERT INTO tablename (intval,stringval) VALUES(?,?)", intVal, stringVal)
@ -105,6 +107,7 @@ func (db *GCDB) BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, erro
QueryRowSQL gets a row from the db with the values in values[] and fills the respective pointers in out[]
Automatically escapes the given values and caches the query
Example:
id := 32
var intVal int
var stringVal string
@ -125,6 +128,7 @@ func (db *GCDB) QueryRowSQL(query string, values, out []interface{}) error {
QuerySQL gets all rows from the db with the values in values[] and fills the respective pointers in out[]
Automatically escapes the given values and caches the query
Example:
rows, err := db.QuerySQL("SELECT * FROM table")
if err == nil {
for rows.Next() {
@ -153,22 +157,26 @@ func Open(host, dbDriver, dbName, username, password, prefix string) (db *GCDB,
"\n", " "),
}
addrMatches := tcpHostIsolator.FindAllStringSubmatch(host, -1)
if len(addrMatches) > 0 && len(addrMatches[0]) > 2 {
host = addrMatches[0][2]
if dbDriver != "sqlite3" {
addrMatches := tcpHostIsolator.FindAllStringSubmatch(host, -1)
if len(addrMatches) > 0 && len(addrMatches[0]) > 2 {
host = addrMatches[0][2]
}
}
switch dbDriver {
case "mysql":
db.connStr = fmt.Sprintf(mysqlConnStr, username, password, host, dbName)
// db.nilTimestamp = "0000-00-00 00:00:00"
case "sqlite3":
db.connStr = fmt.Sprintf(sqlite3ConnStr, host, username, password)
case "postgres":
db.connStr = fmt.Sprintf(postgresConnStr, username, password, host, dbName)
// db.nilTimestamp = "0001-01-01 00:00:00"
default:
return nil, ErrUnsupportedDB
}
fmt.Printf("connStr: %q\nhost: %q\n", db.connStr, host)
db.db, err = sql.Open(db.driver, db.connStr)
return db, err
}

View file

@ -67,7 +67,7 @@ func GetCompleteDatabaseVersion() (dbVersion, dbFlag int, err error) {
return 0, DBClean, nil
}
//CheckAndInitializeDatabase checks the validity of the database and initialises it if it is empty
// CheckAndInitializeDatabase checks the validity of the database and initialises it if it is empty
func CheckAndInitializeDatabase(dbType string) {
dbVersion, versionFlag, err := GetCompleteDatabaseVersion()
if err != nil {

View file

@ -8,13 +8,14 @@ import (
"testing"
"github.com/DATA-DOG/go-sqlmock"
"github.com/gochan-org/gochan/pkg/config"
)
var (
sqm sqlmock.Sqlmock
)
func connectTest() error {
func connectTest() (err error) {
gcdb = &GCDB{
driver: "sqlmock",
replacer: strings.NewReplacer(
@ -22,7 +23,7 @@ func connectTest() error {
"DBPREFIX", "gc_",
"\n", " "),
}
var err error
gcdb.db, sqm, err = sqlmock.New()
if err != nil {
return err
@ -34,556 +35,10 @@ func prepTestQueryString(str string) string {
return regexp.QuoteMeta(strings.Replace(str, "\n", " ", -1))
}
func createTablesTest() error {
if gcdb == nil {
return ErrNotConnected
}
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_database_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(1, 1))
sqm.ExpectPrepare(regexp.QuoteMeta(`CREATE TABLE gc_sections(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(2, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_boards(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES gc_sections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(3, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_threads(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(4, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE INDEX thread_deleted_index ON gc_threads(is_deleted);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(5, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_posts(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES gc_threads(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(5, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_files(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES gc_posts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(6, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_staff(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(7, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_sessions(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_board_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_announcements(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES gc_posts(id) ON DELETE SET NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES gc_ip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_appeals(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES gc_ip_ban(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES gc_ip_ban_appeals(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_reports(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES gc_staff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES gc_posts(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_reports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES gc_staff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES gc_reports(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_filename_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_username_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_file_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_wordfilters(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
func populateTestSchema() error {
var err error
sqm.ExpectPrepare(prepTestQueryString(`INSERT INTO gc_database_version(component, version)
VALUES('gochan', 1);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
// start fulfilling the expected execs
var err error
if _, err = ExecSQL(`CREATE TABLE DBPREFIXdatabase_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXsections(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXboards(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES DBPREFIXsections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXthreads(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE INDEX thread_deleted_index ON DBPREFIXthreads(is_deleted);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXposts(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES DBPREFIXthreads(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfiles(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXstaff(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXsessions(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXboard_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXannouncements(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES DBPREFIXposts(id) ON DELETE SET NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_appeals(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES DBPREFIXip_ban_appeals(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXreports(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXreports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES DBPREFIXreports(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfilename_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXusername_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfile_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXwordfilters(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
);`); err != nil {
return err
}
if _, err = ExecSQL(`INSERT INTO DBPREFIXdatabase_version(component, version)
VALUES('gochan', 1);`); err != nil {
return err
@ -592,8 +47,32 @@ VALUES('gochan', 1);`); err != nil {
return sqm.ExpectationsWereMet()
}
func TestDatabaseVersion(t *testing.T) {
sqm.ExpectPrepare(prepTestQueryString(
`SELECT component,version FROM gc_database_version WHERE component = ?;`,
)).ExpectQuery().WithArgs("gochan").WillReturnRows(
sqlmock.NewRows([]string{"component", "version"}).AddRow("gochan", 1),
)
var component string
var version int
err := QueryRowSQL(`SELECT component,version FROM DBPREFIXdatabase_version WHERE component = ?;`,
interfaceSlice("gochan"),
interfaceSlice(&component, &version))
if err != nil {
t.Fatalf(err.Error())
}
if err = sqm.ExpectationsWereMet(); err != nil {
t.Fatal(err.Error())
}
if version < 1 {
t.Fatalf("Component %q has version: %d", component, version)
}
}
func TestMain(m *testing.M) {
log.SetFlags(0)
config.InitConfig("3.2.0")
err := connectTest()
if err != nil {
@ -601,9 +80,14 @@ func TestMain(m *testing.M) {
}
defer gcdb.Close()
if err = createTablesTest(); err != nil {
if err = createMockSchema(); err != nil {
log.Fatalln("Failed setting up sqlmock db tables:", err.Error())
}
if err = populateTestSchema(); err != nil {
log.Fatalln("Failed populating test schema:", err.Error())
}
exitCode := m.Run()
os.Exit(exitCode)

View file

@ -1,12 +1,49 @@
package gcsql
import (
"log"
"testing"
_ "github.com/DATA-DOG/go-sqlmock"
)
func TestInsertPost(t *testing.T) {
log.Println("Inserting post")
func makeTestPost(post *Post, bump bool) (err error) {
sqm.ExpectPrepare(prepTestQueryString(
`SELECT COALESCE(MAX(id), 0) + 1 FROM gc_threads`,
)).ExpectQuery().WillReturnRows(
sqm.NewRows([]string{"a"}).AddRow(1),
)
err = InsertPost(post, bump)
if err != nil {
return err
}
return sqm.ExpectationsWereMet()
}
func TestInsertPosts(t *testing.T) {
err := makeTestPost(&Post{
ParentID: 0,
BoardID: 1,
Name: "Joe Poster",
Tripcode: "Blah",
Email: "any@example.com",
Subject: "First thread",
MessageHTML: "First post best post",
MessageText: "First post best post",
Password: "12345",
Filename: "12345.png",
FilenameOriginal: "somefile.png",
FileChecksum: "abcd1234",
FileExt: ".png",
Filesize: 1000,
ImageW: 2000,
ImageH: 2000,
ThumbW: 250,
ThumbH: 250,
IP: "192.168.56.1",
}, false)
if err != nil {
t.Fatal(err.Error())
}
}

557
pkg/gcsql/schema_test.go Normal file
View file

@ -0,0 +1,557 @@
package gcsql
import (
"regexp"
"github.com/DATA-DOG/go-sqlmock"
)
func createMockSchema() (err error) {
if gcdb == nil {
return ErrNotConnected
}
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_database_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(1, 1))
sqm.ExpectPrepare(regexp.QuoteMeta(`CREATE TABLE gc_sections(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(2, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_boards(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES gc_sections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(3, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_threads(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(4, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE INDEX thread_deleted_index ON gc_threads(is_deleted);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(5, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_posts(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES gc_threads(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(5, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_files(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES gc_posts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(6, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_staff(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(7, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_sessions(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_board_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_announcements(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES gc_posts(id) ON DELETE SET NULL
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES gc_ip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_appeals(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES gc_ip_ban(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_ip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES gc_ip_ban_appeals(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_reports(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES gc_staff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES gc_posts(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_reports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES gc_staff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES gc_reports(id) ON DELETE CASCADE
);`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_filename_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_username_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_file_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES gc_boards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id)
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
sqm.ExpectPrepare(prepTestQueryString(`CREATE TABLE gc_wordfilters(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES gc_staff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
)`)).ExpectExec().WillReturnResult(sqlmock.NewResult(8, 1))
// start fulfilling the expected execs
if _, err = ExecSQL(`CREATE TABLE DBPREFIXdatabase_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXsections(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXboards(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES DBPREFIXsections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXthreads(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE INDEX thread_deleted_index ON DBPREFIXthreads(is_deleted);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXposts(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES DBPREFIXthreads(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfiles(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXstaff(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXsessions(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXboard_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXannouncements(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES DBPREFIXposts(id) ON DELETE SET NULL
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_appeals(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES DBPREFIXip_ban_appeals(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXreports(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXreports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES DBPREFIXreports(id) ON DELETE CASCADE
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfilename_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXusername_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXfile_ban(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);`); err != nil {
return err
}
if _, err = ExecSQL(`CREATE TABLE DBPREFIXwordfilters(
id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
);`); err != nil {
return err
}
return sqm.ExpectationsWereMet()
}

View file

@ -0,0 +1,81 @@
package gcsql
import (
"testing"
"github.com/DATA-DOG/go-sqlmock"
)
func testCreateSection(section *BoardSection, lastInsertID int) error {
sqm.ExpectPrepare(prepTestQueryString(
`INSERT INTO gc_sections (name, abbreviation, hidden, position) VALUES (?,?,?,?)`,
)).ExpectExec().WithArgs(
section.Name, section.Abbreviation, section.Hidden, section.ListOrder,
).WillReturnResult(sqlmock.NewResult(int64(lastInsertID), 1))
sqm.ExpectPrepare(prepTestQueryString(
`SELECT id FROM gc_sections WHERE position = ?`,
)).ExpectQuery().WithArgs(section.ListOrder).WillReturnRows(
sqlmock.NewRows([]string{"id"}).AddRow(section.ID),
)
err := CreateSection(section)
if err != nil {
return err
}
return sqm.ExpectationsWereMet()
}
func TestSectionCreation(t *testing.T) {
section := &BoardSection{
ID: 2,
Name: "Staff",
Abbreviation: "hidden1",
Hidden: true,
ListOrder: 2,
}
err := testCreateSection(section, 1)
if err != nil {
t.Fatalf("Failed creating section 'Staff': %s", err.Error())
}
sqm.ExpectPrepare(prepTestQueryString(
`UPDATE gc_sections SET name = ?, abbreviation = ?, position = ?, hidden = ? where id = ?`,
)).ExpectExec().WithArgs("Staff", "hidden1", 2, true, 2).WillReturnResult(sqlmock.NewResult(2, 1))
if err = section.UpdateValues(); err != nil {
t.Fatalf("Error updating section: %s", err.Error())
}
if err = sqm.ExpectationsWereMet(); err != nil {
t.Fatal(err.Error())
}
}
func TestDeleteSections(t *testing.T) {
section := &BoardSection{
Name: "Temp",
Abbreviation: "temp",
Hidden: false,
ListOrder: 3,
}
err := testCreateSection(section, 3)
if err != nil {
t.Fatalf("Failed creating temporary section for deletion testing: %s", err.Error())
}
sqm.ExpectPrepare(prepTestQueryString(
`SELECT COUNT(*) FROM gc_sections`,
)).ExpectQuery().WillReturnRows(
sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(2),
)
sqm.ExpectPrepare(prepTestQueryString(
`DELETE FROM gc_sections WHERE id = ?`,
)).ExpectExec().WithArgs(3).WillReturnResult(sqlmock.NewResult(3, 1))
if err = DeleteSection(3); err != nil {
t.Fatalf("Error deleting section #2: %s", err.Error())
}
if err = sqm.ExpectationsWereMet(); err != nil {
t.Fatal(err.Error())
}
}

View file

@ -38,6 +38,8 @@ func SetupSQLString(query string, dbConn *GCDB) (string, error) {
switch dbConn.driver {
case "mysql":
prepared = query
case "sqlite3":
fallthrough
case "postgres":
arr := strings.Split(query, "?")
for i := range arr {

View file

@ -36,9 +36,9 @@ func InitCaptcha() {
return
}
driver = base64Captcha.NewDriverString(
boardConfig.CaptchaHeight, boardConfig.CaptchaWidth, 0, 0, 6,
boardConfig.CaptchaHeight, boardConfig.CaptchaWidth, int(0), int(0), int(6),
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
&color.RGBA{0, 0, 0, 0}, nil).ConvertFonts()
&color.RGBA{0, 0, 0, 0}, nil, nil).ConvertFonts()
}
// ServeCaptcha handles requests to /captcha if UseCaptcha is enabled in gochan.json

View file

@ -0,0 +1,271 @@
-- Gochan master template for new database script
-- Contains macros in the form [curlybrace open]macro text[curlybrace close]
-- Macros are substituted by build_initdb.py to the supported database files. Must not contain extra spaces
-- Versioning numbering goes by whole numbers. Upgrade script migrate existing databases between versions
-- Foreign and unique constraints must be named so they can be dropped.
-- MYSQL requires constraint names to be unique globally, hence the long constraint names.
-- Database version: 1
CREATE TABLE DBPREFIXdatabase_version(
component VARCHAR(40) NOT NULL PRIMARY KEY,
version INT NOT NULL
);
CREATE TABLE DBPREFIXsections(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name TEXT NOT NULL,
abbreviation TEXT NOT NULL,
position SMALLINT NOT NULL,
hidden BOOL NOT NULL
);
CREATE TABLE DBPREFIXboards(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
section_id BIGINT NOT NULL,
uri VARCHAR(45) NOT NULL,
dir VARCHAR(45) NOT NULL,
navbar_position SMALLINT NOT NULL,
title VARCHAR(45) NOT NULL,
subtitle VARCHAR(64) NOT NULL,
description VARCHAR(64) NOT NULL,
max_file_size INT NOT NULL,
max_threads SMALLINT NOT NULL,
default_style VARCHAR(45) NOT NULL,
locked BOOL NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
anonymous_name VARCHAR(45) NOT NULL DEFAULT 'Anonymous',
force_anonymous BOOL NOT NULL,
autosage_after SMALLINT NOT NULL,
no_images_after SMALLINT NOT NULL,
max_message_length SMALLINT NOT NULL,
min_message_length SMALLINT NOT NULL,
allow_embeds BOOL NOT NULL,
redirect_to_thread BOOL NOT NULL,
require_file BOOL NOT NULL,
enable_catalog BOOL NOT NULL,
CONSTRAINT boards_section_id_fk FOREIGN KEY(section_id) REFERENCES DBPREFIXsections(id),
CONSTRAINT boards_dir_unique UNIQUE(dir),
CONSTRAINT boards_uri_unique UNIQUE(uri)
);
CREATE TABLE DBPREFIXthreads(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT NOT NULL,
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
CONSTRAINT threads_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE
);
CREATE INDEX thread_deleted_index ON DBPREFIXthreads(is_deleted);
CREATE TABLE DBPREFIXposts(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
thread_id BIGINT NOT NULL,
is_top_post BOOL NOT NULL DEFAULT FALSE,
ip VARCHAR(45) NOT NULL,
created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(50) NOT NULL DEFAULT '',
tripcode VARCHAR(10) NOT NULL DEFAULT '',
is_role_signature BOOL NOT NULL DEFAULT FALSE,
email VARCHAR(50) NOT NULL DEFAULT '',
subject VARCHAR(100) NOT NULL DEFAULT '',
message TEXT NOT NULL,
message_raw TEXT NOT NULL,
password TEXT NOT NULL,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_deleted BOOL NOT NULL DEFAULT FALSE,
banned_message TEXT,
CONSTRAINT posts_thread_id_fk FOREIGN KEY(thread_id) REFERENCES DBPREFIXthreads(id) ON DELETE CASCADE
);
CREATE INDEX top_post_index ON DBPREFIXposts(is_top_post);
CREATE TABLE DBPREFIXfiles(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
post_id BIGINT NOT NULL,
file_order INT NOT NULL,
original_filename VARCHAR(255) NOT NULL,
filename VARCHAR(45) NOT NULL,
checksum TEXT NOT NULL,
file_size INT NOT NULL,
is_spoilered BOOL NOT NULL,
thumbnail_width INT NOT NULL,
thumbnail_height INT NOT NULL,
width INT NOT NULL,
height INT NOT NULL,
CONSTRAINT files_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE,
CONSTRAINT files_post_id_file_order_unique UNIQUE(post_id, file_order)
);
CREATE TABLE DBPREFIXstaff(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username VARCHAR(45) NOT NULL,
password_checksum VARCHAR(120) NOT NULL,
global_rank INT,
added_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_active BOOL NOT NULL DEFAULT TRUE,
CONSTRAINT staff_username_unique UNIQUE(username)
);
CREATE TABLE DBPREFIXsessions(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
expires TIMESTAMP NOT NULL,
data VARCHAR(45) NOT NULL,
CONSTRAINT sessions_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXboard_staff(
board_id BIGINT NOT NULL,
staff_id BIGINT NOT NULL,
CONSTRAINT board_staff_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT board_staff_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id) ON DELETE CASCADE,
CONSTRAINT board_staff_pk PRIMARY KEY (board_id,staff_id)
);
CREATE TABLE DBPREFIXannouncements(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
subject VARCHAR(45) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT announcements_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXip_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT NOT NULL,
board_id BIGINT,
banned_for_post_id BIGINT,
copy_post_text TEXT NOT NULL,
is_thread_ban BOOL NOT NULL,
is_active BOOL NOT NULL,
ip VARCHAR(45) NOT NULL,
issued_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
CONSTRAINT ip_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_banned_for_post_id_fk FOREIGN KEY(banned_for_post_id) REFERENCES DBPREFIXposts(id) ON DELETE SET NULL
);
CREATE TABLE DBPREFIXip_ban_audit(
ip_ban_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT NOT NULL,
is_active BOOL NOT NULL,
is_thread_ban BOOL NOT NULL,
expires_at TIMESTAMP NOT NULL,
appeal_at TIMESTAMP NOT NULL,
permanent BOOL NOT NULL,
staff_note VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
can_appeal BOOL NOT NULL,
PRIMARY KEY(ip_ban_id, timestamp),
CONSTRAINT ip_ban_audit_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE,
CONSTRAINT ip_ban_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXip_ban_appeals(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
staff_id BIGINT,
ip_ban_id BIGINT NOT NULL,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
CONSTRAINT ip_ban_appeals_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_ip_ban_id_fk FOREIGN KEY(ip_ban_id) REFERENCES DBPREFIXip_ban(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXip_ban_appeals_audit(
appeal_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
staff_id BIGINT,
appeal_text TEXT NOT NULL,
staff_response TEXT,
is_denied BOOL NOT NULL,
PRIMARY KEY(appeal_id, timestamp),
CONSTRAINT ip_ban_appeals_audit_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT ip_ban_appeals_audit_appeal_id_fk FOREIGN KEY(appeal_id) REFERENCES DBPREFIXip_ban_appeals(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXreports(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
handled_by_staff_id BIGINT,
post_id BIGINT NOT NULL,
ip VARCHAR(45) NOT NULL,
reason TEXT NOT NULL,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_post_id_fk FOREIGN KEY(post_id) REFERENCES DBPREFIXposts(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXreports_audit(
report_id BIGINT NOT NULL,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
handled_by_staff_id BIGINT,
is_cleared BOOL NOT NULL,
CONSTRAINT reports_audit_handled_by_staff_id_fk FOREIGN KEY(handled_by_staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT reports_audit_report_id_fk FOREIGN KEY(report_id) REFERENCES DBPREFIXreports(id) ON DELETE CASCADE
);
CREATE TABLE DBPREFIXfilename_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
filename VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT filename_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT filename_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXusername_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
is_regex BOOL NOT NULL,
CONSTRAINT username_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT username_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXfile_ban(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_id BIGINT,
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
checksum TEXT NOT NULL,
CONSTRAINT file_ban_board_id_fk FOREIGN KEY(board_id) REFERENCES DBPREFIXboards(id) ON DELETE CASCADE,
CONSTRAINT file_ban_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
);
CREATE TABLE DBPREFIXwordfilters(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
board_dirs VARCHAR(255) DEFAULT '*',
staff_id BIGINT NOT NULL,
staff_note VARCHAR(255) NOT NULL,
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
search VARCHAR(75) NOT NULL,
is_regex BOOL NOT NULL,
change_to VARCHAR(75) NOT NULL,
CONSTRAINT wordfilters_staff_id_fk FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id),
CONSTRAINT wordfilters_search_check CHECK (search <> '')
);
INSERT INTO DBPREFIXdatabase_version(component, version)
VALUES('gochan', 1);

View file

@ -3,6 +3,7 @@
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
export GO_VERSION=1.16
if [ -z "$DBTYPE" ]; then
echo "DBTYPE environment variable not set, must be 'mysql' or 'postgresql'."
@ -11,7 +12,7 @@ if [ -z "$DBTYPE" ]; then
fi
echo "Using DBTYPE $DBTYPE"
add-apt-repository -y ppa:gophers/archive
add-apt-repository -y ppa:longsleep/golang-backports
apt-get -y update && apt-get -y upgrade
if [ "$DBTYPE" == "mysql" ]; then
@ -54,6 +55,8 @@ elif [ "$DBTYPE" == "postgresql" ]; then
systemctl daemon-reload
systemctl enable gochan.service
fi
elif [ "$DBTYPE" == "sqlite3" ]; then
apt install sqlite3
elif [ "$DBTYPE" == "mssql" ]; then
# using Microsoft SQL Server (currently unsupported)
echo "Microsoft SQL Server not supported yet";
@ -63,9 +66,9 @@ else
exit 1
fi
apt-get -y install git subversion mercurial nginx ffmpeg golang-1.11
apt-get -y install git subversion mercurial nginx ffmpeg golang-${GO_VERSION}
ln -s /usr/lib/go-1.11/bin/* /usr/local/bin/
ln -sf /usr/lib/go-${GO_VERSION}/bin/* /usr/local/bin/
rm -f /etc/nginx/sites-enabled/* /etc/nginx/sites-available/*
ln -sf /vagrant/sample-configs/gochan-fastcgi.nginx /etc/nginx/sites-available/gochan.nginx