Added schema upgrade system and started on new vote type

This commit is contained in:
Ajay Ramachandran 2020-04-27 23:01:51 -04:00
parent 74169e6caf
commit d767f2ff6b
9 changed files with 216 additions and 172 deletions

View file

@ -7,10 +7,12 @@
"youtubeAPIKey": null, //get this from Google Cloud Platform [optional] "youtubeAPIKey": null, //get this from Google Cloud Platform [optional]
"discordReportChannelWebhookURL": null, //URL from discord if you would like notifications when someone makes a report [optional] "discordReportChannelWebhookURL": null, //URL from discord if you would like notifications when someone makes a report [optional]
"discordFirstTimeSubmissionsWebhookURL": null, //URL from discord if you would like notifications when someone makes a first time submission [optional] "discordFirstTimeSubmissionsWebhookURL": null, //URL from discord if you would like notifications when someone makes a first time submission [optional]
"discordCompletelyIncorrectReportWebhookURL": null, //URL from discord if you would like notifications when someone reports a submission as completely incorrect [optional]
"behindProxy": true, "behindProxy": true,
"db": "./databases/sponsorTimes.db", "db": "./databases/sponsorTimes.db",
"privateDB": "./databases/private.db", "privateDB": "./databases/private.db",
"createDatabaseIfNotExist": true, //This will run on startup every time (unless readOnly is true) - so ensure "create table if not exists" is used in the schema "createDatabaseIfNotExist": true, //This will run on startup every time (unless readOnly is true) - so ensure "create table if not exists" is used in the schema
"schemaFolder": "./databases",
"dbSchema": "./databases/_sponsorTimes.db.sql", "dbSchema": "./databases/_sponsorTimes.db.sql",
"privateDBSchema": "./databases/_private.db.sql", "privateDBSchema": "./databases/_private.db.sql",
"mode": "development", "mode": "development",

View file

@ -18,6 +18,11 @@ CREATE TABLE IF NOT EXISTS "userNames" (
"userID" TEXT NOT NULL, "userID" TEXT NOT NULL,
"userName" TEXT NOT NULL "userName" TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS "version" (
"code" INTEGER NOT NULL default '0'
);
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);
COMMIT; COMMIT;

25
databases/_upgrade_0.sql Normal file
View file

@ -0,0 +1,25 @@
BEGIN TRANSACTION;
/* Add incorrectVotes field */
CREATE TABLE "sqlb_temp_table_1" (
"videoID" TEXT NOT NULL,
"startTime" REAL NOT NULL,
"endTime" REAL NOT NULL,
"votes" INTEGER NOT NULL,
"incorrectVotes" INTEGER NOT NULL default '1',
"UUID" TEXT NOT NULL UNIQUE,
"userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL,
"category" TEXT NOT NULL DEFAULT "sponsor",
"shadowHidden" INTEGER NOT NULL
);
INSERT INTO sqlb_temp_table_1 SELECT videoID,startTime,endTime,votes,"1",UUID,userID,timeSubmitted,views,category,shadowHidden FROM sponsorTimes;
DROP TABLE sponsorTimes;
ALTER TABLE sqlb_temp_table_1 RENAME TO "sponsorTimes";
/* Increase version number */
INSERT INTO version VALUES(1);
COMMIT;

View file

