Merge pull request #211 from ajayyy/redis

Postgres
This commit is contained in:
Ajay Ramachandran 2021-03-08 19:28:05 -05:00 committed by GitHub
commit b641a0b0b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
62 changed files with 1016 additions and 670 deletions

3
.gitignore vendored
View file

@ -92,6 +92,8 @@ databases/sponsorTimes.db
databases/sponsorTimes.db-shm databases/sponsorTimes.db-shm
databases/sponsorTimes.db-wal databases/sponsorTimes.db-wal
databases/private.db databases/private.db
databases/private.db-shm
databases/private.db-wal
databases/sponsorTimesReal.db databases/sponsorTimesReal.db
test/databases/sponsorTimes.db test/databases/sponsorTimes.db
test/databases/sponsorTimes.db-shm test/databases/sponsorTimes.db-shm
@ -100,6 +102,7 @@ test/databases/private.db
# Config files # Config files
config.json config.json
docker/database.env
# Mac files # Mac files
.DS_Store .DS_Store

View file

@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS "config" (
"value" TEXT NOT NULL "value" TEXT NOT NULL
); );
CREATE INDEX IF NOT EXISTS sponsorTimes_hashedIP on sponsorTimes(hashedIP); CREATE INDEX IF NOT EXISTS "sponsorTimes_hashedIP" on "sponsorTimes"("hashedIP");
CREATE INDEX IF NOT EXISTS votes_userID on votes(UUID); CREATE INDEX IF NOT EXISTS "votes_userID" on "votes"("UUID");
COMMIT; COMMIT;

View file

@ -3,6 +3,11 @@ BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "vipUsers" ( CREATE TABLE IF NOT EXISTS "vipUsers" (
"userID" TEXT NOT NULL "userID" TEXT NOT NULL
); );
COMMIT;
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "sponsorTimes" ( CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL, "videoID" TEXT NOT NULL,
"startTime" REAL NOT NULL, "startTime" REAL NOT NULL,
@ -22,7 +27,7 @@ CREATE TABLE IF NOT EXISTS "userNames" (
CREATE TABLE IF NOT EXISTS "categoryVotes" ( CREATE TABLE IF NOT EXISTS "categoryVotes" (
"UUID" TEXT NOT NULL, "UUID" TEXT NOT NULL,
"category" TEXT NOT NULL, "category" TEXT NOT NULL,
"votes" INTEGER NOT NULL default '0' "votes" INTEGER NOT NULL default 0
); );
CREATE TABLE IF NOT EXISTS "config" ( CREATE TABLE IF NOT EXISTS "config" (
@ -30,7 +35,9 @@ CREATE TABLE IF NOT EXISTS "config" (
"value" TEXT NOT NULL "value" TEXT NOT NULL
); );
CREATE INDEX IF NOT EXISTS sponsorTimes_videoID on sponsorTimes(videoID); CREATE INDEX IF NOT EXISTS "sponsorTimes_videoID" on "sponsorTimes"("videoID");
CREATE INDEX IF NOT EXISTS sponsorTimes_UUID on sponsorTimes(UUID); CREATE INDEX IF NOT EXISTS "sponsorTimes_UUID" on "sponsorTimes"("UUID");
CREATE EXTENSION IF NOT EXISTS pgcrypto; --!sqlite-ignore
COMMIT; COMMIT;

View file

@ -3,6 +3,6 @@ BEGIN TRANSACTION;
/* for testing the db upgrade, don't remove because it looks empty */ /* for testing the db upgrade, don't remove because it looks empty */
/* Add version to config */ /* Add version to config */
INSERT INTO config (key, value) VALUES("version", 1); INSERT INTO config (key, value) VALUES('version', 1);
COMMIT; COMMIT;

View file

@ -6,20 +6,20 @@ CREATE TABLE "sqlb_temp_table_1" (
"startTime" REAL NOT NULL, "startTime" REAL NOT NULL,
"endTime" REAL NOT NULL, "endTime" REAL NOT NULL,
"votes" INTEGER NOT NULL, "votes" INTEGER NOT NULL,
"incorrectVotes" INTEGER NOT NULL default '1', "incorrectVotes" INTEGER NOT NULL default 1,
"UUID" TEXT NOT NULL UNIQUE, "UUID" TEXT NOT NULL UNIQUE,
"userID" TEXT NOT NULL, "userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL, "timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL, "views" INTEGER NOT NULL,
"category" TEXT NOT NULL DEFAULT "sponsor", "category" TEXT NOT NULL DEFAULT 'sponsor',
"shadowHidden" INTEGER NOT NULL "shadowHidden" INTEGER NOT NULL
); );
INSERT INTO sqlb_temp_table_1 SELECT videoID,startTime,endTime,votes,"1",UUID,userID,timeSubmitted,views,category,shadowHidden FROM sponsorTimes; INSERT INTO sqlb_temp_table_1 SELECT "videoID","startTime","endTime","votes",'1',"UUID","userID","timeSubmitted","views","category","shadowHidden" FROM "sponsorTimes";
DROP TABLE sponsorTimes; DROP TABLE "sponsorTimes";
ALTER TABLE sqlb_temp_table_1 RENAME TO "sponsorTimes"; ALTER TABLE sqlb_temp_table_1 RENAME TO "sponsorTimes";
/* Add version to config */ /* Add version to config */
INSERT INTO config (key, value) VALUES("version", 1); INSERT INTO config (key, value) VALUES('version', 1);
COMMIT; COMMIT;

View file

@ -8,6 +8,6 @@ CREATE TABLE "noSegments" (
); );
/* Add version to config */ /* Add version to config */
UPDATE config SET value = 2 WHERE key = 'version'; UPDATE "config" SET value = 2 WHERE key = 'version';
COMMIT; COMMIT;

View file

@ -1,13 +1,13 @@
BEGIN TRANSACTION; BEGIN TRANSACTION;
/* hash upgrade test sha256('vid') = '1ff838dc6ca9680d88455341118157d59a055fe6d0e3870f9c002847bebe4663' /* hash upgrade test sha256('vid') = '1ff838dc6ca9680d88455341118157d59a055fe6d0e3870f9c002847bebe4663' */
/* Add hash field */ /* Add hash field */
ALTER TABLE sponsorTimes ADD hashedVideoID TEXT NOT NULL default ""; ALTER TABLE "sponsorTimes" ADD "hashedVideoID" TEXT NOT NULL default '';
UPDATE sponsorTimes SET hashedVideoID = sha256(videoID); UPDATE "sponsorTimes" SET "hashedVideoID" = sha256("videoID");
CREATE INDEX IF NOT EXISTS sponsorTimes_hashedVideoID on sponsorTimes(hashedVideoID); CREATE INDEX IF NOT EXISTS "sponsorTimes_hashedVideoID" on "sponsorTimes"("hashedVideoID");
/* Bump version in config */ /* Bump version in config */
UPDATE config SET value = 3 WHERE key = "version"; UPDATE "config" SET value = 3 WHERE key = 'version';
COMMIT; COMMIT;

View file

@ -2,11 +2,11 @@ BEGIN TRANSACTION;
/* Create warnings table */ /* Create warnings table */
CREATE TABLE "warnings" ( CREATE TABLE "warnings" (
userID TEXT NOT NULL, "userID" TEXT NOT NULL,
issueTime INTEGER NOT NULL, "issueTime" INTEGER NOT NULL,
issuerUserID TEXT NOT NULL "issuerUserID" TEXT NOT NULL
); );
UPDATE config SET value = 4 WHERE key = "version"; UPDATE "config" SET value = 4 WHERE key = 'version';
COMMIT; COMMIT;

View file

@ -2,16 +2,16 @@ BEGIN TRANSACTION;
/* Add enabled field */ /* Add enabled field */
CREATE TABLE "sqlb_temp_table_5" ( CREATE TABLE "sqlb_temp_table_5" (
userID TEXT NOT NULL, "userID" TEXT NOT NULL,
issueTime INTEGER NOT NULL, "issueTime" INTEGER NOT NULL,
issuerUserID TEXT NOT NULL, "issuerUserID" TEXT NOT NULL,
enabled INTEGER NOT NULL enabled INTEGER NOT NULL
); );
INSERT INTO sqlb_temp_table_5 SELECT userID,issueTime,issuerUserID,1 FROM warnings; INSERT INTO sqlb_temp_table_5 SELECT "userID","issueTime","issuerUserID",1 FROM "warnings";
DROP TABLE warnings; DROP TABLE warnings;
ALTER TABLE sqlb_temp_table_5 RENAME TO "warnings"; ALTER TABLE sqlb_temp_table_5 RENAME TO "warnings";;
UPDATE config SET value = 5 WHERE key = "version"; UPDATE "config" SET value = 5 WHERE key = 'version';
COMMIT; COMMIT;

View file

@ -12,16 +12,16 @@ CREATE TABLE "sqlb_temp_table_6" (
"userID" TEXT NOT NULL, "userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL, "timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL, "views" INTEGER NOT NULL,
"category" TEXT NOT NULL DEFAULT "sponsor", "category" TEXT NOT NULL DEFAULT 'sponsor',
"shadowHidden" INTEGER NOT NULL, "shadowHidden" INTEGER NOT NULL,
"hashedVideoID" TEXT NOT NULL default "" "hashedVideoID" TEXT NOT NULL default ''
); );
INSERT INTO sqlb_temp_table_6 SELECT videoID,startTime,endTime,votes,"0",incorrectVotes,UUID,userID,timeSubmitted,views,category,shadowHidden,hashedVideoID FROM sponsorTimes; INSERT INTO sqlb_temp_table_6 SELECT "videoID","startTime","endTime","votes",'0',"incorrectVotes","UUID","userID","timeSubmitted","views","category","shadowHidden","hashedVideoID" FROM "sponsorTimes";
DROP TABLE sponsorTimes; DROP TABLE "sponsorTimes";
ALTER TABLE sqlb_temp_table_6 RENAME TO "sponsorTimes"; ALTER TABLE sqlb_temp_table_6 RENAME TO "sponsorTimes";
UPDATE config SET value = 6 WHERE key = "version"; UPDATE "config" SET value = 6 WHERE key = 'version';
COMMIT; COMMIT;

View file

@ -0,0 +1,3 @@
POSTGRES_USER=sponsorblock
POSTGRES_PASSWORD=<choose-a-password>
POSTGRES_DB=sponsorTimes

22
docker/docker-compose.yml Normal file
View file

@ -0,0 +1,22 @@
version: '3'
services:
database:
container_name: database
image: postgres
env_file:
- database.env
volumes:
- database-data:/var/lib/postgresql/data
ports:
- 127.0.0.1:5432:5432
redis:
container_name: redis
image: redis
command: /usr/local/etc/redis/redis.conf
volumes:
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
ports:
- 127.0.0.1:32773:6379
volumes:
database-data:

View file

@ -0,0 +1,5 @@
load database
from ./database.db
into postgresql://sponsorblock:pw@127.0.0.1:5432/sponsorTimes
with quote identifiers;

2
docker/redis/redis.conf Normal file
View file

@ -0,0 +1,2 @@
maxmemory-policy allkeys-lru
maxmemory 1000mb

134
package-lock.json generated
View file

@ -149,6 +149,17 @@
"form-data": "^3.0.0" "form-data": "^3.0.0"
} }
}, },
"@types/pg": {
"version": "7.14.10",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.14.10.tgz",
"integrity": "sha512-m6G0mrpj71YgVgHJF0cIHC3OZTKiQSUzTkMj869a+YWXF2tdbmO2PmIpNnDkiFPhHWcoGq2bk5P2e0CZX0F9Mg==",
"dev": true,
"requires": {
"@types/node": "*",
"pg-protocol": "^1.2.0",
"pg-types": "^2.2.0"
}
},
"@types/qs": { "@types/qs": {
"version": "6.9.5", "version": "6.9.5",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
@ -480,6 +491,11 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
}, },
"buffer-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
},
"bytes": { "bytes": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@ -738,6 +754,11 @@
"is-obj": "^1.0.0" "is-obj": "^1.0.0"
} }
}, },
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
"duplexer3": { "duplexer3": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@ -2011,6 +2032,11 @@
"semver": "^5.1.0" "semver": "^5.1.0"
} }
}, },
"packet-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
},
"parseurl": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -2045,6 +2071,60 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
}, },
"pg": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz",
"integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==",
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.4.0",
"pg-pool": "^3.2.2",
"pg-protocol": "^1.4.0",
"pg-types": "^2.1.0",
"pgpass": "1.x"
}
},
"pg-connection-string": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz",
"integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ=="
},
"pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
},
"pg-pool": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz",
"integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA=="
},
"pg-protocol": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz",
"integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA=="
},
"pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"requires": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
}
},
"pgpass": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz",
"integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==",
"requires": {
"split2": "^3.1.1"
}
},
"picomatch": { "picomatch": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
@ -2057,6 +2137,29 @@
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true "dev": true
}, },
"postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="
},
"postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
},
"postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="
},
"postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"requires": {
"xtend": "^4.0.0"
}
},
"prepend-http": { "prepend-http": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
@ -2132,6 +2235,16 @@
"strip-json-comments": "~2.0.1" "strip-json-comments": "~2.0.1"
} }
}, },
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"readdirp": { "readdirp": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
@ -2340,6 +2453,14 @@
"source-map": "^0.6.0" "source-map": "^0.6.0"
} }
}, },
"split2": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
"integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
"requires": {
"readable-stream": "^3.0.0"
}
},
"sprintf-js": { "sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -2425,6 +2546,14 @@
"es-abstract": "^1.17.5" "es-abstract": "^1.17.5"
} }
}, },
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strip-eof": { "strip-eof": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
@ -2854,6 +2983,11 @@
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
"dev": true "dev": true
}, },
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"y18n": { "y18n": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",

View file

@ -14,11 +14,13 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"better-sqlite3": "^5.4.3", "better-sqlite3": "^5.4.3",
"dotenv": "^8.2.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-rate-limit": "^5.1.3", "express-rate-limit": "^5.1.3",
"http": "0.0.0", "http": "0.0.0",
"iso8601-duration": "^1.2.0", "iso8601-duration": "^1.2.0",
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"pg": "^8.5.1",
"redis": "^3.0.2", "redis": "^3.0.2",
"sync-mysql": "^3.0.1", "sync-mysql": "^3.0.1",
"uuid": "^3.3.2", "uuid": "^3.3.2",
@ -31,6 +33,7 @@
"@types/mocha": "^8.0.3", "@types/mocha": "^8.0.3",
"@types/node": "^14.11.9", "@types/node": "^14.11.9",
"@types/node-fetch": "^2.5.7", "@types/node-fetch": "^2.5.7",
"@types/pg": "^7.14.10",
"@types/redis": "^2.8.28", "@types/redis": "^2.8.28",
"@types/request": "^2.48.5", "@types/request": "^2.48.5",
"mocha": "^7.1.1", "mocha": "^7.1.1",

View file

@ -45,6 +45,7 @@ addDefaults(config, {
}, },
userCounterURL: null, userCounterURL: null,
youtubeAPIKey: null, youtubeAPIKey: null,
postgres: null
}); });
// Add defaults // Add defaults

View file

@ -1,13 +1,7 @@
export interface IDatabase { export interface IDatabase {
init(): void; async init(): Promise<void>;
prepare(type: QueryType, query: string, params: any[]): any; prepare(type: QueryType, query: string, params?: any[]): Promise<any | any[] | void>;
get<TModel>(query: string, params: any[]): TModel;
getAll<TModel>(query: string, params: any[]): TModel[];
run(query: string, params: any[]): void;
exec(query: string): any;
} }
export type QueryType = 'get' | 'all' | 'run'; export type QueryType = 'get' | 'all' | 'run';

View file

@ -9,15 +9,11 @@ export class Mysql implements IDatabase {
constructor(private config: any) { constructor(private config: any) {
} }
init() { async init(): Promise<void> {
this.connection = new MysqlInterface(this.config); this.connection = new MysqlInterface(this.config);
} }
exec(query: string) { prepare(type: QueryType, query: string, params?: any[]) {
this.prepare('run', query, []);
}
prepare(type: QueryType, query: string, params: any[]) {
Logger.debug(`prepare (mysql): type: ${type}, query: ${query}, params: ${params}`); Logger.debug(`prepare (mysql): type: ${type}, query: ${query}, params: ${params}`);
const queryResult = this.connection.query(query, params); const queryResult = this.connection.query(query, params);
@ -34,16 +30,5 @@ export class Mysql implements IDatabase {
} }
} }
public get<TModel>(query: string, params: any[]): TModel {
return this.prepare('get', query, params);
}
public getAll<TModel>(query: string, params: any[]): TModel[] {
return this.prepare('all', query, params);
}
public run(query: string, params: any[]): void {
this.prepare('run', query, params);
}
} }

129
src/databases/Postgres.ts Normal file
View file

@ -0,0 +1,129 @@
import { Logger } from '../utils/logger';
import { IDatabase, QueryType } from './IDatabase';
import { Client, Pool } from 'pg';
import fs from "fs";
export class Postgres implements IDatabase {
private pool: Pool;
constructor(private config: any) {}
async init(): Promise<void> {
this.pool = new Pool(this.config.postgres);
if (!this.config.readOnly) {
if (this.config.createDbIfNotExists) {
await this.createDB();
}
if (this.config.createDbIfNotExists && !this.config.readOnly && fs.existsSync(this.config.dbSchemaFileName)) {
await this.pool.query(this.processUpgradeQuery(fs.readFileSync(this.config.dbSchemaFileName).toString()));
}
// Upgrade database if required
await this.upgradeDB(this.config.fileNamePrefix, this.config.dbSchemaFolder);
}
}
async prepare(type: QueryType, query: string, params?: any[]) {
// Convert query to use numbered parameters
let count = 1;
for (let char = 0; char < query.length; char++) {
if (query.charAt(char) === '?') {
query = query.slice(0, char) + "$" + count + query.slice(char + 1);
count++;
}
}
Logger.debug(`prepare (postgres): type: ${type}, query: ${query}, params: ${params}`);
const queryResult = await this.pool.query({text: query, values: params});
switch (type) {
case 'get': {
const value = queryResult.rows[0];
Logger.debug(`result (postgres): ${JSON.stringify(value)}`);
if (value) {
for (const [key, v] of Object.entries(value)) {
if (!isNaN(v as any)) {
value[key] = parseFloat(v as string)
}
}
}
Logger.debug(`result (postgres): ${value}`);
return value;
}
case 'all': {
let values = queryResult.rows;
if (values) {
values = values.map((row) => {
for (const [key, v] of Object.entries(row)) {
if (!isNaN(v as any)) {
row[key] = parseFloat(v as string)
}
}
return row;
});
}
Logger.debug(`result (postgres): ${values}`);
return values;
}
case 'run': {
break;
}
}
}
private async createDB() {
const client = new Client({
...this.config.postgres,
database: "postgres"
});
await client.connect();
if ((await client.query(`SELECT * FROM pg_database WHERE datname = '${this.config.postgres.database}'`)).rowCount == 0) {
await client.query(`CREATE DATABASE "${this.config.postgres.database}"
WITH
OWNER = ${this.config.postgres.user}
ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
TABLESPACE = pg_default
CONNECTION LIMIT = -1;`
);
}
client.end();
}
private async upgradeDB(fileNamePrefix: string, schemaFolder: string) {
const versionCodeInfo = await this.pool.query("SELECT value FROM config WHERE key = 'version'");
let versionCode = versionCodeInfo.rows[0] ? versionCodeInfo.rows[0].value : 0;
let path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
while (fs.existsSync(path)) {
Logger.debug('db update: updating ' + path);
await this.pool.query(this.processUpgradeQuery(fs.readFileSync(path).toString()));
versionCode = (await this.pool.query("SELECT value FROM config WHERE key = 'version'"))?.rows[0]?.value;
path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
Logger.debug('db update: trying ' + path);
}
Logger.debug('db update: no file ' + path);
}
private processUpgradeQuery(query: string): string {
let result = query;
result = result.replace(/sha256\((.*?)\)/gm, "digest($1, 'sha256')");
result = result.replace(/integer/gmi, "NUMERIC");
return result;
}
}

View file

