Add ratelimits

Fixes #10
master
Dessa Simpson 2021-06-06 23:11:30 -07:00
parent 6e26650077
commit 7897fe6f3d
5 changed files with 85 additions and 11 deletions

View File

@ -1,12 +1,14 @@
CREATE TABLE config ( CREATE TABLE config (
rowlock bool DEFAULT TRUE UNIQUE NOT NULL CHECK (rowlock = TRUE), rowlock bool DEFAULT TRUE UNIQUE NOT NULL CHECK (rowlock = TRUE),
normaluservotepoints int NOT NULL, normaluservotepoints int NOT NULL DEFAULT 10,
followervotepoints int NOT NULL, followervotepoints int NOT NULL DEFAULT 50,
subscribervotepoints int NOT NULL, subscribervotepoints int NOT NULL DEFAULT 100,
title varchar NOT NULL, normaluserratelimit int NOT NULL DEFAULT 1,
colors jsonb NOT NULL, followerratelimit int NOT NULL DEFAULT 2,
subscriberratelimit int NOT NULL DEFAULT 3,
title varchar NOT NULL DEFAULT '{username}''s Learn Request Queue',
colors jsonb NOT NULL DEFAULT '{"bg": {"primary": "#444444","table": "#282828","navbar": "#666666","error": "#ff0000"},"fg": {"primary": "#dddddd","ahover": "#ffffff","title": "#eeeeee"}}',
PRIMARY KEY (rowLock) PRIMARY KEY (rowLock)
); );
INSERT INTO config (normalUserVotePoints,followerVotePoints,subscriberVotePoints,title,colors) INSERT INTO config (rowlock) VALUES (true);
VALUES (10,50,100,'{username}''s Learn Request Queue','{"bg": {"primary": "#444444","table": "#282828","navbar": "#666666","error": "#ff0000"},"fg": {"primary": "#dddddd","ahover": "#ffffff","title": "#eeeeee"}}');

View File

@ -60,3 +60,22 @@ CREATE OR REPLACE VIEW streamer_user_vw AS
SELECT users.userid as userid, users.displayname as displayname, users.imageurl as imageurl FROM streamer SELECT users.userid as userid, users.displayname as displayname, users.imageurl as imageurl FROM streamer
LEFT JOIN users LEFT JOIN users
ON streamer.userid = users.userid; ON streamer.userid = users.userid;
CREATE OR REPLACE VIEW ratelimit_vw AS
SELECT users.userid,COALESCE(count,0),ratelimit.reqcount AS max,COALESCE(count,0) >= ratelimit.reqcount AS status
FROM users
LEFT JOIN (SELECT requester,COUNT(url)
FROM requests
WHERE reqtimestamp > (now() - '24 hours'::interval)
GROUP BY requests.requester
) AS requests ON users.userid = requests.requester
LEFT JOIN follows ON requests.requester = follows.userid
LEFT JOIN subscriptions ON requests.requester = subscriptions.userid
CROSS JOIN config
CROSS JOIN LATERAL (VALUES (
CASE
WHEN follows.userid IS NULL AND subscriptions.userid IS NULL THEN config.normaluserratelimit
WHEN follows.userid IS NOT NULL AND subscriptions.userid IS NULL THEN config.followerratelimit
WHEN subscriptions.userid IS NOT NULL THEN config.subscriberratelimit
END
)) AS ratelimit(reqcount);

34
db/upgrade/v0.7-v0.8.sql Normal file
View File

@ -0,0 +1,34 @@
BEGIN;
ALTER TABLE config
ALTER COLUMN normaluservotepoints SET DEFAULT 10,
ALTER COLUMN followervotepoints SET DEFAULT 50,
ALTER COLUMN subscribervotepoints SET DEFAULT 100,
ALTER COLUMN title SET DEFAULT '{username}''s Learn Request Queue',
ALTER COLUMN colors SET DEFAULT '{"bg": {"primary": "#444444","table": "#282828","navbar": "#666666","error": "#ff0000"},"fg": {"primary": "#dddddd","ahover": "#ffffff","title": "#eeeeee"}}',
ADD COLUMN normaluserratelimit int NOT NULL DEFAULT 1,
ADD COLUMN followerratelimit int NOT NULL DEFAULT 2,
ADD COLUMN subscriberratelimit int NOT NULL DEFAULT 3;
CREATE OR REPLACE VIEW ratelimit_vw AS
SELECT users.userid,COALESCE(count,0),ratelimit.reqcount AS max,COALESCE(count,0) >= ratelimit.reqcount AS status
FROM users
LEFT JOIN (SELECT requester,COUNT(url)
FROM requests
WHERE reqtimestamp > (now() - '24 hours'::interval)
GROUP BY requests.requester
) AS requests ON users.userid = requests.requester
LEFT JOIN follows ON requests.requester = follows.userid
LEFT JOIN subscriptions ON requests.requester = subscriptions.userid
CROSS JOIN config
CROSS JOIN LATERAL (VALUES (
CASE
WHEN follows.userid IS NULL AND subscriptions.userid IS NULL THEN config.normaluserratelimit
WHEN follows.userid IS NOT NULL AND subscriptions.userid IS NULL THEN config.followerratelimit
WHEN subscriptions.userid IS NOT NULL THEN config.subscriberratelimit
END
)) AS ratelimit(reqcount);
ROLLBACK;
--COMMIT;

View File

@ -130,3 +130,8 @@ export const updateCronJobLastSuccess = {
name: "updateCronJobLastSuccess", name: "updateCronJobLastSuccess",
text: "UPDATE cron SET lastSuccess = now() WHERE jobName = $1" text: "UPDATE cron SET lastSuccess = now() WHERE jobName = $1"
} }
export const getRateLimitStatus = {
name: "getRateLimitStatus",
text: "SELECT * FROM ratelimit_vw WHERE userid = $1"
}

View File

@ -87,6 +87,7 @@ async function retrieveYoutubeMetadata(url: string) {
} }
export async function addRequest(url: string, requester: string): Promise<[number,string]> { export async function addRequest(url: string, requester: string): Promise<[number,string]> {
// Check that URL is of an accepted format
var validUrl = false; var validUrl = false;
for (var regex of validUrlRegexes) { for (var regex of validUrlRegexes) {
if (regex.test(url)) { if (regex.test(url)) {
@ -95,11 +96,24 @@ export async function addRequest(url: string, requester: string): Promise<[numbe
} }
} }
if (!validUrl) return [400, "Invalid song URL."]; if (!validUrl) return [400, "Invalid song URL."];
var result = await checkRequestExists(url)
if (result) { // Check whether the URL has already been requested
console.log(result); var existsResult = await checkRequestExists(url)
return [200,`Song already requested by ${result.rows[0].requester}. State: ${result.rows[0].state}`] if (existsResult) {
console.log(existsResult);
return [200,`Song already requested by ${existsResult.rows[0].requester}. State: ${existsResult.rows[0].state}`]
} }
// Check whether the user has hit their rate limit
var rateLimitQuery = Object.assign(queries.getRateLimitStatus, { values: [requester] });
var rateLimitResult = (await db.query(rateLimitQuery)).rows[0];
if (rateLimitResult.status) {
return [429,`You have reached your maximum of ${rateLimitResult.max} requests per day.
Please try again later.\n
Tip: Removing one of your requests from the past 24 hours by retracting your vote will allow you to replace it with another.`];
}
// Add the request
var query = Object.assign(queries.addRequest, { values: [url,requester] }); var query = Object.assign(queries.addRequest, { values: [url,requester] });
return db.query(query) return db.query(query)
.then(async () => { .then(async () => {