@ -15,6 +15,13 @@ if (config.createDatabaseIfNotExist && !config.readOnly) {
if (fs.existsSync(config.privateDBSchema)) privateDB.exec(fs.readFileSync(config.privateDBSchema).toString()); if (fs.existsSync(config.privateDBSchema)) privateDB.exec(fs.readFileSync(config.privateDBSchema).toString());
} }
// Upgrade database if required
let versionCode = db.prepare("SELECT code FROM version").get() || 0;
let path = config.schemaFolder + "/_upgrade_" + versionCode + ".sql";
if (fs.existsSync(path)) {
db.exec(fs.readFileSync(path).toString());
}
// Enable WAL mode checkpoint number // Enable WAL mode checkpoint number
if (!config.readOnly && config.mode === "production") { if (!config.readOnly && config.mode === "production") {
db.exec("PRAGMA journal_mode=WAL;"); db.exec("PRAGMA journal_mode=WAL;");

View file

@ -11,6 +11,11 @@ var privateDB = databases.privateDB;
var YouTubeAPI = require('../utils/youtubeAPI.js'); var YouTubeAPI = require('../utils/youtubeAPI.js');
var request = require('request'); var request = require('request');
function completelyIncorrectVote(req, res, params) {
}
module.exports = async function voteOnSponsorTime(req, res) { module.exports = async function voteOnSponsorTime(req, res) {
let UUID = req.query.UUID; let UUID = req.query.UUID;
let userID = req.query.userID; let userID = req.query.userID;
@ -32,6 +37,13 @@ module.exports = async function voteOnSponsorTime(req, res) {
//hash the ip 5000 times so no one can get it from the database //hash the ip 5000 times so no one can get it from the database
let hashedIP = getHash(ip + config.globalSalt); let hashedIP = getHash(ip + config.globalSalt);
let voteTypes = {
normal: 0,
incorrect: 1
}
let voteTypeEnum = (type == 0 || type == 1) ? voteTypes.normal : voteTypes.incorrect;
try { try {
//check if vote has already happened //check if vote has already happened
let votesRow = privateDB.prepare("SELECT type FROM votes WHERE userID = ? AND UUID = ?").get(userID, UUID); let votesRow = privateDB.prepare("SELECT type FROM votes WHERE userID = ? AND UUID = ?").get(userID, UUID);
@ -40,10 +52,10 @@ module.exports = async function voteOnSponsorTime(req, res) {
let incrementAmount = 0; let incrementAmount = 0;
let oldIncrementAmount = 0; let oldIncrementAmount = 0;
if (type == 1) { if (type == 1 || type == 11) {
//upvote //upvote
incrementAmount = 1; incrementAmount = 1;
} else if (type == 0) { } else if (type == 0 || type == 10) {
//downvote //downvote
incrementAmount = -1; incrementAmount = -1;
} else { } else {
@ -52,10 +64,10 @@ module.exports = async function voteOnSponsorTime(req, res) {
return; return;
} }
if (votesRow != undefined) { if (votesRow != undefined) {
if (votesRow.type == 1) { if (votesRow.type == 1 || type == 11) {
//upvote //upvote
oldIncrementAmount = 1; oldIncrementAmount = 1;
} else if (votesRow.type == 0) { } else if (votesRow.type == 0 || type == 10) {
//downvote //downvote
oldIncrementAmount = -1; oldIncrementAmount = -1;
} else if (votesRow.type == 2) { } else if (votesRow.type == 2) {
@ -64,6 +76,12 @@ module.exports = async function voteOnSponsorTime(req, res) {
} else if (votesRow.type < 0) { } else if (votesRow.type < 0) {
//vip downvote //vip downvote
oldIncrementAmount = votesRow.type; oldIncrementAmount = votesRow.type;
} else if (votesRow.type == 12) {
// VIP downvote for completely incorrect
oldIncrementAmount = -500;
} else if (votesRow.type == 13) {
// VIP upvote for completely incorrect
oldIncrementAmount = 500;
} }
} }
@ -73,6 +91,7 @@ module.exports = async function voteOnSponsorTime(req, res) {
//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)
let row = db.prepare("SELECT votes, views FROM sponsorTimes WHERE UUID = ?").get(UUID); let row = db.prepare("SELECT votes, views FROM sponsorTimes WHERE UUID = ?").get(UUID);
if (voteTypeEnum == voteTypes.normal) {
if (vipRow.userCount != 0 && incrementAmount < 0) { if (vipRow.userCount != 0 && incrementAmount < 0) {
//this user is a vip and a downvote //this user is a vip and a downvote
incrementAmount = - (row.votes + 2 - oldIncrementAmount); incrementAmount = - (row.votes + 2 - oldIncrementAmount);
@ -82,15 +101,29 @@ module.exports = async function voteOnSponsorTime(req, res) {
incrementAmount = -Math.abs(Math.min(10, row.votes + 2 - oldIncrementAmount)); incrementAmount = -Math.abs(Math.min(10, row.votes + 2 - oldIncrementAmount));
type = incrementAmount; type = incrementAmount;
} }
} else if (voteTypeEnum == voteTypes.incorrect) {
if (vipRow.userCount != 0) {
//this user is a vip and a downvote
incrementAmount = 500 * incrementAmount;
type = incrementAmount < 0 ? 12 : 13;
}
}
// Send discord message // Send discord message
if (type != 1) { if (incrementAmount < 0) {
// Get video ID // Get video ID
let submissionInfoRow = db.prepare("SELECT videoID, userID, startTime, endTime FROM sponsorTimes WHERE UUID = ?").get(UUID); let submissionInfoRow = db.prepare("SELECT videoID, userID, startTime, endTime FROM sponsorTimes WHERE UUID = ?").get(UUID);
let userSubmissionCountRow = db.prepare("SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?").get(nonAnonUserID); let userSubmissionCountRow = db.prepare("SELECT count(*) as submissionCount FROM sponsorTimes WHERE userID = ?").get(nonAnonUserID);
if (config.youtubeAPIKey !== null && config.discordReportChannelWebhookURL !== null) { let webhookURL = null;
if (voteTypeEnum === voteTypes.normal) {
webhookURL = config.discordReportChannelWebhookURL;
} else if (voteTypeEnum === voteTypes.incorrect) {
webhookURL = config.discordCompletelyIncorrectReportWebhookURL;
}
if (config.youtubeAPIKey !== null && webhookURL !== null) {
YouTubeAPI.videos.list({ YouTubeAPI.videos.list({
part: "snippet", part: "snippet",
id: submissionInfoRow.videoID id: submissionInfoRow.videoID
@ -100,7 +133,7 @@ module.exports = async function voteOnSponsorTime(req, res) {
return; return;
} }
request.post(config.discordReportChannelWebhookURL, { request.post(webhookURL, {
json: { json: {
"embeds": [{ "embeds": [{
"title": data.items[0].snippet.title, "title": data.items[0].snippet.title,
@ -141,9 +174,16 @@ module.exports = async function voteOnSponsorTime(req, res) {
privateDB.prepare("INSERT INTO votes VALUES(?, ?, ?, ?)").run(UUID, userID, hashedIP, type); privateDB.prepare("INSERT INTO votes VALUES(?, ?, ?, ?)").run(UUID, userID, hashedIP, type);
} }
let tableName = "";
if (voteTypeEnum === voteTypes.normal) {
tableName = "votes";
} else if (voteTypeEnum === voteTypes.incorrect) {
tableName = "incorrectVotes";
}
//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("UPDATE sponsorTimes SET votes = votes + ? WHERE UUID = ?").run(incrementAmount - oldIncrementAmount, UUID); db.prepare("UPDATE sponsorTimes SET " + tableName + " += ? WHERE UUID = ?").run(incrementAmount - oldIncrementAmount, UUID);
//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) { if (incrementAmount > 0) {

View file

@ -6,12 +6,14 @@
"youtubeAPIKey": "", "youtubeAPIKey": "",
"discordReportChannelWebhookURL": "http://127.0.0.1:8081/ReportChannelWebhook", "discordReportChannelWebhookURL": "http://127.0.0.1:8081/ReportChannelWebhook",
"discordFirstTimeSubmissionsWebhookURL": "http://127.0.0.1:8081/FirstTimeSubmissionsWebhook", "discordFirstTimeSubmissionsWebhookURL": "http://127.0.0.1:8081/FirstTimeSubmissionsWebhook",
"discordCompletelyIncorrectReportWebhookURL": "http://127.0.0.1:8081/CompletelyIncorrectReportWebhook",
"behindProxy": true, "behindProxy": true,
"db": "./test/databases/sponsorTimes.db", "db": "./test/databases/sponsorTimes.db",
"privateDB": "./test/databases/private.db", "privateDB": "./test/databases/private.db",
"createDatabaseIfNotExist": true, "createDatabaseIfNotExist": true,
"dbSchema": "./test/databases/_sponsorTimes.db.sql", "schemaFolder": "./databases",
"privateDBSchema": "./test/databases/_private.db.sql", "dbSchema": "./databases/_sponsorTimes.db.sql",
"privateDBSchema": "./databases/_private.db.sql",
"mode": "test", "mode": "test",
"readOnly": false "readOnly": false
} }

View file

@ -1,18 +0,0 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "shadowBannedUsers" (
"userID" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "votes" (
"UUID" TEXT NOT NULL,
"userID" INTEGER NOT NULL,
"hashedIP" INTEGER NOT NULL,
"type" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"hashedIP" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS sponsorTimes_hashedIP on sponsorTimes(hashedIP);
CREATE INDEX IF NOT EXISTS votes_userID on votes(UUID);
COMMIT;

View file

@ -1,23 +0,0 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "vipUsers" (
"userID" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"startTime" REAL NOT NULL,
"endTime" REAL NOT NULL,
"votes" INTEGER NOT NULL,
"UUID" TEXT NOT NULL UNIQUE,
"userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL,
"category" TEXT NOT NULL,
"shadowHidden" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "userNames" (
"userID" TEXT NOT NULL,
"userName" TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS sponsorTimes_videoID on sponsorTimes(videoID);
CREATE INDEX IF NOT EXISTS sponsorTimes_UUID on sponsorTimes(UUID);
COMMIT;

View file

@ -11,6 +11,10 @@ app.post('/FirstTimeSubmissionsWebhook', (req, res) => {
res.sendStatus(200); res.sendStatus(200);
}); });
app.post('/CompletelyIncorrectReportWebhook', (req, res) => {
res.sendStatus(200);
});
module.exports = function createMockServer(callback) { module.exports = function createMockServer(callback) {
return app.listen(config.mockPort, callback); return app.listen(config.mockPort, callback);
} }