@ -12,7 +12,8 @@ export class Sqlite implements IDatabase {
{ {
} }
prepare(type: QueryType, query: string, params: any[]) { async prepare(type: QueryType, query: string, params: any[] = []) {
// Logger.debug(`prepare (sqlite): type: ${type}, query: ${query}, params: ${params}`);
const preparedQuery = this.db.prepare(query); const preparedQuery = this.db.prepare(query);
switch (type) { switch (type) {
@ -29,21 +30,7 @@ export class Sqlite implements IDatabase {
} }
} }
get<TModel>(query: string, params: any[]): TModel { async init() {
return this.prepare('get', query, params);
}
getAll<TModel>(query: string, params: any[]): TModel[] {
return this.prepare('all', query, params);
}
run(query: string, params: any[]): void {
this.prepare('run', query, params);
}
exec(query: string) {
return this.db.exec(query);
}
init() {
// Make dirs if required // Make dirs if required
if (!fs.existsSync(path.join(this.config.dbPath, "../"))) { if (!fs.existsSync(path.join(this.config.dbPath, "../"))) {
fs.mkdirSync(path.join(this.config.dbPath, "../")); fs.mkdirSync(path.join(this.config.dbPath, "../"));
@ -52,7 +39,7 @@ export class Sqlite implements IDatabase {
this.db = new Sqlite3(this.config.dbPath, {readonly: this.config.readOnly, fileMustExist: !this.config.createDbIfNotExists}); this.db = new Sqlite3(this.config.dbPath, {readonly: this.config.readOnly, fileMustExist: !this.config.createDbIfNotExists});
if (this.config.createDbIfNotExists && !this.config.readOnly && fs.existsSync(this.config.dbSchemaFileName)) { if (this.config.createDbIfNotExists && !this.config.readOnly && fs.existsSync(this.config.dbSchemaFileName)) {
this.db.exec(fs.readFileSync(this.config.dbSchemaFileName).toString()); this.db.exec(Sqlite.processUpgradeQuery(fs.readFileSync(this.config.dbSchemaFileName).toString()));
} }
if (!this.config.readOnly) { if (!this.config.readOnly) {
@ -86,7 +73,7 @@ export class Sqlite implements IDatabase {
Logger.debug('db update: trying ' + path); Logger.debug('db update: trying ' + path);
while (fs.existsSync(path)) { while (fs.existsSync(path)) {
Logger.debug('db update: updating ' + path); Logger.debug('db update: updating ' + path);
db.exec(fs.readFileSync(path).toString()); db.exec(this.processUpgradeQuery(fs.readFileSync(path).toString()));
versionCode = db.prepare("SELECT value FROM config WHERE key = ?").get("version").value; versionCode = db.prepare("SELECT value FROM config WHERE key = ?").get("version").value;
path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql"; path = schemaFolder + "/_upgrade_" + fileNamePrefix + "_" + (parseInt(versionCode) + 1) + ".sql";
@ -94,6 +81,12 @@ export class Sqlite implements IDatabase {
} }
Logger.debug('db update: no file ' + path); Logger.debug('db update: no file ' + path);
} }
private static processUpgradeQuery(query: string): string {
let result = query.replace(/^.*--!sqlite-ignore/gm, "");
return result;
}
} }
export interface SqliteConfig { export interface SqliteConfig {

View file

@ -1,6 +1,7 @@
import {config} from '../config'; import {config} from '../config';
import {Sqlite} from './Sqlite'; import {Sqlite} from './Sqlite';
import {Mysql} from './Mysql'; import {Mysql} from './Mysql';
import {Postgres} from './Postgres';
import {IDatabase} from './IDatabase'; import {IDatabase} from './IDatabase';
@ -9,8 +10,37 @@ let privateDB: IDatabase;
if (config.mysql) { if (config.mysql) {
db = new Mysql(config.mysql); db = new Mysql(config.mysql);
privateDB = new Mysql(config.privateMysql); privateDB = new Mysql(config.privateMysql);
} } else if (config.postgres) {
else { db = new Postgres({
dbSchemaFileName: config.dbSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'sponsorTimes',
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
postgres: {
user: config.postgres?.user,
host: config.postgres?.host,
database: "sponsorTimes",
password: config.postgres?.password,
port: config.postgres?.port,
}
});
privateDB = new Postgres({
dbSchemaFileName: config.privateDBSchema,
dbSchemaFolder: config.schemaFolder,
fileNamePrefix: 'private',
readOnly: config.readOnly,
createDbIfNotExists: config.createDatabaseIfNotExist,
postgres: {
user: config.postgres?.user,
host: config.postgres?.host,
database: "privateDB",
password: config.postgres?.password,
port: config.postgres?.port,
}
});
} else {
db = new Sqlite({ db = new Sqlite({
dbPath: config.db, dbPath: config.db,
dbSchemaFileName: config.dbSchema, dbSchemaFileName: config.dbSchema,
@ -30,9 +60,9 @@ else {
enableWalCheckpointNumber: false enableWalCheckpointNumber: false
}); });
} }
function initDb() { async function initDb() {
db.init(); await db.init();
privateDB.init(); await privateDB.init();
if (db instanceof Sqlite) { if (db instanceof Sqlite) {
// Attach private db to main db // Attach private db to main db

View file

@ -3,7 +3,12 @@ import {initDb} from './databases/databases';
import {createServer} from "./app"; import {createServer} from "./app";
import {Logger} from "./utils/logger"; import {Logger} from "./utils/logger";
initDb(); async function init() {
createServer(() => { await initDb();
Logger.info("Server started on port " + config.port + ".");
}); createServer(() => {
Logger.info("Server started on port " + config.port + ".");
});
}
init();

View file

@ -16,8 +16,8 @@ export function rateLimitMiddleware(limitConfig: RateLimitConfig, getUserID?: (r
keyGenerator: (req) => { keyGenerator: (req) => {
return getHash(getIP(req), 1); return getHash(getIP(req), 1);
}, },
handler: (req, res, next) => { handler: async (req, res, next) => {
if (getUserID === undefined || !isUserVIP(getHash(getUserID(req)))) { if (getUserID === undefined || !await isUserVIP(getHash(getUserID(req)))) {
return res.status(limitConfig.statusCode).send(limitConfig.message); return res.status(limitConfig.statusCode).send(limitConfig.message);
} else { } else {
return next(); return next();

View file

@ -27,14 +27,14 @@ export async function addUserAsVIP(req: Request, res: Response) {
} }
//check to see if this user is already a vip //check to see if this user is already a vip
const row = db.prepare('get', "SELECT count(*) as userCount FROM vipUsers WHERE userID = ?", [userID]); const row = await db.prepare('get', 'SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?', [userID]);
if (enabled && row.userCount == 0) { if (enabled && row.userCount == 0) {
//add them to the vip list //add them to the vip list
db.prepare('run', "INSERT INTO vipUsers VALUES(?)", [userID]); await db.prepare('run', 'INSERT INTO "vipUsers" VALUES(?)', [userID]);
} else if (!enabled && row.userCount > 0) { } else if (!enabled && row.userCount > 0) {
//remove them from the shadow ban list //remove them from the shadow ban list
db.prepare('run', "DELETE FROM vipUsers WHERE userID = ?", [userID]); await db.prepare('run', 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]);
} }
res.sendStatus(200); res.sendStatus(200);

View file

@ -3,7 +3,7 @@ import {isUserVIP} from '../utils/isUserVIP';
import {getHash} from '../utils/getHash'; import {getHash} from '../utils/getHash';
import {db} from '../databases/databases'; import {db} from '../databases/databases';
export function deleteNoSegments(req: Request, res: Response) { export async function deleteNoSegments(req: Request, res: Response) {
// Collect user input data // Collect user input data
const videoID = req.body.videoID; const videoID = req.body.videoID;
let userID = req.body.userID; let userID = req.body.userID;
@ -24,7 +24,7 @@ export function deleteNoSegments(req: Request, res: Response) {
// Check if user is VIP // Check if user is VIP
userID = getHash(userID); userID = getHash(userID);
const userIsVIP = isUserVIP(userID); const userIsVIP = await isUserVIP(userID);
if (!userIsVIP) { if (!userIsVIP) {
res.status(403).json({ res.status(403).json({
@ -33,11 +33,13 @@ export function deleteNoSegments(req: Request, res: Response) {
return; return;
} }
db.prepare("all", 'SELECT * FROM noSegments WHERE videoID = ?', [videoID]).filter((entry: any) => { const entries = (await db.prepare("all", 'SELECT * FROM "noSegments" WHERE "videoID" = ?', [videoID])).filter((entry: any) => {
return (categories.indexOf(entry.category) !== -1); return (categories.indexOf(entry.category) !== -1);
}).forEach((entry: any) => {
db.prepare('run', 'DELETE FROM noSegments WHERE videoID = ? AND category = ?', [videoID, entry.category]);
}); });
for (const entry of entries) {
await db.prepare('run', 'DELETE FROM "noSegments" WHERE "videoID" = ? AND "category" = ?', [videoID, entry.category]);
}
res.status(200).json({message: 'Removed no segments entrys for video ' + videoID}); res.status(200).json({message: 'Removed no segments entrys for video ' + videoID});
} }

View file

@ -1,8 +1,8 @@
import {db} from '../databases/databases'; import {db} from '../databases/databases';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
export function getDaysSavedFormatted(req: Request, res: Response) { export async function getDaysSavedFormatted(req: Request, res: Response) {
let row = db.prepare('get', "SELECT SUM((endTime - startTime) / 60 / 60 / 24 * views) as daysSaved from sponsorTimes where shadowHidden != 1", []); let row = await db.prepare('get', 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
if (row !== undefined) { if (row !== undefined) {
//send this result //send this result

View file

@ -4,7 +4,7 @@ import {isUserVIP} from '../utils/isUserVIP';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
import { HashedUserID, UserID } from '../types/user.model'; import { HashedUserID, UserID } from '../types/user.model';
export function getIsUserVIP(req: Request, res: Response): void { export async function getIsUserVIP(req: Request, res: Response): Promise<void> {
const userID = req.query.userID as UserID; const userID = req.query.userID as UserID;
if (userID == undefined) { if (userID == undefined) {
@ -17,7 +17,7 @@ export function getIsUserVIP(req: Request, res: Response): void {
const hashedUserID: HashedUserID = getHash(userID); const hashedUserID: HashedUserID = getHash(userID);
try { try {
let vipState = isUserVIP(hashedUserID); let vipState = await isUserVIP(hashedUserID);
res.status(200).json({ res.status(200).json({
hashedUserID: hashedUserID, hashedUserID: hashedUserID,
vip: vipState, vip: vipState,

View file

@ -1,8 +1,9 @@
import {db} from '../databases/databases'; import {db} from '../databases/databases';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
import {getHash} from '../utils/getHash'; import {getHash} from '../utils/getHash';
import { Logger } from '../utils/logger';
export function getSavedTimeForUser(req: Request, res: Response) { export async function getSavedTimeForUser(req: Request, res: Response) {
let userID = req.query.userID as string; let userID = req.query.userID as string;
if (userID == undefined) { if (userID == undefined) {
@ -15,7 +16,7 @@ export function getSavedTimeForUser(req: Request, res: Response) {
userID = getHash(userID); userID = getHash(userID);
try { try {
let row = db.prepare("get", "SELECT SUM((endTime - startTime) / 60 * views) as minutesSaved FROM sponsorTimes WHERE userID = ? AND votes > -1 AND shadowHidden != 1 ", [userID]); let row = await db.prepare("get", 'SELECT SUM(("endTime" - "startTime") / 60 * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -1 AND "shadowHidden" != 1 ', [userID]);
if (row.minutesSaved != null) { if (row.minutesSaved != null) {
res.send({ res.send({
@ -25,7 +26,7 @@ export function getSavedTimeForUser(req: Request, res: Response) {
res.sendStatus(404); res.sendStatus(404);
} }
} catch (err) { } catch (err) {
console.log(err); Logger.error("getSavedTimeForUser " + err);
res.sendStatus(500); res.sendStatus(500);
return; return;

View file

@ -11,8 +11,8 @@ import { Logger } from '../utils/logger';
import redis from '../utils/redis'; import redis from '../utils/redis';
function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[], cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Segment[] { async function prepareCategorySegments(req: Request, videoID: VideoID, category: Category, segments: DBSegment[], cache: SegmentCache = {shadowHiddenSegmentIPs: {}}): Promise<Segment[]> {
const filteredSegments = segments.filter((segment) => { const shouldFilter: boolean[] = await Promise.all(segments.map(async (segment) => {
if (segment.votes < -1) { if (segment.votes < -1) {
return false; //too untrustworthy, just ignore it return false; //too untrustworthy, just ignore it
} }
@ -24,7 +24,7 @@ function prepareCategorySegments(req: Request, videoID: VideoID, category: Categ
} }
if (cache.shadowHiddenSegmentIPs[videoID] === undefined) { if (cache.shadowHiddenSegmentIPs[videoID] === undefined) {
cache.shadowHiddenSegmentIPs[videoID] = privateDB.prepare('all', 'SELECT hashedIP FROM sponsorTimes WHERE videoID = ?', [videoID]) as { hashedIP: HashedIP }[]; cache.shadowHiddenSegmentIPs[videoID] = await privateDB.prepare('all', 'SELECT "hashedIP" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]) as { hashedIP: HashedIP }[];
} }
//if this isn't their ip, don't send it to them //if this isn't their ip, don't send it to them
@ -36,7 +36,9 @@ function prepareCategorySegments(req: Request, videoID: VideoID, category: Categ
return shadowHiddenSegment.hashedIP === cache.userHashedIP; return shadowHiddenSegment.hashedIP === cache.userHashedIP;
}); });
}); }));
const filteredSegments = segments.filter((_, index) => shouldFilter[index]);
return chooseSegments(filteredSegments).map((chosenSegment) => ({ return chooseSegments(filteredSegments).map((chosenSegment) => ({
category, category,
@ -45,17 +47,20 @@ function prepareCategorySegments(req: Request, videoID: VideoID, category: Categ
})); }));
} }
function getSegmentsByVideoID(req: Request, videoID: string, categories: Category[]): Segment[] { async function getSegmentsByVideoID(req: Request, videoID: string, categories: Category[]): Promise<Segment[]> {
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}}; const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
const segments: Segment[] = []; const segments: Segment[] = [];
try { try {
const segmentsByCategory: SBRecord<Category, DBSegment[]> = db categories = categories.filter((category) => !/[^a-z|_|-]/.test(category));
const segmentsByCategory: SBRecord<Category, DBSegment[]> = (await db
.prepare( .prepare(
'all', 'all',
`SELECT startTime, endTime, votes, locked, UUID, category, shadowHidden FROM sponsorTimes WHERE videoID = ? AND category IN (${Array(categories.length).fill('?').join()}) ORDER BY startTime`, `SELECT "startTime", "endTime", "votes", "locked", "UUID", "category", "shadowHidden" FROM "sponsorTimes"
[videoID, categories] WHERE "videoID" = ? AND "category" IN (${categories.map((c) => "'" + c + "'")}) ORDER BY "startTime"`,
).reduce((acc: SBRecord<Category, DBSegment[]>, segment: DBSegment) => { [videoID]
)).reduce((acc: SBRecord<Category, DBSegment[]>, segment: DBSegment) => {
acc[segment.category] = acc[segment.category] || []; acc[segment.category] = acc[segment.category] || [];
acc[segment.category].push(segment); acc[segment.category].push(segment);
@ -63,7 +68,7 @@ function getSegmentsByVideoID(req: Request, videoID: string, categories: Categor
}, {}); }, {});
for (const [category, categorySegments] of Object.entries(segmentsByCategory)) { for (const [category, categorySegments] of Object.entries(segmentsByCategory)) {
segments.push(...prepareCategorySegments(req, videoID as VideoID, category as Category, categorySegments, cache)); segments.push(...(await prepareCategorySegments(req, videoID as VideoID, category as Category, categorySegments, cache)));
} }
return segments; return segments;
@ -75,19 +80,22 @@ function getSegmentsByVideoID(req: Request, videoID: string, categories: Categor
} }
} }
function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[]): SBRecord<VideoID, VideoData> { async function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categories: Category[]): Promise<SBRecord<VideoID, VideoData>> {
const cache: SegmentCache = {shadowHiddenSegmentIPs: {}}; const cache: SegmentCache = {shadowHiddenSegmentIPs: {}};
const segments: SBRecord<VideoID, VideoData> = {}; const segments: SBRecord<VideoID, VideoData> = {};
try { try {
type SegmentWithHashPerVideoID = SBRecord<VideoID, {hash: VideoIDHash, segmentPerCategory: SBRecord<Category, DBSegment[]>}>; type SegmentWithHashPerVideoID = SBRecord<VideoID, {hash: VideoIDHash, segmentPerCategory: SBRecord<Category, DBSegment[]>}>;
const segmentPerVideoID: SegmentWithHashPerVideoID = db categories = categories.filter((category) => !(/[^a-z|_|-]/.test(category)));
const segmentPerVideoID: SegmentWithHashPerVideoID = (await db
.prepare( .prepare(
'all', 'all',
`SELECT videoID, startTime, endTime, votes, locked, UUID, category, shadowHidden, hashedVideoID FROM sponsorTimes WHERE hashedVideoID LIKE ? AND category IN (${Array(categories.length).fill('?').join()}) ORDER BY startTime`, `SELECT "videoID", "startTime", "endTime", "votes", "locked", "UUID", "category", "shadowHidden", "hashedVideoID" FROM "sponsorTimes"
[hashedVideoIDPrefix + '%', categories] WHERE "hashedVideoID" LIKE ? AND "category" IN (${categories.map((c) => "'" + c + "'")}) ORDER BY "startTime"`,
).reduce((acc: SegmentWithHashPerVideoID, segment: DBSegment) => { [hashedVideoIDPrefix + '%']
)).reduce((acc: SegmentWithHashPerVideoID, segment: DBSegment) => {
acc[segment.videoID] = acc[segment.videoID] || { acc[segment.videoID] = acc[segment.videoID] || {
hash: segment.hashedVideoID, hash: segment.hashedVideoID,
segmentPerCategory: {}, segmentPerCategory: {},
@ -107,7 +115,7 @@ function getSegmentsByHash(req: Request, hashedVideoIDPrefix: VideoIDHash, categ
}; };
for (const [category, segmentPerCategory] of Object.entries(videoData.segmentPerCategory)) { for (const [category, segmentPerCategory] of Object.entries(videoData.segmentPerCategory)) {
segments[videoID].segments.push(...prepareCategorySegments(req, videoID as VideoID, category as Category, segmentPerCategory, cache)); segments[videoID].segments.push(...(await prepareCategorySegments(req, videoID as VideoID, category as Category, segmentPerCategory, cache)));
} }
} }
@ -241,7 +249,7 @@ async function handleGetSegments(req: Request, res: Response): Promise<Segment[]
} }
} }
const segments = getSegmentsByVideoID(req, videoID, categories); const segments = await getSegmentsByVideoID(req, videoID, categories);
if (segments === null || segments === undefined) { if (segments === null || segments === undefined) {
res.sendStatus(500); res.sendStatus(500);

View file

@ -29,7 +29,7 @@ export async function getSkipSegmentsByHash(req: Request, res: Response) {
categories = categories.filter((item: any) => typeof item === "string"); categories = categories.filter((item: any) => typeof item === "string");
// Get all video id's that match hash prefix // Get all video id's that match hash prefix
const segments = getSegmentsByHash(req, hashPrefix, categories); const segments = await getSegmentsByHash(req, hashPrefix, categories);
if (!segments) return res.status(404).json([]); if (!segments) return res.status(404).json([]);

View file

@ -6,60 +6,58 @@ import {Request, Response} from 'express';
const MILLISECONDS_IN_MINUTE = 60000; const MILLISECONDS_IN_MINUTE = 60000;
const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE); const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE);
function generateTopUsersStats(sortBy: string, categoryStatsEnabled: boolean = false) { async function generateTopUsersStats(sortBy: string, categoryStatsEnabled: boolean = false) {
return new Promise((resolve) => { const userNames = [];
const userNames = []; const viewCounts = [];
const viewCounts = []; const totalSubmissions = [];
const totalSubmissions = []; const minutesSaved = [];
const minutesSaved = []; const categoryStats: any[] = categoryStatsEnabled ? [] : undefined;
const categoryStats: any[] = categoryStatsEnabled ? [] : undefined;
let additionalFields = ''; let additionalFields = '';
if (categoryStatsEnabled) {
additionalFields += `SUM(CASE WHEN category = 'sponsor' THEN 1 ELSE 0 END) as "categorySponsor",
SUM(CASE WHEN category = 'intro' THEN 1 ELSE 0 END) as "categorySumIntro",
SUM(CASE WHEN category = 'outro' THEN 1 ELSE 0 END) as "categorySumOutro",
SUM(CASE WHEN category = 'interaction' THEN 1 ELSE 0 END) as "categorySumInteraction",
SUM(CASE WHEN category = 'selfpromo' THEN 1 ELSE 0 END) as "categorySelfpromo",
SUM(CASE WHEN category = 'music_offtopic' THEN 1 ELSE 0 END) as "categoryMusicOfftopic", `;
}
const rows = await db.prepare('all', `SELECT COUNT(*) as "totalSubmissions", SUM(views) as "viewCount",
SUM(("sponsorTimes"."endTime" - "sponsorTimes"."startTime") / 60 * "sponsorTimes"."views") as "minutesSaved",
SUM("votes") as "userVotes", ` +
additionalFields +
`IFNULL("userNames"."userName", "sponsorTimes"."userID") as "userName" FROM "sponsorTimes" LEFT JOIN "userNames" ON "sponsorTimes"."userID"="userNames"."userID"
LEFT JOIN "privateDB"."shadowBannedUsers" ON "sponsorTimes"."userID"="privateDB"."shadowBannedUsers"."userID"
WHERE "sponsorTimes"."votes" > -1 AND "sponsorTimes"."shadowHidden" != 1 AND "privateDB"."shadowBannedUsers"."userID" IS NULL
GROUP BY IFNULL("userName", "sponsorTimes"."userID") HAVING "userVotes" > 20
ORDER BY "` + sortBy + `" DESC LIMIT 100`, []);
for (let i = 0; i < rows.length; i++) {
userNames[i] = rows[i].userName;
viewCounts[i] = rows[i].viewCount;
totalSubmissions[i] = rows[i].totalSubmissions;
minutesSaved[i] = rows[i].minutesSaved;
if (categoryStatsEnabled) { if (categoryStatsEnabled) {
additionalFields += "SUM(CASE WHEN category = 'sponsor' THEN 1 ELSE 0 END) as categorySponsor, " + categoryStats[i] = [
"SUM(CASE WHEN category = 'intro' THEN 1 ELSE 0 END) as categorySumIntro, " + rows[i].categorySponsor,
"SUM(CASE WHEN category = 'outro' THEN 1 ELSE 0 END) as categorySumOutro, " + rows[i].categorySumIntro,
"SUM(CASE WHEN category = 'interaction' THEN 1 ELSE 0 END) as categorySumInteraction, " + rows[i].categorySumOutro,
"SUM(CASE WHEN category = 'selfpromo' THEN 1 ELSE 0 END) as categorySelfpromo, " + rows[i].categorySumInteraction,
"SUM(CASE WHEN category = 'music_offtopic' THEN 1 ELSE 0 END) as categoryMusicOfftopic, "; rows[i].categorySelfpromo,
rows[i].categoryMusicOfftopic,
];
} }
}
const rows = db.prepare('all', "SELECT COUNT(*) as totalSubmissions, SUM(views) as viewCount," + return {
"SUM((sponsorTimes.endTime - sponsorTimes.startTime) / 60 * sponsorTimes.views) as minutesSaved, " + userNames,
"SUM(votes) as userVotes, " + viewCounts,
additionalFields + totalSubmissions,
"IFNULL(userNames.userName, sponsorTimes.userID) as userName FROM sponsorTimes LEFT JOIN userNames ON sponsorTimes.userID=userNames.userID " + minutesSaved,
"LEFT JOIN privateDB.shadowBannedUsers ON sponsorTimes.userID=privateDB.shadowBannedUsers.userID " + categoryStats,
"WHERE sponsorTimes.votes > -1 AND sponsorTimes.shadowHidden != 1 AND privateDB.shadowBannedUsers.userID IS NULL " + };
"GROUP BY IFNULL(userName, sponsorTimes.userID) HAVING userVotes > 20 " +
"ORDER BY " + sortBy + " DESC LIMIT 100", []);
for (let i = 0; i < rows.length; i++) {
userNames[i] = rows[i].userName;
viewCounts[i] = rows[i].viewCount;
totalSubmissions[i] = rows[i].totalSubmissions;
minutesSaved[i] = rows[i].minutesSaved;
if (categoryStatsEnabled) {
categoryStats[i] = [
rows[i].categorySponsor,
rows[i].categorySumIntro,
rows[i].categorySumOutro,
rows[i].categorySumInteraction,
rows[i].categorySelfpromo,
rows[i].categoryMusicOfftopic,
];
}
}
resolve({
userNames,
viewCounts,
totalSubmissions,
minutesSaved,
categoryStats,
});
});
} }
export async function getTopUsers(req: Request, res: Response) { export async function getTopUsers(req: Request, res: Response) {

View file

@ -13,9 +13,9 @@ let apiUsersCache = 0;
let lastUserCountCheck = 0; let lastUserCountCheck = 0;
export function getTotalStats(req: Request, res: Response) { export async function getTotalStats(req: Request, res: Response) {
let row = db.prepare('get', "SELECT COUNT(DISTINCT userID) as userCount, COUNT(*) as totalSubmissions, " + let row = await db.prepare('get', `SELECT COUNT(DISTINCT "userID") as "userCount", COUNT(*) as "totalSubmissions",
"SUM(views) as viewCount, SUM((endTime - startTime) / 60 * views) as minutesSaved FROM sponsorTimes WHERE shadowHidden != 1 AND votes >= 0", []); SUM("views") as "viewCount", SUM(("endTime" - "startTime") / 60 * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "shadowHidden" != 1 AND "votes" >= 0`, []);
if (row !== undefined) { if (row !== undefined) {
let extensionUsers = chromeUsersCache + firefoxUsersCache; let extensionUsers = chromeUsersCache + firefoxUsersCache;

View file

@ -3,9 +3,9 @@ import {getHash} from '../utils/getHash';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
import {Logger} from '../utils/logger' import {Logger} from '../utils/logger'
function dbGetSubmittedSegmentSummary(userID: string): any { async function dbGetSubmittedSegmentSummary(userID: string): Promise<{ minutesSaved: number, segmentCount: number }> {
try { try {
let row = db.prepare("get", "SELECT SUM(((endTime - startTime) / 60) * views) as minutesSaved, count(*) as segmentCount FROM sponsorTimes WHERE userID = ? AND votes > -2 AND shadowHidden != 1", [userID]); let row = await db.prepare("get", `SELECT SUM((("endTime" - "startTime") / 60) * "views") as "minutesSaved", count(*) as "segmentCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]);
if (row.minutesSaved != null) { if (row.minutesSaved != null) {
return { return {
minutesSaved: row.minutesSaved, minutesSaved: row.minutesSaved,
@ -18,13 +18,13 @@ function dbGetSubmittedSegmentSummary(userID: string): any {
}; };
} }
} catch (err) { } catch (err) {
return false; return null;
} }
} }
function dbGetUsername(userID: string) { async function dbGetUsername(userID: string) {
try { try {
let row = db.prepare('get', "SELECT userName FROM userNames WHERE userID = ?", [userID]); let row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
if (row !== undefined) { if (row !== undefined) {
return row.userName; return row.userName;
} else { } else {
@ -36,9 +36,9 @@ function dbGetUsername(userID: string) {
} }
} }
function dbGetViewsForUser(userID: string) { async function dbGetViewsForUser(userID: string) {
try { try {
let row = db.prepare('get', "SELECT SUM(views) as viewCount FROM sponsorTimes WHERE userID = ? AND votes > -2 AND shadowHidden != 1", [userID]); let row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]);
//increase the view count by one //increase the view count by one
if (row.viewCount != null) { if (row.viewCount != null) {
return row.viewCount; return row.viewCount;
@ -50,9 +50,9 @@ function dbGetViewsForUser(userID: string) {
} }
} }
function dbGetWarningsForUser(userID: string): number { async function dbGetWarningsForUser(userID: string): Promise<number> {
try { try {
let rows = db.prepare('all', "SELECT * FROM warnings WHERE userID = ?", [userID]); let rows = await db.prepare('all', `SELECT * FROM "warnings" WHERE "userID" = ?`, [userID]);
return rows.length; return rows.length;
} catch (err) { } catch (err) {
Logger.error('Couldn\'t get warnings for user ' + userID + '. returning 0'); Logger.error('Couldn\'t get warnings for user ' + userID + '. returning 0');
@ -60,7 +60,7 @@ function dbGetWarningsForUser(userID: string): number {
} }
} }
export function getUserInfo(req: Request, res: Response) { export async function getUserInfo(req: Request, res: Response) {
let userID = req.query.userID as string; let userID = req.query.userID as string;
if (userID == undefined) { if (userID == undefined) {
@ -72,13 +72,17 @@ export function getUserInfo(req: Request, res: Response) {
//hash the userID //hash the userID
userID = getHash(userID); userID = getHash(userID);
const segmentsSummary = dbGetSubmittedSegmentSummary(userID); const segmentsSummary = await dbGetSubmittedSegmentSummary(userID);
res.send({ if (segmentsSummary) {
userID, res.send({
userName: dbGetUsername(userID), userID,
minutesSaved: segmentsSummary.minutesSaved, userName: await dbGetUsername(userID),
segmentCount: segmentsSummary.segmentCount, minutesSaved: segmentsSummary.minutesSaved,
viewCount: dbGetViewsForUser(userID), segmentCount: segmentsSummary.segmentCount,
warnings: dbGetWarningsForUser(userID), viewCount: await dbGetViewsForUser(userID),
}); warnings: await dbGetWarningsForUser(userID),
});
} else {
res.status(400).send();
}
} }

View file

@ -3,7 +3,7 @@ import {getHash} from '../utils/getHash';
import {Logger} from '../utils/logger'; import {Logger} from '../utils/logger';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
export function getUsername(req: Request, res: Response) { export async function getUsername(req: Request, res: Response) {
let userID = req.query.userID as string; let userID = req.query.userID as string;
if (userID == undefined) { if (userID == undefined) {
@ -16,7 +16,7 @@ export function getUsername(req: Request, res: Response) {
userID = getHash(userID); userID = getHash(userID);
try { try {
let row = db.prepare('get', "SELECT userName FROM userNames WHERE userID = ?", [userID]); let row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
if (row !== undefined) { if (row !== undefined) {
res.send({ res.send({

View file

@ -3,7 +3,7 @@ import {Request, Response} from 'express';
import {getHash} from '../utils/getHash'; import {getHash} from '../utils/getHash';
import {Logger} from '../utils/logger'; import {Logger} from '../utils/logger';
export function getViewsForUser(req: Request, res: Response) { export async function getViewsForUser(req: Request, res: Response) {
let userID = req.query.userID as string; let userID = req.query.userID as string;
if (userID == undefined) { if (userID == undefined) {
@ -16,7 +16,7 @@ export function getViewsForUser(req: Request, res: Response) {
userID = getHash(userID); userID = getHash(userID);
try { try {
let row = db.prepare('get', "SELECT SUM(views) as viewCount FROM sponsorTimes WHERE userID = ?", [userID]); let row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
//increase the view count by one //increase the view count by one
if (row.viewCount != null) { if (row.viewCount != null) {

View file

@ -4,7 +4,7 @@ import {isUserVIP} from '../utils/isUserVIP';
import {db} from '../databases/databases'; import {db} from '../databases/databases';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
export function postNoSegments(req: Request, res: Response) { export async function postNoSegments(req: Request, res: Response) {
// Collect user input data // Collect user input data
let videoID = req.body.videoID; let videoID = req.body.videoID;
let userID = req.body.userID; let userID = req.body.userID;
@ -25,7 +25,7 @@ export function postNoSegments(req: Request, res: Response) {
// Check if user is VIP // Check if user is VIP
userID = getHash(userID); userID = getHash(userID);
let userIsVIP = isUserVIP(userID); let userIsVIP = await isUserVIP(userID);
if (!userIsVIP) { if (!userIsVIP) {
res.status(403).json({ res.status(403).json({
@ -35,7 +35,7 @@ export function postNoSegments(req: Request, res: Response) {
} }
// Get existing no segment markers // Get existing no segment markers
let noSegmentList = db.prepare('all', 'SELECT category from noSegments where videoID = ?', [videoID]); let noSegmentList = await db.prepare('all', 'SELECT "category" from "noSegments" where "videoID" = ?', [videoID]);
if (!noSegmentList || noSegmentList.length === 0) { if (!noSegmentList || noSegmentList.length === 0) {
noSegmentList = []; noSegmentList = [];
} else { } else {
@ -57,9 +57,9 @@ export function postNoSegments(req: Request, res: Response) {
}); });
// create database entry // create database entry
categoriesToMark.forEach((category) => { for (const category of categoriesToMark) {
try { try {
db.prepare('run', "INSERT INTO noSegments (videoID, userID, category) VALUES(?, ?, ?)", [videoID, userID, category]); await db.prepare('run', `INSERT INTO "noSegments" ("videoID", "userID", "category") VALUES(?, ?, ?)`, [videoID, userID, category]);
} catch (err) { } catch (err) {
Logger.error("Error submitting 'noSegment' marker for category '" + category + "' for video '" + videoID + "'"); Logger.error("Error submitting 'noSegment' marker for category '" + category + "' for video '" + videoID + "'");
Logger.error(err); Logger.error(err);
@ -67,7 +67,7 @@ export function postNoSegments(req: Request, res: Response) {
message: "Internal Server Error: Could not write marker to the database.", message: "Internal Server Error: Could not write marker to the database.",
}); });
} }
}); };
res.status(200).json({ res.status(200).json({
submitted: categoriesToMark, submitted: categoriesToMark,

View file

@ -45,7 +45,7 @@ function shiftSegment(segment: any, shift: { startTime: any; endTime: any }) {
return {action: ACTION_NONE, segment}; return {action: ACTION_NONE, segment};
} }
export function postSegmentShift(req: Request, res: Response): Response { export async function postSegmentShift(req: Request, res: Response): Promise<Response> {
// Collect user input data // Collect user input data
const videoID = req.body.videoID; const videoID = req.body.videoID;
const startTime = req.body.startTime; const startTime = req.body.startTime;
@ -66,7 +66,7 @@ export function postSegmentShift(req: Request, res: Response): Response {
// Check if user is VIP // Check if user is VIP
userID = getHash(userID); userID = getHash(userID);
const userIsVIP = isUserVIP(userID); const userIsVIP = await isUserVIP(userID);
if (!userIsVIP) { if (!userIsVIP) {
res.status(403).json({ res.status(403).json({
@ -76,22 +76,23 @@ export function postSegmentShift(req: Request, res: Response): Response {
} }
try { try {
const segments = db.prepare('all', 'SELECT startTime, endTime, UUID FROM sponsorTimes WHERE videoID = ?', [videoID]); const segments = await db.prepare('all', 'SELECT "startTime", "endTime", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?', [videoID]);
const shift = { const shift = {
startTime, startTime,
endTime, endTime,
}; };
segments.forEach((segment: any) => {
for (const segment of segments) {
const result = shiftSegment(segment, shift); const result = shiftSegment(segment, shift);
switch (result.action) { switch (result.action) {
case ACTION_UPDATE: case ACTION_UPDATE:
db.prepare('run', 'UPDATE sponsorTimes SET startTime = ?, endTime = ? WHERE UUID = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break; break;
case ACTION_REMOVE: case ACTION_REMOVE:
db.prepare('run', 'UPDATE sponsorTimes SET startTime = ?, endTime = ?, votes = -2 WHERE UUID = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ?, "votes" = -2 WHERE "UUID" = ?', [result.segment.startTime, result.segment.endTime, result.segment.UUID]);
break; break;
} }
}); };
} catch (err) { } catch (err) {
Logger.error(err); Logger.error(err);
res.sendStatus(500); res.sendStatus(500);

View file

@ -15,8 +15,8 @@ import { skipSegmentsKey } from '../middleware/redisKeys';
import redis from '../utils/redis'; import redis from '../utils/redis';
function sendWebhookNotification(userID: string, videoID: string, UUID: string, submissionCount: number, youtubeData: any, {submissionStart, submissionEnd}: { submissionStart: number; submissionEnd: number; }, segmentInfo: any) { async function sendWebhookNotification(userID: string, videoID: string, UUID: string, submissionCount: number, youtubeData: any, {submissionStart, submissionEnd}: { submissionStart: number; submissionEnd: number; }, segmentInfo: any) {
const row = db.prepare('get', "SELECT userName FROM userNames WHERE userID = ?", [userID]); const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]);
const userName = row !== undefined ? row.userName : null; const userName = row !== undefined ? row.userName : null;
const video = youtubeData.items[0]; const video = youtubeData.items[0];
@ -45,9 +45,9 @@ function sendWebhookNotification(userID: string, videoID: string, UUID: string,
}); });
} }
function sendWebhooks(userID: string, videoID: string, UUID: string, segmentInfo: any) { async function sendWebhooks(userID: string, videoID: string, UUID: string, segmentInfo: any) {
if (config.youtubeAPIKey !== null) { if (config.youtubeAPIKey !== null) {
const userSubmissionCountRow = db.prepare('get', "SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?", [userID]); const userSubmissionCountRow = await db.prepare('get', `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
YouTubeAPI.listVideos(videoID, (err: any, data: any) => { YouTubeAPI.listVideos(videoID, (err: any, data: any) => {
if (err || data.items.length === 0) { if (err || data.items.length === 0) {
@ -105,11 +105,11 @@ function sendWebhooks(userID: string, videoID: string, UUID: string, segmentInfo
} }
} }
function sendWebhooksNB(userID: string, videoID: string, UUID: string, startTime: number, endTime: number, category: string, probability: number, ytData: any) { async function sendWebhooksNB(userID: string, videoID: string, UUID: string, startTime: number, endTime: number, category: string, probability: number, ytData: any) {
const submissionInfoRow = db.prepare('get', "SELECT " + const submissionInfoRow = await db.prepare('get', `SELECT
"(select count(1) from sponsorTimes where userID = ?) count, " + (select count(1) from "sponsorTimes" where "userID" = ?) count,
"(select count(1) from sponsorTimes where userID = ? and votes <= -2) disregarded, " + (select count(1) from "sponsorTimes" where "userID" = ? and "votes" <= -2) disregarded,
"coalesce((select userName FROM userNames WHERE userID = ?), ?) userName", coalesce((select "userName" FROM "userNames" WHERE "userID" = ?), ?) "userName"`,
[userID, userID, userID, userID]); [userID, userID, userID, userID]);
let submittedBy: string; let submittedBy: string;
@ -304,20 +304,20 @@ export async function postSkipSegments(req: Request, res: Response) {
const MILLISECONDS_IN_HOUR = 3600000; const MILLISECONDS_IN_HOUR = 3600000;
const now = Date.now(); const now = Date.now();
const warningsCount = db.prepare('get', "SELECT count(1) as count FROM warnings WHERE userID = ? AND issueTime > ? AND enabled = 1", const warningsCount = (await db.prepare('get', `SELECT count(1) as count FROM warnings WHERE "userID" = ? AND "issueTime" > ? AND enabled = 1`,
[userID, Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR))], [userID, Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR))],
).count; )).count;
if (warningsCount >= config.maxNumberOfActiveWarnings) { if (warningsCount >= config.maxNumberOfActiveWarnings) {
return res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); return res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?');
} }
const noSegmentList = db.prepare('all', 'SELECT category from noSegments where videoID = ?', [videoID]).map((list: any) => { const noSegmentList = (await db.prepare('all', 'SELECT category from "noSegments" where "videoID" = ?', [videoID])).map((list: any) => {
return list.category; return list.category;
}); });
//check if this user is on the vip list //check if this user is on the vip list
const isVIP = db.prepare("get", "SELECT count(*) as userCount FROM vipUsers WHERE userID = ?", [userID]).userCount > 0; const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0;
const decreaseVotes = 0; const decreaseVotes = 0;
@ -366,8 +366,8 @@ export async function postSkipSegments(req: Request, res: Response) {
} }
//check if this info has already been submitted before //check if this info has already been submitted before
const duplicateCheck2Row = db.prepare('get', "SELECT COUNT(*) as count FROM sponsorTimes WHERE startTime = ? " + const duplicateCheck2Row = await db.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "startTime" = ?
"and endTime = ? and category = ? and videoID = ?", [startTime, endTime, segments[i].category, videoID]); and "endTime" = ? and "category" = ? and "videoID" = ?`, [startTime, endTime, segments[i].category, videoID]);
if (duplicateCheck2Row.count > 0) { if (duplicateCheck2Row.count > 0) {
res.sendStatus(409); res.sendStatus(409);
return; return;
@ -401,7 +401,7 @@ export async function postSkipSegments(req: Request, res: Response) {
// Disable IP ratelimiting for now // Disable IP ratelimiting for now
if (false) { if (false) {
//check to see if this ip has submitted too many sponsors today //check to see if this ip has submitted too many sponsors today
const rateLimitCheckRow = privateDB.prepare('get', "SELECT COUNT(*) as count FROM sponsorTimes WHERE hashedIP = ? AND videoID = ? AND timeSubmitted > ?", [hashedIP, videoID, yesterday]); const rateLimitCheckRow = await privateDB.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "hashedIP" = ? AND "videoID" = ? AND "timeSubmitted" > ?`, [hashedIP, videoID, yesterday]);
if (rateLimitCheckRow.count >= 10) { if (rateLimitCheckRow.count >= 10) {
//too many sponsors for the same video from the same ip address //too many sponsors for the same video from the same ip address
@ -414,7 +414,7 @@ export async function postSkipSegments(req: Request, res: Response) {
// Disable max submissions for now // Disable max submissions for now
if (false) { if (false) {
//check to see if the user has already submitted sponsors for this video //check to see if the user has already submitted sponsors for this video
const duplicateCheckRow = db.prepare('get', "SELECT COUNT(*) as count FROM sponsorTimes WHERE userID = ? and videoID = ?", [userID, videoID]); const duplicateCheckRow = await db.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ?`, [userID, videoID]);
if (duplicateCheckRow.count >= 16) { if (duplicateCheckRow.count >= 16) {
//too many sponsors for the same video from the same user //too many sponsors for the same video from the same user
@ -425,7 +425,7 @@ export async function postSkipSegments(req: Request, res: Response) {
} }
//check to see if this user is shadowbanned //check to see if this user is shadowbanned
const shadowBanRow = privateDB.prepare('get', "SELECT count(*) as userCount FROM shadowBannedUsers WHERE userID = ?", [userID]); const shadowBanRow = await privateDB.prepare('get', `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
let shadowBanned = shadowBanRow.userCount; let shadowBanned = shadowBanRow.userCount;
@ -445,7 +445,7 @@ export async function postSkipSegments(req: Request, res: Response) {
Logger.error("Error while submitting when connecting to YouTube API: " + err); Logger.error("Error while submitting when connecting to YouTube API: " + err);
} else { } else {
//get all segments for this video and user //get all segments for this video and user
const allSubmittedByUser = db.prepare('all', "SELECT startTime, endTime FROM sponsorTimes WHERE userID = ? and videoID = ? and votes > -1", [userID, videoID]); const allSubmittedByUser = await db.prepare('all', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ? and "votes" > -1`, [userID, videoID]);
const allSegmentTimes = []; const allSegmentTimes = [];
if (allSubmittedByUser !== undefined) { if (allSubmittedByUser !== undefined) {
//add segments the user has previously submitted //add segments the user has previously submitted
@ -489,15 +489,15 @@ export async function postSkipSegments(req: Request, res: Response) {
const startingLocked = isVIP ? 1 : 0; const startingLocked = isVIP ? 1 : 0;
try { try {
db.prepare('run', "INSERT INTO sponsorTimes " + await db.prepare('run', `INSERT INTO "sponsorTimes"
"(videoID, startTime, endTime, votes, locked, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID)" + ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "shadowHidden", "hashedVideoID")
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, shadowBanned, getHash(videoID, 1), videoID, segmentInfo.segment[0], segmentInfo.segment[1], startingVotes, startingLocked, UUID, userID, timeSubmitted, 0, segmentInfo.category, shadowBanned, getHash(videoID, 1),
], ],
); );
//add to private db as well //add to private db as well
privateDB.prepare('run', "INSERT INTO sponsorTimes VALUES(?, ?, ?)", [videoID, hashedIP, timeSubmitted]); await privateDB.prepare('run', `INSERT INTO "sponsorTimes" VALUES(?, ?, ?)`, [videoID, hashedIP, timeSubmitted]);
// Clear redis cache for this video // Clear redis cache for this video
redis.delAsync(skipSegmentsKey(videoID)); redis.delAsync(skipSegmentsKey(videoID));

View file

@ -5,7 +5,7 @@ import {isUserVIP} from '../utils/isUserVIP';
import {getHash} from '../utils/getHash'; import {getHash} from '../utils/getHash';
import { HashedUserID, UserID } from '../types/user.model'; import { HashedUserID, UserID } from '../types/user.model';
export function postWarning(req: Request, res: Response) { export async function postWarning(req: Request, res: Response) {
// Collect user input data // Collect user input data
let issuerUserID: HashedUserID = getHash(<UserID> req.body.issuerUserID); let issuerUserID: HashedUserID = getHash(<UserID> req.body.issuerUserID);
let userID: UserID = req.body.userID; let userID: UserID = req.body.userID;
@ -13,7 +13,7 @@ export function postWarning(req: Request, res: Response) {
let enabled: boolean = req.body.enabled ?? true; let enabled: boolean = req.body.enabled ?? true;
// Ensure user is a VIP // Ensure user is a VIP
if (!isUserVIP(issuerUserID)) { if (!await isUserVIP(issuerUserID)) {
Logger.warn("Permission violation: User " + issuerUserID + " attempted to warn user " + userID + "."); Logger.warn("Permission violation: User " + issuerUserID + " attempted to warn user " + userID + ".");
res.status(403).json({"message": "Not a VIP"}); res.status(403).json({"message": "Not a VIP"});
return; return;
@ -22,17 +22,17 @@ export function postWarning(req: Request, res: Response) {
let resultStatus = ""; let resultStatus = "";
if (enabled) { if (enabled) {
let previousWarning = db.prepare('get', 'SELECT * FROM warnings WHERE userID = ? AND issuerUserID = ?', [userID, issuerUserID]); let previousWarning = await db.prepare('get', 'SELECT * FROM "warnings" WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]);
if (!previousWarning) { if (!previousWarning) {
db.prepare('run', 'INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES (?, ?, ?, 1)', [userID, issueTime, issuerUserID]); await db.prepare('run', 'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled") VALUES (?, ?, ?, 1)', [userID, issueTime, issuerUserID]);
resultStatus = "issued to"; resultStatus = "issued to";
} else { } else {
res.status(409).send(); res.status(409).send();
return; return;
} }
} else { } else {
db.prepare('run', 'UPDATE warnings SET enabled = 0 WHERE userID = ? AND issuerUserID = ?', [userID, issuerUserID]); await db.prepare('run', 'UPDATE "warnings" SET "enabled" = 0 WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]);
resultStatus = "removed from"; resultStatus = "removed from";
} }

View file

@ -4,7 +4,7 @@ import {db} from '../databases/databases';
import {getHash} from '../utils/getHash'; import {getHash} from '../utils/getHash';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
export function setUsername(req: Request, res: Response) { export async function setUsername(req: Request, res: Response) {
let userID = req.query.userID as string; let userID = req.query.userID as string;
let userName = req.query.username as string; let userName = req.query.username as string;
@ -38,14 +38,14 @@ export function setUsername(req: Request, res: Response) {
try { try {
//check if username is already set //check if username is already set
let row = db.prepare('get', "SELECT count(*) as count FROM userNames WHERE userID = ?", [userID]); let row = await db.prepare('get', `SELECT count(*) as count FROM "userNames" WHERE "userID" = ?`, [userID]);
if (row.count > 0) { if (row.count > 0) {
//already exists, update this row //already exists, update this row
db.prepare('run', "UPDATE userNames SET userName = ? WHERE userID = ?", [userName, userID]); await db.prepare('run', `UPDATE "userNames" SET "userName" = ? WHERE "userID" = ?`, [userName, userID]);
} else { } else {
//add to the db //add to the db
db.prepare('run', "INSERT INTO userNames VALUES(?, ?)", [userID, userName]); await db.prepare('run', `INSERT INTO "userNames" VALUES(?, ?)`, [userID, userName]);
} }
res.sendStatus(200); res.sendStatus(200);

View file

@ -23,7 +23,7 @@ export async function shadowBanUser(req: Request, res: Response) {
//hash the userID //hash the userID
adminUserIDInput = getHash(adminUserIDInput); adminUserIDInput = getHash(adminUserIDInput);
const isVIP = db.prepare("get", "SELECT count(*) as userCount FROM vipUsers WHERE userID = ?", [adminUserIDInput]).userCount > 0; const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [adminUserIDInput])).userCount > 0;
if (!isVIP) { if (!isVIP) {
//not authorized //not authorized
res.sendStatus(403); res.sendStatus(403);
@ -32,65 +32,64 @@ export async function shadowBanUser(req: Request, res: Response) {
if (userID) { if (userID) {
//check to see if this user is already shadowbanned //check to see if this user is already shadowbanned
const row = privateDB.prepare('get', "SELECT count(*) as userCount FROM shadowBannedUsers WHERE userID = ?", [userID]); const row = await privateDB.prepare('get', `SELECT count(*) as "userCount" FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
if (enabled && row.userCount == 0) { if (enabled && row.userCount == 0) {
//add them to the shadow ban list //add them to the shadow ban list
//add it to the table //add it to the table
privateDB.prepare('run', "INSERT INTO shadowBannedUsers VALUES(?)", [userID]); await privateDB.prepare('run', `INSERT INTO "shadowBannedUsers" VALUES(?)`, [userID]);
//find all previous submissions and hide them //find all previous submissions and hide them
if (unHideOldSubmissions) { if (unHideOldSubmissions) {
db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 1 WHERE userID = ?" await db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "userID" = ?
+ " AND NOT EXISTS ( SELECT videoID, category FROM noSegments WHERE" AND NOT EXISTS ( SELECT "videoID", "category" FROM "noSegments" WHERE
+ " sponsorTimes.videoID = noSegments.videoID AND sponsorTimes.category = noSegments.category)", [userID]); "sponsorTimes"."videoID" = "noSegments"."videoID" AND "sponsorTimes"."category" = "noSegments"."category")`, [userID]);
} }
} else if (!enabled && row.userCount > 0) { } else if (!enabled && row.userCount > 0) {
//remove them from the shadow ban list //remove them from the shadow ban list
privateDB.prepare('run', "DELETE FROM shadowBannedUsers WHERE userID = ?", [userID]); await privateDB.prepare('run', `DELETE FROM "shadowBannedUsers" WHERE "userID" = ?`, [userID]);
//find all previous submissions and unhide them //find all previous submissions and unhide them
if (unHideOldSubmissions) { if (unHideOldSubmissions) {
let segmentsToIgnore = db.prepare('all', "SELECT UUID FROM sponsorTimes st " let segmentsToIgnore = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st
+ "JOIN noSegments ns on st.videoID = ns.videoID AND st.category = ns.category WHERE st.userID = ?" JOIN "noSegments" ns on "st"."videoID" = "ns"."videoID" AND st.category = ns.category WHERE "st"."userID" = ?`
, [userID]).map((item: {UUID: string}) => item.UUID); , [userID])).map((item: {UUID: string}) => item.UUID);
let allSegments = db.prepare('all', "SELECT UUID FROM sponsorTimes st WHERE st.userID = ?", [userID]) let allSegments = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st WHERE "st"."userID" = ?`, [userID]))
.map((item: {UUID: string}) => item.UUID); .map((item: {UUID: string}) => item.UUID);
allSegments.filter((item: {uuid: string}) => { await Promise.all(allSegments.filter((item: {uuid: string}) => {
return segmentsToIgnore.indexOf(item) === -1; return segmentsToIgnore.indexOf(item) === -1;
}).forEach((UUID: string) => { }).map((UUID: string) => {
db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 0 WHERE UUID = ?", [UUID]); return db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 0 WHERE "UUID" = ?`, [UUID]);
}); }));
} }
} }
} } else if (hashedIP) {
else if (hashedIP) {
//check to see if this user is already shadowbanned //check to see if this user is already shadowbanned
// let row = privateDB.prepare('get', "SELECT count(*) as userCount FROM shadowBannedIPs WHERE hashedIP = ?", [hashedIP]); // let row = await privateDB.prepare('get', "SELECT count(*) as userCount FROM shadowBannedIPs WHERE hashedIP = ?", [hashedIP]);
// if (enabled && row.userCount == 0) { // if (enabled && row.userCount == 0) {
if (enabled) { if (enabled) {
//add them to the shadow ban list //add them to the shadow ban list
//add it to the table //add it to the table
// privateDB.prepare('run', "INSERT INTO shadowBannedIPs VALUES(?)", [hashedIP]); // await privateDB.prepare('run', "INSERT INTO shadowBannedIPs VALUES(?)", [hashedIP]);
//find all previous submissions and hide them //find all previous submissions and hide them
if (unHideOldSubmissions) { if (unHideOldSubmissions) {
db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 1 WHERE timeSubmitted IN " + await db.prepare('run', `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "timeSubmitted" IN
"(SELECT privateDB.timeSubmitted FROM sponsorTimes LEFT JOIN privateDB.sponsorTimes as privateDB ON sponsorTimes.timeSubmitted=privateDB.timeSubmitted " + (SELECT "privateDB"."timeSubmitted" FROM "sponsorTimes" LEFT JOIN "privateDB"."sponsorTimes" as "privateDB" ON "sponsorTimes"."timeSubmitted"="privateDB"."timeSubmitted"
"WHERE privateDB.hashedIP = ?)", [hashedIP]); WHERE "privateDB"."hashedIP" = ?)`, [hashedIP]);
} }
} /*else if (!enabled && row.userCount > 0) { } /*else if (!enabled && row.userCount > 0) {
// //remove them from the shadow ban list // //remove them from the shadow ban list
// privateDB.prepare('run', "DELETE FROM shadowBannedUsers WHERE userID = ?", [userID]); // await privateDB.prepare('run', "DELETE FROM shadowBannedUsers WHERE userID = ?", [userID]);
// //find all previous submissions and unhide them // //find all previous submissions and unhide them
// if (unHideOldSubmissions) { // if (unHideOldSubmissions) {
// db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 0 WHERE userID = ?", [userID]); // await db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 0 WHERE userID = ?", [userID]);
// } // }
}*/ }*/
} }

View file

@ -1,7 +1,7 @@
import {db} from '../databases/databases'; import {db} from '../databases/databases';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
export function viewedVideoSponsorTime(req: Request, res: Response): Response { export async function viewedVideoSponsorTime(req: Request, res: Response): Promise<Response> {
let UUID = req.query.UUID; let UUID = req.query.UUID;
if (UUID == undefined) { if (UUID == undefined) {
@ -10,7 +10,7 @@ export function viewedVideoSponsorTime(req: Request, res: Response): Response {
} }
//up the view count by one //up the view count by one
db.prepare('run', "UPDATE sponsorTimes SET views = views + 1 WHERE UUID = ?", [UUID]); await db.prepare('run', `UPDATE "sponsorTimes" SET views = views + 1 WHERE "UUID" = ?`, [UUID]);
return res.sendStatus(200); return res.sendStatus(200);
} }

View file

@ -35,14 +35,14 @@ interface VoteData {
oldIncrementAmount: number; oldIncrementAmount: number;
} }
function sendWebhooks(voteData: VoteData) { async function sendWebhooks(voteData: VoteData) {
const submissionInfoRow = db.prepare('get', "SELECT s.videoID, s.userID, s.startTime, s.endTime, s.category, u.userName, " + const submissionInfoRow = await db.prepare('get', `SELECT "s"."videoID", "s"."userID", s."startTime", s."endTime", s."category", u."userName",
"(select count(1) from sponsorTimes where userID = s.userID) count, " + (select count(1) from "sponsorTimes" where "userID" = s."userID") count,
"(select count(1) from sponsorTimes where userID = s.userID and votes <= -2) disregarded " + (select count(1) from "sponsorTimes" where "userID" = s."userID" and votes <= -2) disregarded
"FROM sponsorTimes s left join userNames u on s.userID = u.userID where s.UUID=?", FROM "sponsorTimes" s left join "userNames" u on s."userID" = u."userID" where s."UUID"=?`,
[voteData.UUID]); [voteData.UUID]);
const userSubmissionCountRow = db.prepare('get', "SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?", [voteData.nonAnonUserID]); const userSubmissionCountRow = await db.prepare('get', `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ?`, [voteData.nonAnonUserID]);
if (submissionInfoRow !== undefined && userSubmissionCountRow != undefined) { if (submissionInfoRow !== undefined && userSubmissionCountRow != undefined) {
let webhookURL: string = null; let webhookURL: string = null;
@ -141,9 +141,9 @@ function sendWebhooks(voteData: VoteData) {
} }
} }
function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmission: boolean, category: string, hashedIP: string, res: Response) { async function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmission: boolean, category: string, hashedIP: string, res: Response) {
// Check if they've already made a vote // Check if they've already made a vote
const usersLastVoteInfo = privateDB.prepare('get', "select count(*) as votes, category from categoryVotes where UUID = ? and userID = ?", [UUID, userID]); const usersLastVoteInfo = await privateDB.prepare('get', `select count(*) as votes, category from "categoryVotes" where "UUID" = ? and "userID" = ? group by category`, [UUID, userID]);
if (usersLastVoteInfo?.category === category) { if (usersLastVoteInfo?.category === category) {
// Double vote, ignore // Double vote, ignore
@ -151,7 +151,7 @@ function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmiss
return; return;
} }
const currentCategory = db.prepare('get', "select category from sponsorTimes where UUID = ?", [UUID]); const currentCategory = await db.prepare('get', `select category from "sponsorTimes" where "UUID" = ?`, [UUID]);
if (!currentCategory) { if (!currentCategory) {
// Submission doesn't exist // Submission doesn't exist
res.status(400).send("Submission doesn't exist."); res.status(400).send("Submission doesn't exist.");
@ -163,36 +163,36 @@ function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmiss
return; return;
} }
const nextCategoryInfo = db.prepare("get", "select votes from categoryVotes where UUID = ? and category = ?", [UUID, category]); const nextCategoryInfo = await db.prepare("get", `select votes from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, category]);
const timeSubmitted = Date.now(); const timeSubmitted = Date.now();
const voteAmount = isVIP ? 500 : 1; const voteAmount = isVIP ? 500 : 1;
// Add the vote // Add the vote
if (db.prepare('get', "select count(*) as count from categoryVotes where UUID = ? and category = ?", [UUID, category]).count > 0) { if ((await db.prepare('get', `select count(*) as count from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, category])).count > 0) {
// Update the already existing db entry // Update the already existing db entry
db.prepare('run', "update categoryVotes set votes = votes + ? where UUID = ? and category = ?", [voteAmount, UUID, category]); await db.prepare('run', `update "categoryVotes" set "votes" = "votes" + ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, category]);
} else { } else {
// Add a db entry // Add a db entry
db.prepare('run', "insert into categoryVotes (UUID, category, votes) values (?, ?, ?)", [UUID, category, voteAmount]); await db.prepare('run', `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, category, voteAmount]);
} }
// Add the info into the private db // Add the info into the private db
if (usersLastVoteInfo?.votes > 0) { if (usersLastVoteInfo?.votes > 0) {
// Reverse the previous vote // Reverse the previous vote
db.prepare('run', "update categoryVotes set votes = votes - ? where UUID = ? and category = ?", [voteAmount, UUID, usersLastVoteInfo.category]); await db.prepare('run', `update "categoryVotes" set "votes" = "votes" - ? where "UUID" = ? and "category" = ?`, [voteAmount, UUID, usersLastVoteInfo.category]);
privateDB.prepare('run', "update categoryVotes set category = ?, timeSubmitted = ?, hashedIP = ? where userID = ? and UUID = ?", [category, timeSubmitted, hashedIP, userID, UUID]); await privateDB.prepare('run', `update "categoryVotes" set "category" = ?, "timeSubmitted" = ?, "hashedIP" = ? where "userID" = ? and "UUID" = ?`, [category, timeSubmitted, hashedIP, userID, UUID]);
} else { } else {
privateDB.prepare('run', "insert into categoryVotes (UUID, userID, hashedIP, category, timeSubmitted) values (?, ?, ?, ?, ?)", [UUID, userID, hashedIP, category, timeSubmitted]); await privateDB.prepare('run', `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, userID, hashedIP, category, timeSubmitted]);
} }
// See if the submissions category is ready to change // See if the submissions category is ready to change
const currentCategoryInfo = db.prepare("get", "select votes from categoryVotes where UUID = ? and category = ?", [UUID, currentCategory.category]); const currentCategoryInfo = await db.prepare("get", `select votes from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, currentCategory.category]);
const submissionInfo = db.prepare("get", "SELECT userID, timeSubmitted, votes FROM sponsorTimes WHERE UUID = ?", [UUID]); const submissionInfo = await db.prepare("get", `SELECT "userID", "timeSubmitted", "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]);
const isSubmissionVIP = submissionInfo && isUserVIP(submissionInfo.userID); const isSubmissionVIP = submissionInfo && await isUserVIP(submissionInfo.userID);
const startingVotes = isSubmissionVIP ? 10000 : 1; const startingVotes = isSubmissionVIP ? 10000 : 1;
// Change this value from 1 in the future to make it harder to change categories // Change this value from 1 in the future to make it harder to change categories
@ -201,9 +201,9 @@ function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmiss
// Add submission as vote // Add submission as vote
if (!currentCategoryInfo && submissionInfo) { if (!currentCategoryInfo && submissionInfo) {
db.prepare("run", "insert into categoryVotes (UUID, category, votes) values (?, ?, ?)", [UUID, currentCategory.category, currentCategoryCount]); await db.prepare("run", `insert into "categoryVotes" ("UUID", "category", "votes") values (?, ?, ?)`, [UUID, currentCategory.category, currentCategoryCount]);
privateDB.prepare("run", "insert into categoryVotes (UUID, userID, hashedIP, category, timeSubmitted) values (?, ?, ?, ?, ?)", [UUID, submissionInfo.userID, "unknown", currentCategory.category, submissionInfo.timeSubmitted]); await privateDB.prepare("run", `insert into "categoryVotes" ("UUID", "userID", "hashedIP", "category", "timeSubmitted") values (?, ?, ?, ?, ?)`, [UUID, submissionInfo.userID, "unknown", currentCategory.category, submissionInfo.timeSubmitted]);
} }
const nextCategoryCount = (nextCategoryInfo?.votes || 0) + voteAmount; const nextCategoryCount = (nextCategoryInfo?.votes || 0) + voteAmount;
@ -212,7 +212,7 @@ function categoryVote(UUID: string, userID: string, isVIP: boolean, isOwnSubmiss
// VIPs change it every time // VIPs change it every time
if (nextCategoryCount - currentCategoryCount >= Math.max(Math.ceil(submissionInfo?.votes / 2), 2) || isVIP || isOwnSubmission) { if (nextCategoryCount - currentCategoryCount >= Math.max(Math.ceil(submissionInfo?.votes / 2), 2) || isVIP || isOwnSubmission) {
// Replace the category // Replace the category
db.prepare('run', "update sponsorTimes set category = ? where UUID = ?", [category, UUID]); await db.prepare('run', `update "sponsorTimes" set "category" = ? where "UUID" = ?`, [category, UUID]);
} }
res.sendStatus(200); res.sendStatus(200);
@ -245,20 +245,19 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
const hashedIP = getHash(ip + config.globalSalt); const hashedIP = getHash(ip + config.globalSalt);
//check if this user is on the vip list //check if this user is on the vip list
const isVIP = db.prepare('get', "SELECT count(*) as userCount FROM vipUsers WHERE userID = ?", [nonAnonUserID]).userCount > 0; const isVIP = (await db.prepare('get', `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [nonAnonUserID])).userCount > 0;
//check if user voting on own submission //check if user voting on own submission
const isOwnSubmission = db.prepare("get", "SELECT UUID as submissionCount FROM sponsorTimes where userID = ? AND UUID = ?", [nonAnonUserID, UUID]) !== undefined; const isOwnSubmission = (await db.prepare("get", `SELECT "UUID" as "submissionCount" FROM "sponsorTimes" where "userID" = ? AND "UUID" = ?`, [nonAnonUserID, UUID])) !== undefined;
// If not upvote // If not upvote
if (!isVIP && type !== 1) { if (!isVIP && type !== 1) {
const isSegmentLocked = () => !!db.prepare('get', "SELECT locked FROM sponsorTimes WHERE UUID = ?", [UUID])?.locked; const isSegmentLocked = async () => !!(await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]))?.locked;
const isVideoLocked = () => !!db.prepare('get', 'SELECT noSegments.category from noSegments left join sponsorTimes' + const isVideoLocked = async () => !!(await db.prepare('get', 'SELECT "noSegments".category from "noSegments" left join "sponsorTimes"' +
' on (noSegments.videoID = sponsorTimes.videoID and noSegments.category = sponsorTimes.category)' + ' on ("noSegments"."videoID" = "sponsorTimes"."videoID" and "noSegments".category = "sponsorTimes".category)' +
' where UUID = ?', [UUID]); ' where "UUID" = ?', [UUID]));
if (isSegmentLocked() || isVideoLocked()) { if (await isSegmentLocked() || await isVideoLocked()) {
res.status(403).send("Vote rejected: A moderator has decided that this segment is correct"); res.status(403).send("Vote rejected: A moderator has decided that this segment is correct");
return; return;
} }
@ -270,7 +269,7 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
if (type == 1 && !isVIP && !isOwnSubmission) { if (type == 1 && !isVIP && !isOwnSubmission) {
// Check if upvoting hidden segment // Check if upvoting hidden segment
const voteInfo = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", [UUID]); const voteInfo = await db.prepare('get', `SELECT votes FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]);
if (voteInfo && voteInfo.votes <= -2) { if (voteInfo && voteInfo.votes <= -2) {
res.status(403).send("Not allowed to upvote segment with too many downvotes unless you are VIP."); res.status(403).send("Not allowed to upvote segment with too many downvotes unless you are VIP.");
@ -280,9 +279,9 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
const MILLISECONDS_IN_HOUR = 3600000; const MILLISECONDS_IN_HOUR = 3600000;
const now = Date.now(); const now = Date.now();
const warningsCount = db.prepare('get', "SELECT count(1) as count FROM warnings WHERE userID = ? AND issueTime > ? AND enabled = 1", const warningsCount = (await db.prepare('get', `SELECT count(1) as count FROM warnings WHERE "userID" = ? AND "issueTime" > ? AND enabled = 1`,
[nonAnonUserID, Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR))], [nonAnonUserID, Math.floor(now - (config.hoursAfterWarningExpires * MILLISECONDS_IN_HOUR))],
).count; )).count;
if (warningsCount >= config.maxNumberOfActiveWarnings) { if (warningsCount >= config.maxNumberOfActiveWarnings) {
return res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); return res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?');
@ -292,7 +291,7 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
try { try {
//check if vote has already happened //check if vote has already happened
const votesRow = privateDB.prepare('get', "SELECT type FROM votes WHERE userID = ? AND UUID = ?", [userID, UUID]); const votesRow = await privateDB.prepare('get', `SELECT "type" FROM "votes" WHERE "userID" = ? AND "UUID" = ?`, [userID, UUID]);
//-1 for downvote, 1 for upvote. Maybe more depending on reputation in the future //-1 for downvote, 1 for upvote. Maybe more depending on reputation in the future
let incrementAmount = 0; let incrementAmount = 0;
@ -338,7 +337,7 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
} }
//check if the increment amount should be multiplied (downvotes have more power if there have been many views) //check if the increment amount should be multiplied (downvotes have more power if there have been many views)
const row = db.prepare('get', "SELECT videoID, votes, views FROM sponsorTimes WHERE UUID = ?", [UUID]) as const row = await db.prepare('get', `SELECT "videoID", votes, views FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]) as
{videoID: VideoID, votes: number, views: number}; {videoID: VideoID, votes: number, views: number};
if (voteTypeEnum === voteTypes.normal) { if (voteTypeEnum === voteTypes.normal) {
@ -357,16 +356,16 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
// Only change the database if they have made a submission before and haven't voted recently // Only change the database if they have made a submission before and haven't voted recently
const ableToVote = isVIP const ableToVote = isVIP
|| (db.prepare("get", "SELECT userID FROM sponsorTimes WHERE userID = ?", [nonAnonUserID]) !== undefined || ((await db.prepare("get", `SELECT "userID" FROM "sponsorTimes" WHERE "userID" = ?`, [nonAnonUserID])) !== undefined
&& privateDB.prepare("get", "SELECT userID FROM shadowBannedUsers WHERE userID = ?", [nonAnonUserID]) === undefined && (await privateDB.prepare("get", `SELECT "userID" FROM "shadowBannedUsers" WHERE "userID" = ?`, [nonAnonUserID])) === undefined
&& privateDB.prepare("get", "SELECT UUID FROM votes WHERE UUID = ? AND hashedIP = ? AND userID != ?", [UUID, hashedIP, userID]) === undefined); && (await privateDB.prepare("get", `SELECT "UUID" FROM "votes" WHERE "UUID" = ? AND "hashedIP" = ? AND "userID" != ?`, [UUID, hashedIP, userID])) === undefined);
if (ableToVote) { if (ableToVote) {
//update the votes table //update the votes table
if (votesRow != undefined) { if (votesRow != undefined) {
privateDB.prepare('run', "UPDATE votes SET type = ? WHERE userID = ? AND UUID = ?", [type, userID, UUID]); await privateDB.prepare('run', `UPDATE "votes" SET "type" = ? WHERE "userID" = ? AND "UUID" = ?`, [type, userID, UUID]);
} else { } else {
privateDB.prepare('run', "INSERT INTO votes VALUES(?, ?, ?, ?)", [UUID, userID, hashedIP, type]); await privateDB.prepare('run', `INSERT INTO "votes" VALUES(?, ?, ?, ?)`, [UUID, userID, hashedIP, type]);
} }
let columnName = ""; let columnName = "";
@ -378,13 +377,13 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
//update the vote count on this sponsorTime //update the vote count on this sponsorTime
//oldIncrementAmount will be zero is row is null //oldIncrementAmount will be zero is row is null
db.prepare('run', "UPDATE sponsorTimes SET " + columnName + " = " + columnName + " + ? WHERE UUID = ?", [incrementAmount - oldIncrementAmount, UUID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET ' + columnName + ' = ' + columnName + ' + ? WHERE "UUID" = ?', [incrementAmount - oldIncrementAmount, UUID]);
if (isVIP && incrementAmount > 0 && voteTypeEnum === voteTypes.normal) { if (isVIP && incrementAmount > 0 && voteTypeEnum === voteTypes.normal) {
// Lock this submission // Lock this submission
db.prepare('run', "UPDATE sponsorTimes SET locked = 1 WHERE UUID = ?", [UUID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET locked = 1 WHERE "UUID" = ?', [UUID]);
} else if (isVIP && incrementAmount < 0 && voteTypeEnum === voteTypes.normal) { } else if (isVIP && incrementAmount < 0 && voteTypeEnum === voteTypes.normal) {
// Unlock if a VIP downvotes it // Unlock if a VIP downvotes it
db.prepare('run', "UPDATE sponsorTimes SET locked = 0 WHERE UUID = ?", [UUID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET locked = 0 WHERE "UUID" = ?', [UUID]);
} }
// Clear redis cache for this video // Clear redis cache for this video
@ -393,7 +392,7 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
//for each positive vote, see if a hidden submission can be shown again //for each positive vote, see if a hidden submission can be shown again
if (incrementAmount > 0 && voteTypeEnum === voteTypes.normal) { if (incrementAmount > 0 && voteTypeEnum === voteTypes.normal) {
//find the UUID that submitted the submission that was voted on //find the UUID that submitted the submission that was voted on
const submissionUserIDInfo = db.prepare('get', "SELECT userID FROM sponsorTimes WHERE UUID = ?", [UUID]); const submissionUserIDInfo = await db.prepare('get', 'SELECT "userID" FROM "sponsorTimes" WHERE "UUID" = ?', [UUID]);
if (!submissionUserIDInfo) { if (!submissionUserIDInfo) {
// They are voting on a non-existent submission // They are voting on a non-existent submission
res.status(400).send("Voting on a non-existent submission"); res.status(400).send("Voting on a non-existent submission");
@ -403,14 +402,14 @@ export async function voteOnSponsorTime(req: Request, res: Response) {
const submissionUserID = submissionUserIDInfo.userID; const submissionUserID = submissionUserIDInfo.userID;
//check if any submissions are hidden //check if any submissions are hidden
const hiddenSubmissionsRow = db.prepare('get', "SELECT count(*) as hiddenSubmissions FROM sponsorTimes WHERE userID = ? AND shadowHidden > 0", [submissionUserID]); const hiddenSubmissionsRow = await db.prepare('get', 'SELECT count(*) as "hiddenSubmissions" FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" > 0', [submissionUserID]);
if (hiddenSubmissionsRow.hiddenSubmissions > 0) { if (hiddenSubmissionsRow.hiddenSubmissions > 0) {
//see if some of this users submissions should be visible again //see if some of this users submissions should be visible again
if (await isUserTrustworthy(submissionUserID)) { if (await isUserTrustworthy(submissionUserID)) {
//they are trustworthy again, show 2 of their submissions again, if there are two to show //they are trustworthy again, show 2 of their submissions again, if there are two to show
db.prepare('run', "UPDATE sponsorTimes SET shadowHidden = 0 WHERE ROWID IN (SELECT ROWID FROM sponsorTimes WHERE userID = ? AND shadowHidden = 1 LIMIT 2)", [submissionUserID]); await db.prepare('run', 'UPDATE "sponsorTimes" SET "shadowHidden" = 0 WHERE ROWID IN (SELECT ROWID FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = 1 LIMIT 2)', [submissionUserID]);
} }
} }
} }

View file

@ -1,3 +1,4 @@
import { PoolConfig } from 'pg';
import * as redis from 'redis'; import * as redis from 'redis';
export interface SBSConfig { export interface SBSConfig {
@ -36,6 +37,7 @@ export interface SBSConfig {
minimumPrefix?: string; minimumPrefix?: string;
maximumPrefix?: string; maximumPrefix?: string;
redis?: redis.ClientOpts; redis?: redis.ClientOpts;
postgres?: PoolConfig;
} }
export interface WebhookConfig { export interface WebhookConfig {
@ -50,3 +52,13 @@ export interface RateLimitConfig {
message: string; message: string;
statusCode: number; statusCode: number;
} }
export interface PostgresConfig {
dbSchemaFileName: string;
dbSchemaFolder: string;
fileNamePrefix: string;
readOnly: boolean;
createDbIfNotExists: boolean;
enableWalCheckpointNumber: boolean;
postgres: PoolConfig;
}

View file

@ -6,11 +6,11 @@ import {db} from '../databases/databases';
*/ */
export async function isUserTrustworthy(userID: string): Promise<boolean> { export async function isUserTrustworthy(userID: string): Promise<boolean> {
//check to see if this user how many submissions this user has submitted //check to see if this user how many submissions this user has submitted
const totalSubmissionsRow = db.prepare('get', "SELECT count(*) as totalSubmissions, sum(votes) as voteSum FROM sponsorTimes WHERE userID = ?", [userID]); const totalSubmissionsRow = await db.prepare('get', `SELECT count(*) as "totalSubmissions", sum(votes) as "voteSum" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]);
if (totalSubmissionsRow.totalSubmissions > 5) { if (totalSubmissionsRow.totalSubmissions > 5) {
//check if they have a high downvote ratio //check if they have a high downvote ratio
const downvotedSubmissionsRow = db.prepare('get', "SELECT count(*) as downvotedSubmissions FROM sponsorTimes WHERE userID = ? AND (votes < 0 OR shadowHidden > 0)", [userID]); const downvotedSubmissionsRow = await db.prepare('get', `SELECT count(*) as "downvotedSubmissions" FROM "sponsorTimes" WHERE "userID" = ? AND (votes < 0 OR "shadowHidden" > 0)`, [userID]);
return (downvotedSubmissionsRow.downvotedSubmissions / totalSubmissionsRow.totalSubmissions) < 0.6 || return (downvotedSubmissionsRow.downvotedSubmissions / totalSubmissionsRow.totalSubmissions) < 0.6 ||
(totalSubmissionsRow.voteSum > downvotedSubmissionsRow.downvotedSubmissions); (totalSubmissionsRow.voteSum > downvotedSubmissionsRow.downvotedSubmissions);

View file

@ -1,8 +1,8 @@
import {db} from '../databases/databases'; import {db} from '../databases/databases';
import { HashedUserID } from '../types/user.model'; import { HashedUserID } from '../types/user.model';
export function isUserVIP(userID: HashedUserID): boolean { export async function isUserVIP(userID: HashedUserID): Promise<boolean> {
return db.prepare('get', "SELECT count(*) as userCount FROM vipUsers WHERE userID = ?", [userID]).userCount > 0; return (await db.prepare('get', `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0;
} }

View file

@ -2,10 +2,10 @@ import {db, privateDB} from '../../src/databases/databases';
import {Done} from '../utils'; import {Done} from '../utils';
describe('dbUpgrade', () => { describe('dbUpgrade', () => {
it('Should update the database version when starting the application', (done: Done) => { it('Should update the database version when starting the application', async () => {
let dbVersion = db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version']).value; let dbVersion = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
let privateVersion = privateDB.prepare('get', 'SELECT key, value FROM config where key = ?', ['version']).value; let privateVersion = (await privateDB.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
if (dbVersion >= 1 && privateVersion >= 1) done(); if (dbVersion >= 1 && privateVersion >= 1) return;
else done('Versions are not at least 1. db is ' + dbVersion + ', private is ' + privateVersion); else return 'Versions are not at least 1. db is ' + dbVersion + ', private is ' + privateVersion;
}); });
}); });

View file

@ -4,8 +4,8 @@ import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
describe('getIsUserVIP', () => { describe('getIsUserVIP', () => {
before(() => { before((done: Done) => {
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("supertestman") + "')"); db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("supertestman") + "')").then(done);
}); });
it('Should be able to get a 200', (done: Done) => { it('Should be able to get a 200', (done: Done) => {

View file

@ -4,9 +4,11 @@ import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
describe('getSavedTimeForUser', () => { describe('getSavedTimeForUser', () => {
before(() => { before(async () => {
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfQuery + "('getSavedTimeForUser', 1, 11, 2, 'abc1239999', '" + getHash("testman") + "', 0, 50, 'sponsor', 0, '" + getHash('getSavedTimeForUser', 0) + "')"); await db.prepare("run", startOfQuery + "('getSavedTimeForUser', 1, 11, 2, 'abc1239999', '" + getHash("testman") + "', 0, 50, 'sponsor', 0, '" + getHash('getSavedTimeForUser', 0) + "')");
return;
}); });
it('Should be able to get a 200', (done: Done) => { it('Should be able to get a 200', (done: Done) => {

View file

@ -11,13 +11,12 @@ const sinonStub = mockManager.mock('listVideos');
sinonStub.callsFake(YouTubeApiMock.listVideos); sinonStub.callsFake(YouTubeApiMock.listVideos);
describe('getSegmentsByHash', () => { describe('getSegmentsByHash', () => {
before(() => { before(async () => {
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfQuery + "('getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('getSegmentsByHash-0', 1) + "')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910 await db.prepare("run", startOfQuery + "('getSegmentsByHash-0', 1, 10, 2, 'getSegmentsByHash-0-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('getSegmentsByHash-0', 1) + "')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910
db.exec(startOfQuery + "('getSegmentsByHash-0', 20, 30, 2, 'getSegmentsByHash-0-1', 'testman', 100, 150, 'intro', 0, '" + getHash('getSegmentsByHash-0', 1) + "')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910 await db.prepare("run", startOfQuery + "('getSegmentsByHash-0', 20, 30, 2, 'getSegmentsByHash-0-1', 'testman', 100, 150, 'intro', 0, '" + getHash('getSegmentsByHash-0', 1) + "')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910
db.exec(startOfQuery + "('getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 0, 'fdaffnoMatchHash')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910 await db.prepare("run", startOfQuery + "('getSegmentsByHash-noMatchHash', 40, 50, 2, 'getSegmentsByHash-noMatchHash', 'testman', 0, 50, 'sponsor', 0, 'fdaffnoMatchHash')"); // hash = fdaff4dee1043451faa7398324fb63d8618ebcd11bddfe0491c488db12c6c910
db.exec(startOfQuery + "('getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('getSegmentsByHash-1', 1) + "')"); // hash = 3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b await db.prepare("run", startOfQuery + "('getSegmentsByHash-1', 60, 70, 2, 'getSegmentsByHash-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('getSegmentsByHash-1', 1) + "')"); // hash = 3272fa85ee0927f6073ef6f07ad5f3146047c1abba794cfa364d65ab9921692b
}); });
it('Should be able to get a 200', (done: Done) => { it('Should be able to get a 200', (done: Done) => {

View file

@ -4,92 +4,94 @@ import {Done, getbaseURL} from '../utils';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
describe('getSkipSegments', () => { describe('getSkipSegments', () => {
before(() => { before(async () => {
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, locked, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfQuery + "('testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('testtesttest', 1) + "')"); await db.prepare("run", startOfQuery + "('testtesttest', 1, 11, 2, 0, '1-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('testtesttest', 1) + "')");
db.exec(startOfQuery + "('testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', 0, 50, 'intro', 0, '" + getHash('testtesttest', 1) + "')"); await db.prepare("run", startOfQuery + "('testtesttest', 20, 33, 2, 0, '1-uuid-2', 'testman', 0, 50, 'intro', 0, '" + getHash('testtesttest', 1) + "')");
db.exec(startOfQuery + "('testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('testtesttest,test', 1) + "')"); await db.prepare("run", startOfQuery + "('testtesttest,test', 1, 11, 2, 0, '1-uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('testtesttest,test', 1) + "')");
db.exec(startOfQuery + "('test3', 1, 11, 2, 0, '1-uuid-4', 'testman', 0, 50, 'sponsor', 0, '" + getHash('test3', 1) + "')"); await db.prepare("run", startOfQuery + "('test3', 1, 11, 2, 0, '1-uuid-4', 'testman', 0, 50, 'sponsor', 0, '" + getHash('test3', 1) + "')");
db.exec(startOfQuery + "('test3', 7, 22, -3, 0, '1-uuid-5', 'testman', 0, 50, 'sponsor', 0, '" + getHash('test3', 1) + "')"); await db.prepare("run", startOfQuery + "('test3', 7, 22, -3, 0, '1-uuid-5', 'testman', 0, 50, 'sponsor', 0, '" + getHash('test3', 1) + "')");
db.exec(startOfQuery + "('multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', 0, 50, 'intro', 0, '" + getHash('multiple', 1) + "')"); await db.prepare("run", startOfQuery + "('multiple', 1, 11, 2, 0, '1-uuid-6', 'testman', 0, 50, 'intro', 0, '" + getHash('multiple', 1) + "')");
db.exec(startOfQuery + "('multiple', 20, 33, 2, 0, '1-uuid-7', 'testman', 0, 50, 'intro', 0, '" + getHash('multiple', 1) + "')"); await db.prepare("run", startOfQuery + "('multiple', 20, 33, 2, 0, '1-uuid-7', 'testman', 0, 50, 'intro', 0, '" + getHash('multiple', 1) + "')");
db.exec(startOfQuery + "('locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', 0, 50, 'intro', 0, '" + getHash('locked', 1) + "')"); await db.prepare("run", startOfQuery + "('locked', 20, 33, 2, 1, '1-uuid-locked-8', 'testman', 0, 50, 'intro', 0, '" + getHash('locked', 1) + "')");
db.exec(startOfQuery + "('locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', 0, 50, 'intro', 0, '" + getHash('locked', 1) + "')"); await db.prepare("run", startOfQuery + "('locked', 20, 34, 100000, 0, '1-uuid-9', 'testman', 0, 50, 'intro', 0, '" + getHash('locked', 1) + "')");
return;
}); });
it('Should be able to get a time by category 1', (done: Done) => { it('Should be able to get a time by category 1', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=sponsor")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const data = await res.json(); const data = await res.json();
if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11 if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") { && data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") {
done(); return;
} else { } else {
done("Received incorrect body: " + (await res.text())); return ("Received incorrect body: " + (await res.text()));
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => "Couldn't call endpoint");
}); });
it('Should be able to get a time by category 2', (done: Done) => { it('Should be able to get a time by category 2', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=intro") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&category=intro")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const data = await res.json(); const data = await res.json();
if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33 if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33
&& data[0].category === "intro" && data[0].UUID === "1-uuid-2") { && data[0].category === "intro" && data[0].UUID === "1-uuid-2") {
done(); return;
} else { } else {
done("Received incorrect body: " + (await res.text())); return ("Received incorrect body: " + (await res.text()));
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should be able to get a time by categories array', (done: Done) => { it('Should be able to get a time by categories array', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\"]") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\"]")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const data = await res.json(); const data = await res.json();
if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11 if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") { && data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") {
done(); return;
} else { } else {
done("Received incorrect body: " + (await res.text())); return ("Received incorrect body: " + (await res.text()));
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should be able to get a time by categories array 2', (done: Done) => { it('Should be able to get a time by categories array 2', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"intro\"]") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"intro\"]")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const data = await res.json(); const data = await res.json();
if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33 if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33
&& data[0].category === "intro" && data[0].UUID === "1-uuid-2") { && data[0].category === "intro" && data[0].UUID === "1-uuid-2") {
done(); return;
} else { } else {
done("Received incorrect body: " + (await res.text())); return ("Received incorrect body: " + (await res.text()));
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should be able to get multiple times by category', (done: Done) => { it('Should be able to get multiple times by category', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=multiple&categories=[\"intro\"]") fetch(getbaseURL() + "/api/skipSegments?videoID=multiple&categories=[\"intro\"]")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const body = await res.text(); const body = await res.text();
const data = JSON.parse(body); const data = JSON.parse(body);
@ -105,20 +107,20 @@ describe('getSkipSegments', () => {
} }
} }
if (success) done(); if (success) return;
else done("Received incorrect body: " + body); else return ("Received incorrect body: " + body);
} else { } else {
done("Received incorrect body: " + body); return ("Received incorrect body: " + body);
} }
} }
}) })
.catch(err => done("Couldn't call endpoint\n\n" + err)); .catch(err => ("Couldn't call endpoint\n\n" + err));
}); });
it('Should be able to get multiple times by multiple categories', (done: Done) => { it('Should be able to get multiple times by multiple categories', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\", \"intro\"]") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&categories=[\"sponsor\", \"intro\"]")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const body = await res.text(); const body = await res.text();
const data = JSON.parse(body); const data = JSON.parse(body);
@ -135,95 +137,95 @@ describe('getSkipSegments', () => {
} }
} }
if (success) done(); if (success) return;
else done("Received incorrect body: " + body); else return ("Received incorrect body: " + body);
} else { } else {
done("Received incorrect body: " + body); return ("Received incorrect body: " + body);
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should be possible to send unexpected query parameters', (done: Done) => { it('Should be possible to send unexpected query parameters', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&fakeparam=hello&category=sponsor") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest&fakeparam=hello&category=sponsor")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const body = await res.text(); const body = await res.text();
const data = JSON.parse(body); const data = JSON.parse(body);
if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11 if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") { && data[0].category === "sponsor" && data[0].UUID === "1-uuid-0") {
done(); return;
} else { } else {
done("Received incorrect body: " + body); return ("Received incorrect body: " + body);
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Low voted submissions should be hidden', (done: Done) => { it('Low voted submissions should be hidden', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=test3&category=sponsor") fetch(getbaseURL() + "/api/skipSegments?videoID=test3&category=sponsor")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const body = await res.text(); const body = await res.text();
const data = JSON.parse(body); const data = JSON.parse(body);
if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11 if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-4") { && data[0].category === "sponsor" && data[0].UUID === "1-uuid-4") {
done(); return;
} else { } else {
done("Received incorrect body: " + body); return ("Received incorrect body: " + body);
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should return 404 if no segment found', (done: Done) => { it('Should return 404 if no segment found', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=notarealvideo") fetch(getbaseURL() + "/api/skipSegments?videoID=notarealvideo")
.then(res => { .then(res => {
if (res.status !== 404) done("non 404 respone code: " + res.status); if (res.status !== 404) return ("non 404 respone code: " + res.status);
else done(); // pass else return; // pass
}) })
.catch(err => done("couldn't call endpoint")); .catch(err => ("couldn't call endpoint"));
}); });
it('Should be able send a comma in a query param', (done: Done) => { it('Should be able send a comma in a query param', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest,test&category=sponsor") fetch(getbaseURL() + "/api/skipSegments?videoID=testtesttest,test&category=sponsor")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const body = await res.text(); const body = await res.text();
const data = JSON.parse(body); const data = JSON.parse(body);
if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11 if (data.length === 1 && data[0].segment[0] === 1 && data[0].segment[1] === 11
&& data[0].category === "sponsor" && data[0].UUID === "1-uuid-1") { && data[0].category === "sponsor" && data[0].UUID === "1-uuid-1") {
done(); return;
} else { } else {
done("Received incorrect body: " + body); return ("Received incorrect body: " + body);
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
it('Should always get locked segment', (done: Done) => { it('Should always get locked segment', () => {
fetch(getbaseURL() + "/api/skipSegments?videoID=locked&category=intro") fetch(getbaseURL() + "/api/skipSegments?videoID=locked&category=intro")
.then(async res => { .then(async res => {
if (res.status !== 200) done("Status code was: " + res.status); if (res.status !== 200) return ("Status code was: " + res.status);
else { else {
const data = await res.json(); const data = await res.json();
if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33 if (data.length === 1 && data[0].segment[0] === 20 && data[0].segment[1] === 33
&& data[0].category === "intro" && data[0].UUID === "1-uuid-locked-8") { && data[0].category === "intro" && data[0].UUID === "1-uuid-locked-8") {
done(); return;
} else { } else {
done("Received incorrect body: " + (await res.text())); return ("Received incorrect body: " + (await res.text()));
} }
} }
}) })
.catch(err => done("Couldn't call endpoint")); .catch(err => ("Couldn't call endpoint"));
}); });
}); });

View file

@ -4,30 +4,30 @@ import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
describe('getUserInfo', () => { describe('getUserInfo', () => {
before(() => { before(async () => {
let startOfUserNamesQuery = "INSERT INTO userNames (userID, userName) VALUES"; let startOfUserNamesQuery = `INSERT INTO "userNames" ("userID", "userName") VALUES`;
db.exec(startOfUserNamesQuery + "('" + getHash("getuserinfo_user_01") + "', 'Username user 01')"); await db.prepare("run", startOfUserNamesQuery + "('" + getHash("getuserinfo_user_01") + "', 'Username user 01')");
let startOfSponsorTimesQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden) VALUES"; let startOfSponsorTimesQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden") VALUES';
db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000001', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)"); await db.prepare("run", startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000001', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)");
db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000002', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)"); await db.prepare("run", startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000002', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)");
db.exec(startOfSponsorTimesQuery + "('yyyxxxzzz', 1, 11, -1, 'uuid000003', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)"); await db.prepare("run", startOfSponsorTimesQuery + "('yyyxxxzzz', 1, 11, -1, 'uuid000003', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 0)");
db.exec(startOfSponsorTimesQuery + "('yyyxxxzzz', 1, 11, -2, 'uuid000004', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 1)"); await db.prepare("run", startOfSponsorTimesQuery + "('yyyxxxzzz', 1, 11, -2, 'uuid000004', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 1)");
db.exec(startOfSponsorTimesQuery + "('xzzzxxyyy', 1, 11, -5, 'uuid000005', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 1)"); await db.prepare("run", startOfSponsorTimesQuery + "('xzzzxxyyy', 1, 11, -5, 'uuid000005', '" + getHash("getuserinfo_user_01") + "', 0, 10, 'sponsor', 1)");
db.exec(startOfSponsorTimesQuery + "('zzzxxxyyy', 1, 11, 2, 'uuid000006', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 0)"); await db.prepare("run", startOfSponsorTimesQuery + "('zzzxxxyyy', 1, 11, 2, 'uuid000006', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 0)");
db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000007', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)"); await db.prepare("run", startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000007', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)");
db.exec(startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000008', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)"); await db.prepare("run", startOfSponsorTimesQuery + "('xxxyyyzzz', 1, 11, 2, 'uuid000008', '" + getHash("getuserinfo_user_02") + "', 0, 10, 'sponsor', 1)");
db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES ('" + getHash('getuserinfo_warning_0') + "', 10, 'getuserinfo_vip', 1)"); await db.prepare("run", `INSERT INTO warnings ("userID", "issueTime", "issuerUserID", enabled) VALUES ('` + getHash('getuserinfo_warning_0') + "', 10, 'getuserinfo_vip', 1)");
db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES ('" + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip', 1)"); await db.prepare("run", `INSERT INTO warnings ("userID", "issueTime", "issuerUserID", enabled) VALUES ('` + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip', 1)");
db.exec("INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES ('" + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip', 1)"); await db.prepare("run", `INSERT INTO warnings ("userID", "issueTime", "issuerUserID", enabled) VALUES ('` + getHash('getuserinfo_warning_1') + "', 10, 'getuserinfo_vip', 1)");
}); });
it('Should be able to get a 200', (done: Done) => { it('Should be able to get a 200', (done: Done) => {
fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_01') fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_01')
.then(res => { .then(res => {
if (res.status !== 200) done('non 200 (' + res.status + ')'); if (res.status !== 200) done('non 200 (' + res.status + ')');
else done(); // pass else done(); // pass
}) })
.catch(err => done('couldn\'t call endpoint')); .catch(err => done('couldn\'t call endpoint'));
}); });
@ -41,7 +41,7 @@ describe('getUserInfo', () => {
.catch(err => done('couldn\'t call endpoint')); .catch(err => done('couldn\'t call endpoint'));
}); });
it('Should return info', (done: Done) => { it('Should done(info', (done: Done) => {
fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_01') fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_01')
.then(async res => { .then(async res => {
if (res.status !== 200) { if (res.status !== 200) {
@ -61,7 +61,7 @@ describe('getUserInfo', () => {
} }
} }
}) })
.catch(err => done("couldn't call endpoint")); .catch(err => ("couldn't call endpoint"));
}); });
it('Should get warning data', (done: Done) => { it('Should get warning data', (done: Done) => {
@ -75,7 +75,7 @@ describe('getUserInfo', () => {
else done(); // pass else done(); // pass
} }
}) })
.catch(err => done("couldn't call endpoint")); .catch(err => ("couldn't call endpoint"));
}); });
it('Should get multiple warnings', (done: Done) => { it('Should get multiple warnings', (done: Done) => {
@ -89,7 +89,7 @@ describe('getUserInfo', () => {
else done(); // pass else done(); // pass
} }
}) })
.catch(err => done("couldn't call endpoint")); .catch(err => ("couldn't call endpoint"));
}); });
it('Should not get warnings if noe', (done: Done) => { it('Should not get warnings if noe', (done: Done) => {
@ -103,10 +103,10 @@ describe('getUserInfo', () => {
else done(); // pass else done(); // pass
} }
}) })
.catch(err => done("couldn't call endpoint")); .catch(err => ("couldn't call endpoint"));
}); });
it('Should return userID for userName (No userName set)', (done: Done) => { it('Should done(userID for userName (No userName set)', (done: Done) => {
fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_02') fetch(getbaseURL() + '/api/getUserInfo?userID=getuserinfo_user_02')
.then(async res => { .then(async res => {
if (res.status !== 200) { if (res.status !== 200) {
@ -114,11 +114,11 @@ describe('getUserInfo', () => {
} else { } else {
const data = await res.json(); const data = await res.json();
if (data.userName !== 'c2a28fd225e88f74945794ae85aef96001d4a1aaa1022c656f0dd48ac0a3ea0f') { if (data.userName !== 'c2a28fd225e88f74945794ae85aef96001d4a1aaa1022c656f0dd48ac0a3ea0f') {
return done('Did not return userID for userName'); done('Did not done(userID for userName');
} }
done(); // pass done(); // pass
} }
}) })
.catch(err => done('couldn\'t call endpoint')); .catch(err => ('couldn\'t call endpoint'));
}); });
}); });

View file

@ -5,26 +5,26 @@ import {db} from '../../src/databases/databases';
describe('noSegmentRecords', () => { describe('noSegmentRecords', () => {
before(() => { before(async () => {
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("VIPUser-noSegments") + "')"); await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("VIPUser-noSegments") + "')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'no-segments-video-id', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'no-segments-video-id', 'sponsor')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'no-segments-video-id', 'intro')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'no-segments-video-id', 'intro')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'no-segments-video-id-1', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'no-segments-video-id-1', 'sponsor')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'no-segments-video-id-1', 'intro')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'no-segments-video-id-1', 'intro')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'noSubmitVideo', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'noSubmitVideo', 'sponsor')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'delete-record', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'delete-record', 'sponsor')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'delete-record-1', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'delete-record-1', 'sponsor')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-noSegments") + "', 'delete-record-1', 'intro')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-noSegments") + "', 'delete-record-1', 'intro')");
}); });
it('Should update the database version when starting the application', (done: Done) => { it('Should update the database version when starting the application', async () => {
let version = db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version']).value; let version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value;
if (version > 1) done(); if (version > 1) return;
else done('Version isn\'t greater than 1. Version is ' + version); else return 'Version isn\'t greater than 1. Version is ' + version;
}); });
it('Should be able to submit categories not in video (http response)', (done: Done) => { it('Should be able to submit categories not in video (http response)', (done: Done) => {
@ -95,7 +95,7 @@ describe('noSegmentRecords', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['no-segments-video-id-1']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['no-segments-video-id-1']);
if (result.length !== 4) { if (result.length !== 4) {
console.log(result); console.log(result);
done("Expected 4 entrys in db, got " + result.length); done("Expected 4 entrys in db, got " + result.length);
@ -129,7 +129,7 @@ describe('noSegmentRecords', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['underscore']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['underscore']);
if (result.length !== 1) { if (result.length !== 1) {
console.log(result); console.log(result);
done("Expected 1 entrys in db, got " + result.length); done("Expected 1 entrys in db, got " + result.length);
@ -163,7 +163,7 @@ describe('noSegmentRecords', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['bothCases']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['bothCases']);
if (result.length !== 1) { if (result.length !== 1) {
console.log(result); console.log(result);
done("Expected 1 entrys in db, got " + result.length); done("Expected 1 entrys in db, got " + result.length);
@ -197,7 +197,7 @@ describe('noSegmentRecords', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['specialChar']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['specialChar']);
if (result.length !== 0) { if (result.length !== 0) {
console.log(result); console.log(result);
done("Expected 0 entrys in db, got " + result.length); done("Expected 0 entrys in db, got " + result.length);
@ -221,7 +221,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify({}), body: JSON.stringify({}),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -245,7 +245,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -269,7 +269,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -293,7 +293,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -317,7 +317,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -341,7 +341,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -367,7 +367,7 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -393,9 +393,9 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['delete-record']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['delete-record']);
if (result.length === 0) { if (result.length === 0) {
done(); done();
} else { } else {
@ -424,9 +424,9 @@ describe('noSegmentRecords', () => {
}, },
body: JSON.stringify(json), body: JSON.stringify(json),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM noSegments WHERE videoID = ?', ['delete-record-1']); let result = await db.prepare('all', 'SELECT * FROM "noSegments" WHERE "videoID" = ?', ['delete-record-1']);
if (result.length === 1) { if (result.length === 1) {
done(); done();
} else { } else {
@ -460,7 +460,7 @@ describe('noSegmentRecords', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -488,7 +488,7 @@ describe('noSegmentRecords', () => {
}], }],
},), },),
}) })
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -514,7 +514,7 @@ describe('noSegmentRecords', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
done(); done();
} else { } else {
@ -539,7 +539,7 @@ describe('noSegmentRecords', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
done(); done();
} else { } else {

View file

@ -18,9 +18,9 @@ import {getHash} from '../../src/utils/getHash';
describe('getVideoSponsorTime (Old get method)', () => { describe('getVideoSponsorTime (Old get method)', () => {
before(() => { before(() => {
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfQuery + "('old-testtesttest', 1, 11, 2, 'uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('old-testtesttest', 1) + "')"); db.prepare("run", startOfQuery + "('old-testtesttest', 1, 11, 2, 'uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('old-testtesttest', 1) + "')");
db.exec(startOfQuery + "('old-testtesttest,test', 1, 11, 2, 'uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('old-testtesttest,test', 1) + "')"); db.prepare("run", startOfQuery + "('old-testtesttest,test', 1, 11, 2, 'uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('old-testtesttest,test', 1) + "')");
}); });
it('Should be able to get a time', (done: Done) => { it('Should be able to get a time', (done: Done) => {

View file

@ -7,9 +7,9 @@ describe('postVideoSponsorTime (Old submission method)', () => {
it('Should be able to submit a time (GET)', (done: Done) => { it('Should be able to submit a time (GET)', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/postVideoSponsorTimes?videoID=dQw4w9WgXcQ&startTime=1&endTime=10&userID=test") + "/api/postVideoSponsorTimes?videoID=dQw4w9WgXcQ&startTime=1&endTime=10&userID=test")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ?", ["dQw4w9WgXcQ"]); let row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcQ"]);
if (row.startTime === 1 && row.endTime === 10 && row.category === "sponsor") { if (row.startTime === 1 && row.endTime === 10 && row.category === "sponsor") {
done(); done();
} else { } else {
@ -30,9 +30,9 @@ describe('postVideoSponsorTime (Old submission method)', () => {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ?", ["dQw4w9WgXcE"]); let row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcE"]);
if (row.startTime === 1 && row.endTime === 11 && row.category === "sponsor") { if (row.startTime === 1 && row.endTime === 11 && row.category === "sponsor") {
done(); done();
} else { } else {
@ -48,7 +48,7 @@ describe('postVideoSponsorTime (Old submission method)', () => {
it('Should return 400 for missing params', (done: Done) => { it('Should return 400 for missing params', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=test") + "/api/postVideoSponsorTimes?startTime=1&endTime=10&userID=test")
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done("Status code was: " + res.status); else done("Status code was: " + res.status);
}) })

View file

@ -13,11 +13,11 @@ sinonStub.callsFake(YouTubeApiMock.listVideos);
describe('postSkipSegments', () => { describe('postSkipSegments', () => {
before(() => { before(() => {
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfQuery + "('80percent_video', 0, 1000, 0, '80percent-uuid-0', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')"); db.prepare("run", startOfQuery + "('80percent_video', 0, 1000, 0, '80percent-uuid-0', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')");
db.exec(startOfQuery + "('80percent_video', 1001, 1005, 0, '80percent-uuid-1', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')"); db.prepare("run", startOfQuery + "('80percent_video', 1001, 1005, 0, '80percent-uuid-1', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')");
db.exec(startOfQuery + "('80percent_video', 0, 5000, -2, '80percent-uuid-2', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')"); db.prepare("run", startOfQuery + "('80percent_video', 0, 5000, -2, '80percent-uuid-2', '" + getHash("test") + "', 0, 0, 'interaction', 0, '80percent_video')");
const now = Date.now(); const now = Date.now();
const warnVip01Hash = getHash("warn-vip01"); const warnVip01Hash = getHash("warn-vip01");
@ -26,21 +26,21 @@ describe('postSkipSegments', () => {
const warnUser03Hash = getHash("warn-user03"); const warnUser03Hash = getHash("warn-user03");
const MILLISECONDS_IN_HOUR = 3600000; const MILLISECONDS_IN_HOUR = 3600000;
const warningExpireTime = MILLISECONDS_IN_HOUR * config.hoursAfterWarningExpires; const warningExpireTime = MILLISECONDS_IN_HOUR * config.hoursAfterWarningExpires;
const startOfWarningQuery = 'INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES'; const startOfWarningQuery = 'INSERT INTO warnings ("userID", "issueTime", "issuerUserID", enabled) VALUES';
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 1000)) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 1000)) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 2000)) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 2000)) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser03Hash + "', '" + now + "', '" + warnVip01Hash + "', 0)"); db.prepare("run", startOfWarningQuery + "('" + warnUser03Hash + "', '" + now + "', '" + warnVip01Hash + "', 0)");
db.exec(startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 0)"); db.prepare("run", startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 0)");
db.exec(startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)"); db.prepare("run", startOfWarningQuery + "('" + warnUser03Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)");
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("VIPUserSubmission") + "')"); db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("VIPUserSubmission") + "')");
}); });
it('Should be able to submit a single time (Params method)', (done: Done) => { it('Should be able to submit a single time (Params method)', (done: Done) => {
@ -51,9 +51,9 @@ describe('postSkipSegments', () => {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
const row = db.prepare('get', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ?", ["dQw4w9WgXcR"]); const row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcR"]);
if (row.startTime === 2 && row.endTime === 10 && row.category === "sponsor") { if (row.startTime === 2 && row.endTime === 10 && row.category === "sponsor") {
done(); done();
} else { } else {
@ -82,9 +82,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
const row = db.prepare('get', "SELECT startTime, endTime, locked, category FROM sponsorTimes WHERE videoID = ?", ["dQw4w9WgXcF"]); const row = await db.prepare('get', `SELECT "startTime", "endTime", "locked", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcF"]);
if (row.startTime === 0 && row.endTime === 10 && row.locked === 0 && row.category === "sponsor") { if (row.startTime === 0 && row.endTime === 10 && row.locked === 0 && row.category === "sponsor") {
done(); done();
} else { } else {
@ -113,9 +113,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
const row = db.prepare('get', "SELECT startTime, endTime, locked, category FROM sponsorTimes WHERE videoID = ?", ["vipuserIDSubmission"]); const row = await db.prepare('get', `SELECT "startTime", "endTime", "locked", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["vipuserIDSubmission"]);
if (row.startTime === 0 && row.endTime === 10 && row.locked === 1 && row.category === "sponsor") { if (row.startTime === 0 && row.endTime === 10 && row.locked === 1 && row.category === "sponsor") {
done(); done();
} else { } else {
@ -147,9 +147,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
const rows = db.prepare('all', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ?", ["dQw4w9WgXcR"]); const rows = await db.prepare('all', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcR"]);
let success = true; let success = true;
if (rows.length === 2) { if (rows.length === 2) {
for (const row of rows) { for (const row of rows) {
@ -194,9 +194,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
const rows = db.prepare('all', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ? and votes > -1", ["L_jWHffIx5E"]); const rows = await db.prepare('all', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ? and "votes" > -1`, ["L_jWHffIx5E"]);
let success = true; let success = true;
if (rows.length === 4) { if (rows.length === 4) {
for (const row of rows) { for (const row of rows) {
@ -243,9 +243,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
const rows = db.prepare('all', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ? and votes > -1", ["n9rIGdXnSJc"]); const rows = await db.prepare('all', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ? and "votes" > -1`, ["n9rIGdXnSJc"]);
let success = true; let success = true;
if (rows.length === 4) { if (rows.length === 4) {
for (const row of rows) { for (const row of rows) {
@ -291,9 +291,9 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
const rows = db.prepare('all', "SELECT startTime, endTime, category FROM sponsorTimes WHERE videoID = ? and votes > -1", ["80percent_video"]); const rows = await db.prepare('all', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ? and "votes" > -1`, ["80percent_video"]);
let success = rows.length == 2; let success = rows.length == 2;
for (const row of rows) { for (const row of rows) {
if ((row.startTime === 2000 || row.endTime === 4000 || row.category === "sponsor") || if ((row.startTime === 2000 || row.endTime === 4000 || row.category === "sponsor") ||
@ -385,7 +385,7 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); // success done(); // success
} else { } else {
@ -482,7 +482,7 @@ describe('postSkipSegments', () => {
+ "/api/postVideoSponsorTimes?startTime=9&endTime=10&userID=test", { + "/api/postVideoSponsorTimes?startTime=9&endTime=10&userID=test", {
method: 'POST', method: 'POST',
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })
@ -507,7 +507,7 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })
@ -525,7 +525,7 @@ describe('postSkipSegments', () => {
videoID: "dQw4w9WgXcQ", videoID: "dQw4w9WgXcQ",
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })
@ -550,7 +550,7 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })
@ -574,7 +574,7 @@ describe('postSkipSegments', () => {
}], }],
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })
@ -592,7 +592,7 @@ describe('postSkipSegments', () => {
videoID: "dQw4w9WgXcQ", videoID: "dQw4w9WgXcQ",
}), }),
}) })
.then(res => { .then(async res => {
if (res.status === 400) done(); if (res.status === 400) done();
else done(true); else done(true);
}) })

View file

@ -4,8 +4,8 @@ import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
describe('postWarning', () => { describe('postWarning', () => {
before(() => { before(async () => {
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("warning-vip") + "')"); await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("warning-vip") + "')");
}); });
it('Should be able to create warning if vip (exp 200)', (done: Done) => { it('Should be able to create warning if vip (exp 200)', (done: Done) => {
@ -23,7 +23,7 @@ describe('postWarning', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT userID, issueTime, issuerUserID, enabled FROM warnings WHERE userID = ?", [json.userID]); let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID)) { if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID)) {
done(); done();
} else { } else {
@ -54,7 +54,7 @@ describe('postWarning', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 409) { if (res.status === 409) {
let row = db.prepare('get', "SELECT userID, issueTime, issuerUserID, enabled FROM warnings WHERE userID = ?", [json.userID]); let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID)) { if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID)) {
done(); done();
} else { } else {
@ -86,7 +86,7 @@ describe('postWarning', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT userID, issueTime, issuerUserID, enabled FROM warnings WHERE userID = ?", [json.userID]); let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]);
if (row?.enabled == 0) { if (row?.enabled == 0) {
done(); done();
} else { } else {

View file

@ -4,30 +4,30 @@ import {db} from '../../src/databases/databases';
import {getHash} from '../../src/utils/getHash'; import {getHash} from '../../src/utils/getHash';
import {IDatabase} from '../../src/databases/IDatabase'; import {IDatabase} from '../../src/databases/IDatabase';
function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: number, endTime: number, UUID: string, category: string) { async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: number, endTime: number, UUID: string, category: string) {
const votes = 0, const votes = 0,
userID = 0, userID = 0,
timeSubmitted = 0, timeSubmitted = 0,
views = 0, views = 0,
shadowHidden = 0, shadowHidden = 0,
hashedVideoID = `hash_${UUID}`; hashedVideoID = `hash_${UUID}`;
db.exec(`INSERT INTO await db.prepare("run", `INSERT INTO
sponsorTimes (videoID, startTime, endTime, votes, UUID, "sponsorTimes" ("videoID", "startTime", "endTime", votes, "UUID",
userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID")
VALUES VALUES
('${videoID}', ${startTime}, ${endTime}, ${votes}, '${UUID}', ('${videoID}', ${startTime}, ${endTime}, ${votes}, '${UUID}',
'${userID}', ${timeSubmitted}, ${views}, '${category}', ${shadowHidden}, '${hashedVideoID}') '${userID}', ${timeSubmitted}, ${views}, '${category}', ${shadowHidden}, '${hashedVideoID}')
`); `);
} }
function dbSponsorTimesSetByUUID(db: IDatabase, UUID: string, startTime: number, endTime: number) { async function dbSponsorTimesSetByUUID(db: IDatabase, UUID: string, startTime: number, endTime: number) {
db.prepare('run', `UPDATE sponsorTimes SET startTime = ?, endTime = ? WHERE UUID = ?`, [startTime, endTime, UUID]); await db.prepare('run', `UPDATE "sponsorTimes" SET "startTime" = ?, "endTime" = ? WHERE "UUID" = ?`, [startTime, endTime, UUID]);
} }
function dbSponsorTimesCompareExpect(db: IDatabase, expect: any) { async function dbSponsorTimesCompareExpect(db: IDatabase, expect: any) {
for (let i = 0, len = expect.length; i < len; i++) { for (let i = 0, len = expect.length; i < len; i++) {
const expectSeg = expect[i]; const expectSeg = expect[i];
let seg = db.prepare('get', "SELECT startTime, endTime FROM sponsorTimes WHERE UUID = ?", [expectSeg.UUID]); let seg = await db.prepare('get', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "UUID" = ?`, [expectSeg.UUID]);
if ('removed' in expect) { if ('removed' in expect) {
if (expect.removed === true && seg.votes === -2) { if (expect.removed === true && seg.votes === -2) {
return; return;
@ -50,14 +50,13 @@ describe('segmentShift', function () {
const vipUserID = getHash(privateVipUserID); const vipUserID = getHash(privateVipUserID);
const baseURL = getbaseURL(); const baseURL = getbaseURL();
before(function (done: Done) { before(async function () {
// startTime and endTime get set in beforeEach for consistency // startTime and endTime get set in beforeEach for consistency
dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid01', 'intro'); await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid01', 'intro');
dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid02', 'sponsor'); await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid02', 'sponsor');
dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid03', 'interaction'); await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid03', 'interaction');
dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid04', 'outro'); await dbSponsorTimesAdd(db, 'vsegshift01', 0, 0, 'vsegshifttest01uuid04', 'outro');
db.exec(`INSERT INTO vipUsers (userID) VALUES ('${vipUserID}')`); await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('${vipUserID}')`);
done();
}); });
beforeEach(function (done: Done) { beforeEach(function (done: Done) {
@ -82,7 +81,7 @@ describe('segmentShift', function () {
endTime: 30, endTime: 30,
}), }),
}) })
.then(res => { .then(async res => {
done(res.status === 403 ? undefined : res.status); done(res.status === 403 ? undefined : res.status);
}) })
.catch(err => done(err)); .catch(err => done(err));
@ -101,7 +100,7 @@ describe('segmentShift', function () {
endTime: 30, endTime: 30,
}), }),
}) })
.then(res => { .then(async res => {
if (res.status !== 200) return done(`Status code was ${res.status}`); if (res.status !== 200) return done(`Status code was ${res.status}`);
const expect = [ const expect = [
{ {
@ -125,7 +124,7 @@ describe('segmentShift', function () {
endTime: 130, endTime: 130,
}, },
]; ];
done(dbSponsorTimesCompareExpect(db, expect)); done(await dbSponsorTimesCompareExpect(db, expect));
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });
@ -143,7 +142,7 @@ describe('segmentShift', function () {
endTime: 75, endTime: 75,
}), }),
}) })
.then(res => { .then(async res => {
if (res.status !== 200) return done(`Status code was ${res.status}`); if (res.status !== 200) return done(`Status code was ${res.status}`);
const expect = [ const expect = [
{ {
@ -167,7 +166,7 @@ describe('segmentShift', function () {
endTime: 130, endTime: 130,
}, },
]; ];
done(dbSponsorTimesCompareExpect(db, expect)); done(await dbSponsorTimesCompareExpect(db, expect));
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });
@ -185,7 +184,7 @@ describe('segmentShift', function () {
endTime: 42, endTime: 42,
}), }),
}) })
.then(res => { .then(async res => {
if (res.status !== 200) return done(`Status code was ${res.status}`); if (res.status !== 200) return done(`Status code was ${res.status}`);
const expect = [ const expect = [
{ {
@ -209,7 +208,7 @@ describe('segmentShift', function () {
endTime: 130, endTime: 130,
}, },
]; ];
done(dbSponsorTimesCompareExpect(db, expect)); done(await dbSponsorTimesCompareExpect(db, expect));
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });
@ -227,7 +226,7 @@ describe('segmentShift', function () {
endTime: 95, endTime: 95,
}), }),
}) })
.then(res => { .then(async res => {
if (res.status !== 200) return done(`Status code was ${res.status}`); if (res.status !== 200) return done(`Status code was ${res.status}`);
const expect = [ const expect = [
{ {
@ -251,7 +250,7 @@ describe('segmentShift', function () {
endTime: 130, endTime: 130,
}, },
]; ];
done(dbSponsorTimesCompareExpect(db, expect)); done(await dbSponsorTimesCompareExpect(db, expect));
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });
@ -269,7 +268,7 @@ describe('segmentShift', function () {
endTime: 55, endTime: 55,
}), }),
}) })
.then(res => { .then(async res => {
if (res.status !== 200) return done(`Status code was ${res.status}`); if (res.status !== 200) return done(`Status code was ${res.status}`);
const expect = [ const expect = [
{ {
@ -294,7 +293,7 @@ describe('segmentShift', function () {
endTime: 120, endTime: 120,
}, },
]; ];
done(dbSponsorTimesCompareExpect(db, expect)); done(await dbSponsorTimesCompareExpect(db, expect));
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });

View file

@ -3,23 +3,23 @@ import fetch from 'node-fetch';
import * as utils from '../utils'; import * as utils from '../utils';
import { getHash } from '../../src/utils/getHash'; import { getHash } from '../../src/utils/getHash';
import { db } from '../../src/databases/databases'; import { db, privateDB } from '../../src/databases/databases';
import { Logger } from '../../src/utils/logger.js'; import { Logger } from '../../src/utils/logger.js';
describe('unBan', () => { describe('unBan', () => {
before(() => { before(async () => {
db.exec("INSERT INTO shadowBannedUsers VALUES('testMan-unBan')"); await privateDB.prepare("run", `INSERT INTO "shadowBannedUsers" VALUES('testMan-unBan')`);
db.exec("INSERT INTO shadowBannedUsers VALUES('testWoman-unBan')"); await privateDB.prepare("run", `INSERT INTO "shadowBannedUsers" VALUES('testWoman-unBan')`);
db.exec("INSERT INTO shadowBannedUsers VALUES('testEntity-unBan')"); await privateDB.prepare("run", `INSERT INTO "shadowBannedUsers" VALUES('testEntity-unBan')`);
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("VIPUser-unBan") + "')"); await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("VIPUser-unBan") + "')");
db.exec("INSERT INTO noSegments (userID, videoID, category) VALUES ('" + getHash("VIPUser-unBan") + "', 'unBan-videoID-1', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("userID", "videoID", "category") VALUES ('` + getHash("VIPUser-unBan") + "', 'unBan-videoID-1', 'sponsor')");
let startOfInsertSegmentQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfInsertSegmentQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
db.exec(startOfInsertSegmentQuery + "('unBan-videoID-0', 1, 11, 2, 'unBan-uuid-0', 'testMan-unBan', 0, 50, 'sponsor', 1, '" + getHash('unBan-videoID-0', 1) + "')"); await db.prepare("run", startOfInsertSegmentQuery + "('unBan-videoID-0', 1, 11, 2, 'unBan-uuid-0', 'testMan-unBan', 0, 50, 'sponsor', 1, '" + getHash('unBan-videoID-0', 1) + "')");
db.exec(startOfInsertSegmentQuery + "('unBan-videoID-1', 1, 11, 2, 'unBan-uuid-1', 'testWoman-unBan', 0, 50, 'sponsor', 1, '" + getHash('unBan-videoID-1', 1) + "')"); await db.prepare("run", startOfInsertSegmentQuery + "('unBan-videoID-1', 1, 11, 2, 'unBan-uuid-1', 'testWoman-unBan', 0, 50, 'sponsor', 1, '" + getHash('unBan-videoID-1', 1) + "')");
db.exec(startOfInsertSegmentQuery + "('unBan-videoID-1', 1, 11, 2, 'unBan-uuid-2', 'testEntity-unBan', 0, 60, 'sponsor', 1, '" + getHash('unBan-videoID-1', 1) + "')"); await db.prepare("run", startOfInsertSegmentQuery + "('unBan-videoID-1', 1, 11, 2, 'unBan-uuid-2', 'testEntity-unBan', 0, 60, 'sponsor', 1, '" + getHash('unBan-videoID-1', 1) + "')");
db.exec(startOfInsertSegmentQuery + "('unBan-videoID-2', 1, 11, 2, 'unBan-uuid-3', 'testEntity-unBan', 0, 60, 'sponsor', 1, '" + getHash('unBan-videoID-2', 1) + "')"); await db.prepare("run", startOfInsertSegmentQuery + "('unBan-videoID-2', 1, 11, 2, 'unBan-uuid-3', 'testEntity-unBan', 0, 60, 'sponsor', 1, '" + getHash('unBan-videoID-2', 1) + "')");
}); });
it('Should be able to unban a user and re-enable shadow banned segments', (done) => { it('Should be able to unban a user and re-enable shadow banned segments', (done) => {
@ -31,7 +31,7 @@ describe('unBan', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM sponsorTimes WHERE videoID = ? AND userID = ? AND shadowHidden = ?', ['unBan-videoID-0', 'testMan-unBan', 1]); let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-0', 'testMan-unBan', 1]);
if (result.length !== 0) { if (result.length !== 0) {
console.log(result); console.log(result);
done("Expected 0 banned entrys in db, got " + result.length); done("Expected 0 banned entrys in db, got " + result.length);
@ -56,7 +56,7 @@ describe('unBan', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM sponsorTimes WHERE videoID = ? AND userID = ? AND shadowHidden = ?', ['unBan-videoID-1', 'testWoman-unBan', 1]); let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-1', 'testWoman-unBan', 1]);
if (result.length !== 1) { if (result.length !== 1) {
console.log(result); console.log(result);
done("Expected 1 banned entry1 in db, got " + result.length); done("Expected 1 banned entry1 in db, got " + result.length);
@ -81,7 +81,7 @@ describe('unBan', () => {
}) })
.then(async res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let result = db.prepare('all', 'SELECT * FROM sponsorTimes WHERE userID = ? AND shadowHidden = ?', ['testEntity-unBan', 1]); let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?', ['testEntity-unBan', 1]);
if (result.length !== 1) { if (result.length !== 1) {
console.log(result); console.log(result);
done("Expected 1 banned entry1 in db, got " + result.length); done("Expected 1 banned entry1 in db, got " + result.length);

View file

@ -12,63 +12,63 @@ const sinonStub = mockManager.mock('listVideos');
sinonStub.callsFake(YouTubeApiMock.listVideos); sinonStub.callsFake(YouTubeApiMock.listVideos);
describe('voteOnSponsorTime', () => { describe('voteOnSponsorTime', () => {
before(() => { before(async () => {
const now = Date.now(); const now = Date.now();
const warnVip01Hash = getHash("warn-vip01"); const warnVip01Hash = getHash("warn-vip01");
const warnUser01Hash = getHash("warn-voteuser01"); const warnUser01Hash = getHash("warn-voteuser01");
const warnUser02Hash = getHash("warn-voteuser02"); const warnUser02Hash = getHash("warn-voteuser02");
const MILLISECONDS_IN_HOUR = 3600000; const MILLISECONDS_IN_HOUR = 3600000;
const warningExpireTime = MILLISECONDS_IN_HOUR * config.hoursAfterWarningExpires; const warningExpireTime = MILLISECONDS_IN_HOUR * config.hoursAfterWarningExpires;
let startOfQuery = "INSERT INTO sponsorTimes (videoID, startTime, endTime, votes, UUID, userID, timeSubmitted, views, category, shadowHidden, hashedVideoID) VALUES"; let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
const startOfWarningQuery = 'INSERT INTO warnings (userID, issueTime, issuerUserID, enabled) VALUES'; const startOfWarningQuery = 'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled") VALUES';
db.exec(startOfQuery + "('vote-testtesttest', 1, 11, 2, 'vote-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest', 1, 11, 2, 'vote-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest2', 1, 11, 2, 'vote-uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest2', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest2', 1, 11, 2, 'vote-uuid-1', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest2', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.5', 'testman', 0, 50, 'outro', 0, '" + getHash('vote-testtesttest2', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.5', 'testman', 0, 50, 'outro', 0, '" + getHash('vote-testtesttest2', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.6', 'testman', 0, 50, 'interaction', 0, '" + getHash('vote-testtesttest2', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest2', 1, 11, 10, 'vote-uuid-1.6', 'testman', 0, 50, 'interaction', 0, '" + getHash('vote-testtesttest2', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest3', 20, 33, 10, 'vote-uuid-2', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-testtesttest3', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest3', 20, 33, 10, 'vote-uuid-2', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-testtesttest3', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest,test', 1, 11, 100, 'vote-uuid-3', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest,test', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest,test', 1, 11, 100, 'vote-uuid-3', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest,test', 1) + "')");
db.exec(startOfQuery + "('vote-test3', 1, 11, 2, 'vote-uuid-4', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-test3', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-test3', 1, 11, 2, 'vote-uuid-4', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-test3', 1) + "')");
db.exec(startOfQuery + "('vote-test3', 7, 22, -3, 'vote-uuid-5', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-test3', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-test3', 7, 22, -3, 'vote-uuid-5', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-test3', 1) + "')");
db.exec(startOfQuery + "('vote-test3', 7, 22, -3, 'vote-uuid-5_1', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-test3', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-test3', 7, 22, -3, 'vote-uuid-5_1', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-test3', 1) + "')");
db.exec(startOfQuery + "('vote-multiple', 1, 11, 2, 'vote-uuid-6', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-multiple', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-multiple', 1, 11, 2, 'vote-uuid-6', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-multiple', 1) + "')");
db.exec(startOfQuery + "('vote-multiple', 20, 33, 2, 'vote-uuid-7', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-multiple', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-multiple', 20, 33, 2, 'vote-uuid-7', 'testman', 0, 50, 'intro', 0, '" + getHash('vote-multiple', 1) + "')");
db.exec(startOfQuery + "('voter-submitter', 1, 11, 2, 'vote-uuid-8', '" + getHash("randomID") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter', 1) + "')"); await db.prepare("run", startOfQuery + "('voter-submitter', 1, 11, 2, 'vote-uuid-8', '" + getHash("randomID") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter', 1) + "')");
db.exec(startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-9', '" + getHash("randomID2") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')"); await db.prepare("run", startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-9', '" + getHash("randomID2") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')");
db.exec(startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-10', '" + getHash("randomID3") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')"); await db.prepare("run", startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-10', '" + getHash("randomID3") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')");
db.exec(startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-11', '" + getHash("randomID4") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')"); await db.prepare("run", startOfQuery + "('voter-submitter2', 1, 11, 2, 'vote-uuid-11', '" + getHash("randomID4") + "', 0, 50, 'sponsor', 0, '" + getHash('voter-submitter2', 1) + "')");
db.exec(startOfQuery + "('own-submission-video', 1, 11, 500, 'own-submission-uuid', '" + getHash('own-submission-id') + "', 0, 50, 'sponsor', 0, '" + getHash('own-submission-video', 1) + "')"); await db.prepare("run", startOfQuery + "('own-submission-video', 1, 11, 500, 'own-submission-uuid', '" + getHash('own-submission-id') + "', 0, 50, 'sponsor', 0, '" + getHash('own-submission-video', 1) + "')");
db.exec(startOfQuery + "('not-own-submission-video', 1, 11, 500, 'not-own-submission-uuid', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('not-own-submission-video', 1) + "')"); await db.prepare("run", startOfQuery + "('not-own-submission-video', 1, 11, 500, 'not-own-submission-uuid', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('not-own-submission-video', 1) + "')");
db.exec(startOfQuery + "('incorrect-category', 1, 11, 500, 'incorrect-category', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('incorrect-category', 1) + "')"); await db.prepare("run", startOfQuery + "('incorrect-category', 1, 11, 500, 'incorrect-category', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('incorrect-category', 1) + "')");
db.exec(startOfQuery + "('incorrect-category-change', 1, 11, 500, 'incorrect-category-change', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('incorrect-category-change', 1) + "')"); await db.prepare("run", startOfQuery + "('incorrect-category-change', 1, 11, 500, 'incorrect-category-change', '" + getHash('somebody-else-id') + "', 0, 50, 'sponsor', 0, '" + getHash('incorrect-category-change', 1) + "')");
db.exec(startOfQuery + "('vote-testtesttest', 1, 11, 2, 'warnvote-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest', 1) + "')"); await db.prepare("run", startOfQuery + "('vote-testtesttest', 1, 11, 2, 'warnvote-uuid-0', 'testman', 0, 50, 'sponsor', 0, '" + getHash('vote-testtesttest', 1) + "')");
db.exec(startOfQuery + "('no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-0', 'no-sponsor-segments', 0, 50, 'sponsor', 0, '" + getHash('no-sponsor-segments-video', 1) + "')"); await db.prepare("run", startOfQuery + "('no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-0', 'no-sponsor-segments', 0, 50, 'sponsor', 0, '" + getHash('no-sponsor-segments-video', 1) + "')");
db.exec(startOfQuery + "('no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-1', 'no-sponsor-segments', 0, 50, 'intro', 0, '" + getHash('no-sponsor-segments-video', 1) + "')"); await db.prepare("run", startOfQuery + "('no-sponsor-segments-video', 1, 11, 2, 'no-sponsor-segments-uuid-1', 'no-sponsor-segments', 0, 50, 'intro', 0, '" + getHash('no-sponsor-segments-video', 1) + "')");
db.exec(startOfQuery + "('segment-locking-video', 1, 11, 2, 'segment-locking-uuid-1', 'segment-locking-user', 0, 50, 'intro', 0, '" + getHash('segment-locking-video', 1) + "')"); await db.prepare("run", startOfQuery + "('segment-locking-video', 1, 11, 2, 'segment-locking-uuid-1', 'segment-locking-user', 0, 50, 'intro', 0, '" + getHash('segment-locking-video', 1) + "')");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 1000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 2000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser01Hash + "', '" + (now - 3601000) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + now + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 1000)) + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 1000)) + "', '" + warnVip01Hash + "', 1)");
db.exec(startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 2000)) + "', '" + warnVip01Hash + "', 1)"); await db.prepare("run", startOfWarningQuery + "('" + warnUser02Hash + "', '" + (now - (warningExpireTime + 2000)) + "', '" + warnVip01Hash + "', 1)");
db.exec("INSERT INTO vipUsers (userID) VALUES ('" + getHash("VIPUser") + "')"); await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("VIPUser") + "')");
privateDB.exec("INSERT INTO shadowBannedUsers (userID) VALUES ('" + getHash("randomID4") + "')"); await privateDB.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES ('` + getHash("randomID4") + "')");
db.exec("INSERT INTO noSegments (videoID, userID, category) VALUES ('no-sponsor-segments-video', 'someUser', 'sponsor')"); await db.prepare("run", `INSERT INTO "noSegments" ("videoID", "userID", "category") VALUES ('no-sponsor-segments-video', 'someUser', 'sponsor')`);
}); });
it('Should be able to upvote a segment', (done: Done) => { it('Should be able to upvote a segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID&UUID=vote-uuid-0&type=1") + "/api/voteOnSponsorTime?userID=randomID&UUID=vote-uuid-0&type=1")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-0"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-0"]);
if (row.votes === 3) { if (row.votes === 3) {
done(); done();
} else { } else {
@ -84,9 +84,9 @@ describe('voteOnSponsorTime', () => {
it('Should be able to downvote a segment', (done: Done) => { it('Should be able to downvote a segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=0") + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-2"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
if (row.votes < 10) { if (row.votes < 10) {
done(); done();
} else { } else {
@ -102,9 +102,9 @@ describe('voteOnSponsorTime', () => {
it('Should not be able to downvote the same segment when voting from a different user on the same IP', (done: Done) => { it('Should not be able to downvote the same segment when voting from a different user on the same IP', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID3&UUID=vote-uuid-2&type=0") + "/api/voteOnSponsorTime?userID=randomID3&UUID=vote-uuid-2&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-2"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]);
if (row.votes === 9) { if (row.votes === 9) {
done(); done();
} else { } else {
@ -120,9 +120,9 @@ describe('voteOnSponsorTime', () => {
it("Should not be able to downvote a segment if the user is shadow banned", (done: Done) => { it("Should not be able to downvote a segment if the user is shadow banned", (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID4&UUID=vote-uuid-1.6&type=0") + "/api/voteOnSponsorTime?userID=randomID4&UUID=vote-uuid-1.6&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-1.6"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.6"]);
if (row.votes === 10) { if (row.votes === 10) {
done(); done();
} else { } else {
@ -138,9 +138,9 @@ describe('voteOnSponsorTime', () => {
it("Should not be able to upvote a segment if the user hasn't submitted yet", (done: Done) => { it("Should not be able to upvote a segment if the user hasn't submitted yet", (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1&type=1") + "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1&type=1")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-1"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1"]);
if (row.votes === 2) { if (row.votes === 2) {
done(); done();
} else { } else {
@ -156,9 +156,9 @@ describe('voteOnSponsorTime', () => {
it("Should not be able to downvote a segment if the user hasn't submitted yet", (done: Done) => { it("Should not be able to downvote a segment if the user hasn't submitted yet", (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1.5&type=0") + "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1.5&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-1.5"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.5"]);
if (row.votes === 10) { if (row.votes === 10) {
done(); done();
} else { } else {
@ -174,9 +174,9 @@ describe('voteOnSponsorTime', () => {
it('VIP should be able to completely downvote a segment', (done: Done) => { it('VIP should be able to completely downvote a segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-3&type=0") + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-3&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-3"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-3"]);
if (row.votes <= -2) { if (row.votes <= -2) {
done(); done();
} else { } else {
@ -192,9 +192,9 @@ describe('voteOnSponsorTime', () => {
it('should be able to completely downvote your own segment', (done: Done) => { it('should be able to completely downvote your own segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=own-submission-id&UUID=own-submission-uuid&type=0") + "/api/voteOnSponsorTime?userID=own-submission-id&UUID=own-submission-uuid&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["own-submission-uuid"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["own-submission-uuid"]);
if (row.votes <= -2) { if (row.votes <= -2) {
done(); done();
} else { } else {
@ -210,9 +210,9 @@ describe('voteOnSponsorTime', () => {
it('should not be able to completely downvote somebody elses segment', (done: Done) => { it('should not be able to completely downvote somebody elses segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=not-own-submission-uuid&type=0") + "/api/voteOnSponsorTime?userID=randomID2&UUID=not-own-submission-uuid&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["not-own-submission-uuid"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["not-own-submission-uuid"]);
if (row.votes === 499) { if (row.votes === 499) {
done(); done();
} else { } else {
@ -228,10 +228,10 @@ describe('voteOnSponsorTime', () => {
it('Should be able to vote for a category and it should add your vote to the database', (done: Done) => { it('Should be able to vote for a category and it should add your vote to the database', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=intro") + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=intro")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-4"]); let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
let categoryRows = db.prepare('all', "SELECT votes, category FROM categoryVotes WHERE UUID = ?", ["vote-uuid-4"]); let categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
if (row.category === "sponsor" && categoryRows.length === 2 if (row.category === "sponsor" && categoryRows.length === 2
&& categoryRows[0]?.votes === 1 && categoryRows[0]?.category === "intro" && categoryRows[0]?.votes === 1 && categoryRows[0]?.category === "intro"
&& categoryRows[1]?.votes === 1 && categoryRows[1]?.category === "sponsor") { && categoryRows[1]?.votes === 1 && categoryRows[1]?.category === "sponsor") {
@ -249,9 +249,9 @@ describe('voteOnSponsorTime', () => {
it('Should not able to change to an invalid category', (done: Done) => { it('Should not able to change to an invalid category', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=fakecategory") + "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=fakecategory")
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
let row = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["incorrect-category"]); let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]);
if (row.category === "sponsor") { if (row.category === "sponsor") {
done(); done();
} else { } else {
@ -267,10 +267,10 @@ describe('voteOnSponsorTime', () => {
it('Should be able to change your vote for a category and it should add your vote to the database', (done: Done) => { it('Should be able to change your vote for a category and it should add your vote to the database', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=outro") + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=outro")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let submissionRow = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-4"]); let submissionRow = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
let categoryRows = db.prepare('all', "SELECT votes, category FROM categoryVotes WHERE UUID = ?", ["vote-uuid-4"]); let categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]);
let introVotes = 0; let introVotes = 0;
let outroVotes = 0; let outroVotes = 0;
let sponsorVotes = 0; let sponsorVotes = 0;
@ -298,8 +298,8 @@ describe('voteOnSponsorTime', () => {
const vote = (inputCat: string, assertCat: string, callback: Done) => { const vote = (inputCat: string, assertCat: string, callback: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category-change&category=" + inputCat) + "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category-change&category=" + inputCat)
.then(res => { .then(async res => {
let row = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["incorrect-category-change"]); let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category-change"]);
if (row.category === assertCat) { if (row.category === assertCat) {
callback(); callback();
} else { } else {
@ -317,10 +317,10 @@ describe('voteOnSponsorTime', () => {
it('VIP should be able to vote for a category and it should immediately change', (done: Done) => { it('VIP should be able to vote for a category and it should immediately change', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&category=outro") + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&category=outro")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-5"]); let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
let row2 = db.prepare('get', "SELECT votes FROM categoryVotes WHERE UUID = ? and category = ?", ["vote-uuid-5", "outro"]); let row2 = await db.prepare('get', `SELECT votes FROM "categoryVotes" WHERE "UUID" = ? and category = ?`, ["vote-uuid-5", "outro"]);
if (row.category === "outro" && row2.votes === 500) { if (row.category === "outro" && row2.votes === 500) {
done(); done();
} else { } else {
@ -336,9 +336,9 @@ describe('voteOnSponsorTime', () => {
it('Submitter should be able to vote for a category and it should immediately change', (done: Done) => { it('Submitter should be able to vote for a category and it should immediately change', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=testman&UUID=vote-uuid-5_1&category=outro") + "/api/voteOnSponsorTime?userID=testman&UUID=vote-uuid-5_1&category=outro")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT category FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-5"]); let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
if (row.category === "outro") { if (row.category === "outro") {
done(); done();
} else { } else {
@ -354,7 +354,7 @@ describe('voteOnSponsorTime', () => {
it('Should not be able to category-vote on an invalid UUID submission', (done: Done) => { it('Should not be able to category-vote on an invalid UUID submission', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID3&UUID=invalid-uuid&category=intro") + "/api/voteOnSponsorTime?userID=randomID3&UUID=invalid-uuid&category=intro")
.then(res => { .then(async res => {
if (res.status === 400) { if (res.status === 400) {
done(); done();
} else { } else {
@ -367,7 +367,7 @@ describe('voteOnSponsorTime', () => {
it('Non-VIP should not be able to upvote "dead" submission', (done: Done) => { it('Non-VIP should not be able to upvote "dead" submission', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1") + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1")
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -380,9 +380,9 @@ describe('voteOnSponsorTime', () => {
it('VIP should be able to upvote "dead" submission', (done: Done) => { it('VIP should be able to upvote "dead" submission', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&type=1") + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&type=1")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT votes FROM sponsorTimes WHERE UUID = ?", ["vote-uuid-5"]); let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]);
if (row.votes > -3) { if (row.votes > -3) {
done(); done();
} else { } else {
@ -398,7 +398,7 @@ describe('voteOnSponsorTime', () => {
it('Should not be able to upvote a segment (Too many warning)', (done: Done) => { it('Should not be able to upvote a segment (Too many warning)', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=warn-voteuser01&UUID=warnvote-uuid-0&type=1") + "/api/voteOnSponsorTime?userID=warn-voteuser01&UUID=warnvote-uuid-0&type=1")
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); // success done(); // success
} else { } else {
@ -411,7 +411,7 @@ describe('voteOnSponsorTime', () => {
it('Non-VIP should not be able to downvote on a segment with no-segments category', (done: Done) => { it('Non-VIP should not be able to downvote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=0") + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=0")
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -424,7 +424,7 @@ describe('voteOnSponsorTime', () => {
it('Non-VIP should be able to upvote on a segment with no-segments category', (done: Done) => { it('Non-VIP should be able to upvote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=1") + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&type=1")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
done(); done();
} else { } else {
@ -437,7 +437,7 @@ describe('voteOnSponsorTime', () => {
it('Non-VIP should not be able to category vote on a segment with no-segments category', (done: Done) => { it('Non-VIP should not be able to category vote on a segment with no-segments category', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&category=outro") + "/api/voteOnSponsorTime?userID=no-segments-voter&UUID=no-sponsor-segments-uuid-0&category=outro")
.then(res => { .then(async res => {
if (res.status === 403) { if (res.status === 403) {
done(); done();
} else { } else {
@ -450,9 +450,9 @@ describe('voteOnSponsorTime', () => {
it('VIP upvote should lock segment', (done: Done) => { it('VIP upvote should lock segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=1") + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=1")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT locked FROM sponsorTimes WHERE UUID = ?", ["segment-locking-uuid-1"]); let row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
if (row?.locked) { if (row?.locked) {
done(); done();
} else { } else {
@ -468,9 +468,9 @@ describe('voteOnSponsorTime', () => {
it('VIP downvote should unlock segment', (done: Done) => { it('VIP downvote should unlock segment', (done: Done) => {
fetch(getbaseURL() fetch(getbaseURL()
+ "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=0") + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=0")
.then(res => { .then(async res => {
if (res.status === 200) { if (res.status === 200) {
let row = db.prepare('get', "SELECT locked FROM sponsorTimes WHERE UUID = ?", ["segment-locking-uuid-1"]); let row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]);
if (!row?.locked) { if (!row?.locked) {
done(); done();
} else { } else {

View file

@ -10,44 +10,48 @@ import {ImportMock} from 'ts-mock-imports';
import * as rateLimitMiddlewareModule from '../src/middleware/requestRateLimit'; import * as rateLimitMiddlewareModule from '../src/middleware/requestRateLimit';
import rateLimit from 'express-rate-limit'; import rateLimit from 'express-rate-limit';
ImportMock.mockFunction(rateLimitMiddlewareModule, 'rateLimitMiddleware', rateLimit({ async function init() {
skip: () => { ImportMock.mockFunction(rateLimitMiddlewareModule, 'rateLimitMiddleware', rateLimit({
return true; skip: () => {
} return true;
})); }
}));
// delete old test database // delete old test database
if (fs.existsSync(config.db)) fs.unlinkSync(config.db) if (fs.existsSync(config.db)) fs.unlinkSync(config.db)
if (fs.existsSync(config.privateDB)) fs.unlinkSync(config.privateDB); if (fs.existsSync(config.privateDB)) fs.unlinkSync(config.privateDB);
initDb(); await initDb();
// Instantiate a Mocha instance. // Instantiate a Mocha instance.
const mocha = new Mocha(); const mocha = new Mocha();
const testDir = './test/cases'; const testDir = './test/cases';
// Add each .ts file to the mocha instance // Add each .ts file to the mocha instance
fs.readdirSync(testDir) fs.readdirSync(testDir)
.filter(function(file) { .filter(function(file) {
// Only keep the .ts files // Only keep the .ts files
return file.substr(-3) === '.ts'; return file.substr(-3) === '.ts';
}) })
.forEach(function(file) { .forEach(function(file) {
mocha.addFile( mocha.addFile(
path.join(testDir, file) path.join(testDir, file)
); );
}); });
const mockServer = createMockServer(() => { const mockServer = createMockServer(() => {
Logger.info("Started mock HTTP Server"); Logger.info("Started mock HTTP Server");
const server = createServer(() => { const server = createServer(() => {
Logger.info("Started main HTTP server"); Logger.info("Started main HTTP server");
// Run the tests. // Run the tests.
mocha.run((failures) => { mocha.run((failures) => {
mockServer.close(); mockServer.close();
server.close(); server.close();
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
}); });
}); });
}); }
init();