mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-11 05:57:04 +03:00
Treat duplicate full video submission as upvote
This commit is contained in:
@@ -9,17 +9,18 @@ import { getIP } from "../utils/getIP";
|
|||||||
import { getFormattedTime } from "../utils/getFormattedTime";
|
import { getFormattedTime } from "../utils/getFormattedTime";
|
||||||
import { dispatchEvent } from "../utils/webhookUtils";
|
import { dispatchEvent } from "../utils/webhookUtils";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { ActionType, Category, CategoryActionType, IncomingSegment, SegmentUUID, Service, VideoDuration, VideoID } from "../types/segments.model";
|
import { ActionType, Category, CategoryActionType, IncomingSegment, IPAddress, SegmentUUID, Service, VideoDuration, VideoID } from "../types/segments.model";
|
||||||
import { deleteLockCategories } from "./deleteLockCategories";
|
import { deleteLockCategories } from "./deleteLockCategories";
|
||||||
import { getCategoryActionType } from "../utils/categoryInfo";
|
import { getCategoryActionType } from "../utils/categoryInfo";
|
||||||
import { QueryCacher } from "../utils/queryCacher";
|
import { QueryCacher } from "../utils/queryCacher";
|
||||||
import { getReputation } from "../utils/reputation";
|
import { getReputation } from "../utils/reputation";
|
||||||
import { APIVideoData, APIVideoInfo } from "../types/youtubeApi.model";
|
import { APIVideoData, APIVideoInfo } from "../types/youtubeApi.model";
|
||||||
import { UserID } from "../types/user.model";
|
import { HashedUserID, UserID } from "../types/user.model";
|
||||||
import { isUserVIP } from "../utils/isUserVIP";
|
import { isUserVIP } from "../utils/isUserVIP";
|
||||||
import { parseUserAgent } from "../utils/userAgent";
|
import { parseUserAgent } from "../utils/userAgent";
|
||||||
import { getService } from "../utils/getService";
|
import { getService } from "../utils/getService";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { vote } from "./voteOnSponsorTime";
|
||||||
|
|
||||||
type CheckResult = {
|
type CheckResult = {
|
||||||
pass: boolean,
|
pass: boolean,
|
||||||
@@ -343,7 +344,7 @@ function checkInvalidFields(videoID: VideoID, userID: UserID, segments: Incoming
|
|||||||
return CHECK_PASS;
|
return CHECK_PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkEachSegmentValid(userID: string, videoID: VideoID,
|
async function checkEachSegmentValid(rawIP: IPAddress, paramUserID: UserID, userID: HashedUserID, videoID: VideoID,
|
||||||
segments: IncomingSegment[], service: string, isVIP: boolean, lockedCategoryList: Array<any>): Promise<CheckResult> {
|
segments: IncomingSegment[], service: string, isVIP: boolean, lockedCategoryList: Array<any>): Promise<CheckResult> {
|
||||||
|
|
||||||
for (let i = 0; i < segments.length; i++) {
|
for (let i = 0; i < segments.length; i++) {
|
||||||
@@ -399,14 +400,21 @@ async function checkEachSegmentValid(userID: string, videoID: VideoID,
|
|||||||
if (!isVIP && segments[i].category === "sponsor"
|
if (!isVIP && segments[i].category === "sponsor"
|
||||||
&& segments[i].actionType !== ActionType.Full && Math.abs(startTime - endTime) < 1) {
|
&& segments[i].actionType !== ActionType.Full && Math.abs(startTime - endTime) < 1) {
|
||||||
// Too short
|
// Too short
|
||||||
return { pass: false, errorMessage: "Sponsors must be longer than 1 second long", errorCode: 400 };
|
return { pass: false, errorMessage: "Segments must be longer than 1 second long", errorCode: 400 };
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if this info has already been submitted before
|
//check if this info has already been submitted before
|
||||||
const duplicateCheck2Row = await db.prepare("get", `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "startTime" = ?
|
const duplicateCheck2Row = await db.prepare("get", `SELECT "UUID" FROM "sponsorTimes" WHERE "startTime" = ?
|
||||||
and "endTime" = ? and "category" = ? and "actionType" = ? and "videoID" = ? and "service" = ?`, [startTime, endTime, segments[i].category, segments[i].actionType, videoID, service]);
|
and "endTime" = ? and "category" = ? and "actionType" = ? and "videoID" = ? and "service" = ?`, [startTime, endTime, segments[i].category, segments[i].actionType, videoID, service]);
|
||||||
if (duplicateCheck2Row.count > 0) {
|
if (duplicateCheck2Row) {
|
||||||
return { pass: false, errorMessage: "Sponsors has already been submitted before.", errorCode: 409 };
|
if (segments[i].actionType === ActionType.Full) {
|
||||||
|
// Forward as vote
|
||||||
|
vote(rawIP, duplicateCheck2Row.UUID, paramUserID, 1);
|
||||||
|
segments[i].ignoreSegment = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return { pass: false, errorMessage: "Segment has already been submitted before.", errorCode: 409 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,15 +584,15 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let { videoID, userID, service, videoDuration, videoDurationParam, segments, userAgent } = preprocessInput(req);
|
let { videoID, userID: paramUserID, service, videoDuration, videoDurationParam, segments, userAgent } = preprocessInput(req);
|
||||||
|
|
||||||
const invalidCheckResult = checkInvalidFields(videoID, userID, segments);
|
const invalidCheckResult = checkInvalidFields(videoID, paramUserID, segments);
|
||||||
if (!invalidCheckResult.pass) {
|
if (!invalidCheckResult.pass) {
|
||||||
return res.status(invalidCheckResult.errorCode).send(invalidCheckResult.errorMessage);
|
return res.status(invalidCheckResult.errorCode).send(invalidCheckResult.errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
//hash the userID
|
//hash the userID
|
||||||
userID = await getHashCache(userID);
|
const userID = await getHashCache(paramUserID);
|
||||||
|
|
||||||
const userWarningCheckResult = await checkUserActiveWarning(userID);
|
const userWarningCheckResult = await checkUserActiveWarning(userID);
|
||||||
if (!userWarningCheckResult.pass) {
|
if (!userWarningCheckResult.pass) {
|
||||||
@@ -592,15 +600,15 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
return res.status(userWarningCheckResult.errorCode).send(userWarningCheckResult.errorMessage);
|
return res.status(userWarningCheckResult.errorCode).send(userWarningCheckResult.errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if this user is on the vip list
|
|
||||||
const isVIP = await isUserVIP(userID);
|
const isVIP = await isUserVIP(userID);
|
||||||
|
const rawIP = getIP(req);
|
||||||
|
|
||||||
const newData = await updateDataIfVideoDurationChange(videoID, service, videoDuration, videoDurationParam);
|
const newData = await updateDataIfVideoDurationChange(videoID, service, videoDuration, videoDurationParam);
|
||||||
videoDuration = newData.videoDuration;
|
videoDuration = newData.videoDuration;
|
||||||
const { lockedCategoryList, apiVideoInfo } = newData;
|
const { lockedCategoryList, apiVideoInfo } = newData;
|
||||||
|
|
||||||
// Check if all submissions are correct
|
// Check if all submissions are correct
|
||||||
const segmentCheckResult = await checkEachSegmentValid(userID, videoID, segments, service, isVIP, lockedCategoryList);
|
const segmentCheckResult = await checkEachSegmentValid(rawIP, paramUserID, userID, videoID, segments, service, isVIP, lockedCategoryList);
|
||||||
if (!segmentCheckResult.pass) {
|
if (!segmentCheckResult.pass) {
|
||||||
return res.status(segmentCheckResult.errorCode).send(segmentCheckResult.errorMessage);
|
return res.status(segmentCheckResult.errorCode).send(segmentCheckResult.errorMessage);
|
||||||
}
|
}
|
||||||
@@ -619,7 +627,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
const newSegments = [];
|
const newSegments = [];
|
||||||
|
|
||||||
//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
|
||||||
const hashedIP = await getHashCache(getIP(req) + config.globalSalt);
|
const hashedIP = await getHashCache(rawIP + config.globalSalt);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//get current time
|
//get current time
|
||||||
@@ -636,6 +644,8 @@ export async function postSkipSegments(req: Request, res: Response): Promise<Res
|
|||||||
const reputation = await getReputation(userID);
|
const reputation = await getReputation(userID);
|
||||||
|
|
||||||
for (const segmentInfo of segments) {
|
for (const segmentInfo of segments) {
|
||||||
|
if (segmentInfo.ignoreSegment) continue;
|
||||||
|
|
||||||
//this can just be a hash of the data
|
//this can just be a hash of the data
|
||||||
//it's better than generating an actual UUID like what was used before
|
//it's better than generating an actual UUID like what was used before
|
||||||
//also better for duplication checking
|
//also better for duplication checking
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { getIP } from "../utils/getIP";
|
|||||||
import { getHashCache } from "../utils/getHashCache";
|
import { getHashCache } from "../utils/getHashCache";
|
||||||
import { config } from "../config";
|
import { config } from "../config";
|
||||||
import { HashedUserID, UserID } from "../types/user.model";
|
import { HashedUserID, UserID } from "../types/user.model";
|
||||||
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash, Visibility, VideoDuration } from "../types/segments.model";
|
import { Category, CategoryActionType, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash, Visibility, VideoDuration, ActionType } from "../types/segments.model";
|
||||||
import { getCategoryActionType } from "../utils/categoryInfo";
|
import { getCategoryActionType } from "../utils/categoryInfo";
|
||||||
import { QueryCacher } from "../utils/queryCacher";
|
import { QueryCacher } from "../utils/queryCacher";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -188,38 +188,38 @@ async function sendWebhooks(voteData: VoteData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, isOwnSubmission: boolean, category: Category
|
async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, isOwnSubmission: boolean, category: Category
|
||||||
, hashedIP: HashedIP, finalResponse: FinalResponse, res: Response): Promise<Response> {
|
, hashedIP: HashedIP, finalResponse: FinalResponse): Promise<{ status: number, message?: string }> {
|
||||||
// Check if they've already made a vote
|
// Check if they've already made a vote
|
||||||
const usersLastVoteInfo = await privateDB.prepare("get", `select count(*) as votes, category from "categoryVotes" where "UUID" = ? and "userID" = ? group by category`, [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
|
||||||
return res.sendStatus(finalResponse.finalStatus);
|
return { status: finalResponse.finalStatus };
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoInfo = (await db.prepare("get", `SELECT "category", "videoID", "hashedVideoID", "service", "userID", "locked" FROM "sponsorTimes" WHERE "UUID" = ?`,
|
const videoInfo = (await db.prepare("get", `SELECT "category", "videoID", "hashedVideoID", "service", "userID", "locked" FROM "sponsorTimes" WHERE "UUID" = ?`,
|
||||||
[UUID])) as {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID, locked: number};
|
[UUID])) as {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID, locked: number};
|
||||||
if (!videoInfo) {
|
if (!videoInfo) {
|
||||||
// Submission doesn't exist
|
// Submission doesn't exist
|
||||||
return res.status(400).send("Submission doesn't exist.");
|
return { status: 400, message: "Submission doesn't exist." };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.categoryList.includes(category)) {
|
if (!config.categoryList.includes(category)) {
|
||||||
return res.status(400).send("Category doesn't exist.");
|
return { status: 400, message: "Category doesn't exist." };
|
||||||
}
|
}
|
||||||
if (getCategoryActionType(category) !== CategoryActionType.Skippable) {
|
if (getCategoryActionType(category) !== CategoryActionType.Skippable) {
|
||||||
return res.status(400).send("Cannot vote for this category");
|
return { status: 400, message: "Cannot vote for this category" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore vote if the next category is locked
|
// Ignore vote if the next category is locked
|
||||||
const nextCategoryLocked = await db.prepare("get", `SELECT "videoID", "category" FROM "lockCategories" WHERE "videoID" = ? AND "service" = ? AND "category" = ?`, [videoInfo.videoID, videoInfo.service, category]);
|
const nextCategoryLocked = await db.prepare("get", `SELECT "videoID", "category" FROM "lockCategories" WHERE "videoID" = ? AND "service" = ? AND "category" = ?`, [videoInfo.videoID, videoInfo.service, category]);
|
||||||
if (nextCategoryLocked && !isVIP) {
|
if (nextCategoryLocked && !isVIP) {
|
||||||
return res.sendStatus(200);
|
return { status: 200 };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore vote if the segment is locked
|
// Ignore vote if the segment is locked
|
||||||
if (!isVIP && videoInfo.locked === 1) {
|
if (!isVIP && videoInfo.locked === 1) {
|
||||||
return res.sendStatus(200);
|
return { status: 200 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextCategoryInfo = await 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]);
|
||||||
@@ -279,7 +279,7 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i
|
|||||||
|
|
||||||
QueryCacher.clearSegmentCache(videoInfo);
|
QueryCacher.clearSegmentCache(videoInfo);
|
||||||
|
|
||||||
return res.sendStatus(finalResponse.finalStatus);
|
return { status: finalResponse.finalStatus };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserID(req: Request): UserID {
|
export function getUserID(req: Request): UserID {
|
||||||
@@ -289,16 +289,30 @@ export function getUserID(req: Request): UserID {
|
|||||||
export async function voteOnSponsorTime(req: Request, res: Response): Promise<Response> {
|
export async function voteOnSponsorTime(req: Request, res: Response): Promise<Response> {
|
||||||
const UUID = req.query.UUID as SegmentUUID;
|
const UUID = req.query.UUID as SegmentUUID;
|
||||||
const paramUserID = getUserID(req);
|
const paramUserID = getUserID(req);
|
||||||
let type = req.query.type !== undefined ? parseInt(req.query.type as string) : undefined;
|
const type = req.query.type !== undefined ? parseInt(req.query.type as string) : undefined;
|
||||||
const category = req.query.category as Category;
|
const category = req.query.category as Category;
|
||||||
|
const ip = getIP(req);
|
||||||
|
|
||||||
|
const result = await vote(ip, UUID, paramUserID, type, category);
|
||||||
|
|
||||||
|
const response = res.status(result.status);
|
||||||
|
if (result.message) {
|
||||||
|
return response.send(result.message);
|
||||||
|
} else if (result.json) {
|
||||||
|
return response.json(result.json);
|
||||||
|
} else {
|
||||||
|
return response.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID, type: number, category?: Category): Promise<{ status: number, message?: string, json?: unknown }> {
|
||||||
if (UUID === undefined || paramUserID === undefined || (type === undefined && category === undefined)) {
|
if (UUID === undefined || paramUserID === undefined || (type === undefined && category === undefined)) {
|
||||||
//invalid request
|
//invalid request
|
||||||
return res.sendStatus(400);
|
return { status: 400 };
|
||||||
}
|
}
|
||||||
if (paramUserID.length < 30 && config.mode !== "test") {
|
if (paramUserID.length < 30 && config.mode !== "test") {
|
||||||
// Ignore this vote, invalid
|
// Ignore this vote, invalid
|
||||||
return res.sendStatus(200);
|
return { status: 200 };
|
||||||
}
|
}
|
||||||
|
|
||||||
//hash the userID
|
//hash the userID
|
||||||
@@ -314,9 +328,6 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
webhookMessage: null
|
webhookMessage: null
|
||||||
};
|
};
|
||||||
|
|
||||||
//x-forwarded-for if this server is behind a proxy
|
|
||||||
const ip = getIP(req);
|
|
||||||
|
|
||||||
//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
|
||||||
const hashedIP: HashedIP = await getHashCache((ip + config.globalSalt) as IPAddress);
|
const hashedIP: HashedIP = await getHashCache((ip + config.globalSalt) as IPAddress);
|
||||||
|
|
||||||
@@ -331,7 +342,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
// disallow vote types 10/11
|
// disallow vote types 10/11
|
||||||
if (type === 10 || type === 11) {
|
if (type === 10 || type === 11) {
|
||||||
// no longer allow type 10/11 alternative votes
|
// no longer allow type 10/11 alternative votes
|
||||||
return res.sendStatus(400);
|
return { status: 400 };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not upvote
|
// If not upvote
|
||||||
@@ -350,19 +361,20 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === undefined && category !== undefined) {
|
if (type === undefined && category !== undefined) {
|
||||||
return categoryVote(UUID, nonAnonUserID, isVIP, isOwnSubmission, category, hashedIP, finalResponse, res);
|
return categoryVote(UUID, nonAnonUserID, isVIP, isOwnSubmission, category, hashedIP, finalResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type !== undefined && !isVIP && !isOwnSubmission) {
|
if (type !== undefined && !isVIP && !isOwnSubmission) {
|
||||||
// Check if upvoting hidden segment
|
// Check if upvoting hidden segment
|
||||||
const voteInfo = await db.prepare("get", `SELECT votes FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]);
|
const voteInfo = await db.prepare("get", `SELECT votes, "actionType" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID]) as
|
||||||
|
{ votes: number, actionType: ActionType };
|
||||||
|
|
||||||
if (voteInfo && voteInfo.votes <= -2) {
|
if (voteInfo && voteInfo.votes <= -2 && voteInfo.actionType !== ActionType.Full) {
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
return res.status(403).send("Not allowed to upvote segment with too many downvotes unless you are VIP.");
|
return { status: 403, message: "Not allowed to upvote segment with too many downvotes unless you are VIP." };
|
||||||
} else if (type == 0) {
|
} else if (type == 0) {
|
||||||
// Already downvoted enough, ignore
|
// Already downvoted enough, ignore
|
||||||
return res.sendStatus(200);
|
return { status: 200 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,9 +386,9 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
));
|
));
|
||||||
|
|
||||||
if (warnings.length >= config.maxNumberOfActiveWarnings) {
|
if (warnings.length >= 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. " +
|
return { status: 403, message: "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?" +
|
"Could you please send a message in Discord or Matrix so we can further help you?" +
|
||||||
`${(warnings[0]?.reason?.length > 0 ? ` Warning reason: '${warnings[0].reason}'` : "")}`);
|
`${(warnings[0]?.reason?.length > 0 ? ` Warning reason: '${warnings[0].reason}'` : "")}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
const voteTypeEnum = (type == 0 || type == 1 || type == 20) ? voteTypes.normal : voteTypes.incorrect;
|
const voteTypeEnum = (type == 0 || type == 1 || type == 20) ? voteTypes.normal : voteTypes.incorrect;
|
||||||
@@ -400,7 +412,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
incrementAmount = 0;
|
incrementAmount = 0;
|
||||||
} else {
|
} else {
|
||||||
//unrecongnised type of vote
|
//unrecongnised type of vote
|
||||||
return res.sendStatus(400);
|
return { status: 400 };
|
||||||
}
|
}
|
||||||
if (votesRow != undefined) {
|
if (votesRow != undefined) {
|
||||||
if (votesRow.type === 1) {
|
if (votesRow.type === 1) {
|
||||||
@@ -447,7 +459,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
|
|
||||||
// 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
|
||||||
|| (!(isOwnSubmission && incrementAmount > 0)
|
|| (!(isOwnSubmission && incrementAmount > 0 && oldIncrementAmount >= 0)
|
||||||
&& (await db.prepare("get", `SELECT "userID" FROM "sponsorTimes" WHERE "userID" = ?`, [nonAnonUserID])) !== undefined
|
&& (await db.prepare("get", `SELECT "userID" FROM "sponsorTimes" WHERE "userID" = ?`, [nonAnonUserID])) !== undefined
|
||||||
&& (await db.prepare("get", `SELECT "userID" FROM "shadowBannedUsers" WHERE "userID" = ?`, [nonAnonUserID])) === undefined
|
&& (await db.prepare("get", `SELECT "userID" FROM "shadowBannedUsers" WHERE "userID" = ?`, [nonAnonUserID])) === undefined
|
||||||
&& (await 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)
|
||||||
@@ -502,9 +514,9 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise<Re
|
|||||||
finalResponse
|
finalResponse
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return res.status(finalResponse.finalStatus).send(finalResponse.finalMessage ?? undefined);
|
return { status: finalResponse.finalStatus, message: finalResponse.finalMessage ?? undefined };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Logger.error(err as string);
|
Logger.error(err as string);
|
||||||
return res.status(500).json({ error: "Internal error creating segment vote" });
|
return { status: 500, message: finalResponse.finalMessage ?? undefined, json: { error: "Internal error creating segment vote" } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,9 @@ export interface IncomingSegment {
|
|||||||
actionType: ActionType;
|
actionType: ActionType;
|
||||||
segment: string[];
|
segment: string[];
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
// Used to remove in pre-check stage
|
||||||
|
ignoreSegment?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Segment {
|
export interface Segment {
|
||||||
|
|||||||
Reference in New Issue
Block a user