mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-06 19:47:00 +03:00
use shared parseParams helper
This commit is contained in:
@@ -3,17 +3,12 @@ import { Logger } from "../utils/logger";
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { ActionType, Category, VideoID } from "../types/segments.model";
|
import { ActionType, Category, VideoID } from "../types/segments.model";
|
||||||
import { getService } from "../utils/getService";
|
import { getService } from "../utils/getService";
|
||||||
|
import { parseActionTypes } from "../utils/parseParams";
|
||||||
|
|
||||||
export async function getLockCategories(req: Request, res: Response): Promise<Response> {
|
export async function getLockCategories(req: Request, res: Response): Promise<Response> {
|
||||||
const videoID = req.query.videoID as VideoID;
|
const videoID = req.query.videoID as VideoID;
|
||||||
const service = getService(req.query.service as string);
|
const service = getService(req.query.service as string);
|
||||||
const actionTypes: ActionType[] = req.query.actionTypes
|
const actionTypes: ActionType[] = parseActionTypes(req, [ActionType.Skip, ActionType.Mute]);
|
||||||
? JSON.parse(req.query.actionTypes as string)
|
|
||||||
: req.query.actionType
|
|
||||||
? Array.isArray(req.query.actionType)
|
|
||||||
? req.query.actionType
|
|
||||||
: [req.query.actionType]
|
|
||||||
: [ActionType.Skip, ActionType.Mute];
|
|
||||||
if (!videoID || !Array.isArray(actionTypes)) {
|
if (!videoID || !Array.isArray(actionTypes)) {
|
||||||
//invalid request
|
//invalid request
|
||||||
return res.sendStatus(400);
|
return res.sendStatus(400);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Logger } from "../utils/logger";
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { hashPrefixTester } from "../utils/hashPrefixTester";
|
import { hashPrefixTester } from "../utils/hashPrefixTester";
|
||||||
import { ActionType, Category, VideoID, VideoIDHash } from "../types/segments.model";
|
import { ActionType, Category, VideoID, VideoIDHash } from "../types/segments.model";
|
||||||
|
import { parseActionTypes } from "../utils/parseParams";
|
||||||
|
|
||||||
interface LockResultByHash {
|
interface LockResultByHash {
|
||||||
videoID: VideoID,
|
videoID: VideoID,
|
||||||
@@ -44,25 +45,13 @@ const mergeLocks = (source: DBLock[], actionTypes: ActionType[]): LockResultByHa
|
|||||||
|
|
||||||
export async function getLockCategoriesByHash(req: Request, res: Response): Promise<Response> {
|
export async function getLockCategoriesByHash(req: Request, res: Response): Promise<Response> {
|
||||||
let hashPrefix = req.params.prefix as VideoIDHash;
|
let hashPrefix = req.params.prefix as VideoIDHash;
|
||||||
let actionTypes: ActionType[] = [];
|
const actionTypes: ActionType[] = parseActionTypes(req, [ActionType.Skip, ActionType.Mute]);
|
||||||
try {
|
if (!Array.isArray(actionTypes)) {
|
||||||
actionTypes = req.query.actionTypes
|
|
||||||
? JSON.parse(req.query.actionTypes as string)
|
|
||||||
: req.query.actionType
|
|
||||||
? Array.isArray(req.query.actionType)
|
|
||||||
? req.query.actionType
|
|
||||||
: [req.query.actionType]
|
|
||||||
: [ActionType.Skip, ActionType.Mute];
|
|
||||||
if (!Array.isArray(actionTypes)) {
|
|
||||||
//invalid request
|
|
||||||
return res.sendStatus(400);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
//invalid request
|
//invalid request
|
||||||
return res.status(400).send("Invalid request: JSON parse error (actionTypes)");
|
return res.sendStatus(400);
|
||||||
}
|
}
|
||||||
if (!hashPrefixTester(req.params.prefix)) {
|
|
||||||
|
|
||||||
|
if (!hashPrefixTester(req.params.prefix)) {
|
||||||
return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix
|
return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix
|
||||||
}
|
}
|
||||||
hashPrefix = hashPrefix.toLowerCase() as VideoIDHash;
|
hashPrefix = hashPrefix.toLowerCase() as VideoIDHash;
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import { db } from "../databases/databases";
|
|||||||
import { Logger } from "../utils/logger";
|
import { Logger } from "../utils/logger";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { Category, VideoID, ActionType } from "../types/segments.model";
|
import { Category, VideoID, ActionType } from "../types/segments.model";
|
||||||
import { config } from "../config";
|
import { filterInvalidCategoryActionType, parseActionTypes, parseCategories } from "../utils/parseParams";
|
||||||
|
|
||||||
const categorySupportList = config.categorySupport;
|
|
||||||
interface lockArray {
|
interface lockArray {
|
||||||
category: Category;
|
category: Category;
|
||||||
locked: number,
|
locked: number,
|
||||||
@@ -13,62 +12,19 @@ interface lockArray {
|
|||||||
userName: string,
|
userName: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterActionType = (actionTypes: ActionType[]) => {
|
|
||||||
const filterCategories = new Set();
|
|
||||||
for (const [key, value] of Object.entries(categorySupportList)) {
|
|
||||||
for (const type of actionTypes) {
|
|
||||||
if (value.includes(type)) {
|
|
||||||
filterCategories.add(key as Category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [...filterCategories];
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function getLockReason(req: Request, res: Response): Promise<Response> {
|
export async function getLockReason(req: Request, res: Response): Promise<Response> {
|
||||||
const videoID = req.query.videoID as VideoID;
|
const videoID = req.query.videoID as VideoID;
|
||||||
if (!videoID) {
|
const actionTypes = parseActionTypes(req, [ActionType.Skip, ActionType.Mute]);
|
||||||
// invalid request
|
const categories = parseCategories(req, []);
|
||||||
return res.status(400).send("No videoID provided");
|
|
||||||
}
|
|
||||||
let categories: Category[] = [];
|
|
||||||
let actionTypes: ActionType[] = [];
|
|
||||||
try {
|
|
||||||
actionTypes = req.query.actionTypes
|
|
||||||
? JSON.parse(req.query.actionTypes as string)
|
|
||||||
: req.query.actionType
|
|
||||||
? Array.isArray(req.query.actionType)
|
|
||||||
? req.query.actionType
|
|
||||||
: [req.query.actionType]
|
|
||||||
: [ActionType.Skip, ActionType.Mute];
|
|
||||||
if (!Array.isArray(actionTypes)) {
|
|
||||||
//invalid request
|
|
||||||
return res.status(400).send("actionTypes parameter does not match format requirements");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return res.status(400).send("Bad parameter: actionTypes (invalid JSON)");
|
|
||||||
}
|
|
||||||
const possibleCategories = filterActionType(actionTypes);
|
|
||||||
|
|
||||||
try {
|
// invalid requests
|
||||||
categories = req.query.categories
|
const errors = [];
|
||||||
? JSON.parse(req.query.categories as string)
|
if (!videoID) errors.push("No videoID provided");
|
||||||
: req.query.category
|
if (!Array.isArray(actionTypes)) errors.push("actionTypes parameter does not match format requirements");
|
||||||
? Array.isArray(req.query.category)
|
if (!Array.isArray(categories)) errors.push("Categories parameter does not match format requirements.");
|
||||||
? req.query.category
|
if (errors.length) return res.status(400).send(errors.join(", "));
|
||||||
: [req.query.category]
|
|
||||||
: []; // default to empty, will be set to all
|
|
||||||
if (!Array.isArray(categories)) {
|
|
||||||
return res.status(400).send("Categories parameter does not match format requirements.");
|
|
||||||
}
|
|
||||||
} catch(error) {
|
|
||||||
return res.status(400).send("Bad parameter: categories (invalid JSON)");
|
|
||||||
}
|
|
||||||
// only take valid categories
|
// only take valid categories
|
||||||
const searchCategories = (categories.length === 0 )
|
const searchCategories = filterInvalidCategoryActionType(categories, actionTypes);
|
||||||
? possibleCategories
|
|
||||||
: categories.filter(x =>
|
|
||||||
possibleCategories.includes(x));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get existing lock categories markers
|
// Get existing lock categories markers
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Request, Response } from "express";
|
|||||||
import { db } from "../databases/databases";
|
import { db } from "../databases/databases";
|
||||||
import { ActionType, Category, DBSegment, Service, VideoID, SortableFields } from "../types/segments.model";
|
import { ActionType, Category, DBSegment, Service, VideoID, SortableFields } from "../types/segments.model";
|
||||||
import { getService } from "../utils/getService";
|
import { getService } from "../utils/getService";
|
||||||
|
import { parseActionTypes, parseCategories } from "../utils/parseParams";
|
||||||
|
|
||||||
const maxSegmentsPerPage = 100;
|
const maxSegmentsPerPage = 100;
|
||||||
const defaultSegmentsPerPage = 10;
|
const defaultSegmentsPerPage = 10;
|
||||||
|
|
||||||
@@ -73,25 +75,15 @@ async function handleGetSegments(req: Request, res: Response): Promise<searchSeg
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Default to sponsor
|
// Default to sponsor
|
||||||
const categories: Category[] = req.query.categories
|
const categories: Category[] = parseCategories(req, []);
|
||||||
? JSON.parse(req.query.categories as string)
|
console.log(categories)
|
||||||
: req.query.category
|
|
||||||
? Array.isArray(req.query.category)
|
|
||||||
? req.query.category
|
|
||||||
: [req.query.category]
|
|
||||||
: [];
|
|
||||||
if (!Array.isArray(categories)) {
|
if (!Array.isArray(categories)) {
|
||||||
res.status(400).send("Categories parameter does not match format requirements.");
|
res.status(400).send("Categories parameter does not match format requirements.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionTypes: ActionType[] = req.query.actionTypes
|
const actionTypes: ActionType[] = parseActionTypes(req, [ActionType.Skip]);
|
||||||
? JSON.parse(req.query.actionTypes as string)
|
console.log(actionTypes)
|
||||||
: req.query.actionType
|
|
||||||
? Array.isArray(req.query.actionType)
|
|
||||||
? req.query.actionType
|
|
||||||
: [req.query.actionType]
|
|
||||||
: [ActionType.Skip];
|
|
||||||
if (!Array.isArray(actionTypes)) {
|
if (!Array.isArray(actionTypes)) {
|
||||||
res.status(400).send("actionTypes parameter does not match format requirements.");
|
res.status(400).send("actionTypes parameter does not match format requirements.");
|
||||||
return false;
|
return false;
|
||||||
@@ -184,6 +176,7 @@ async function endpoint(req: Request, res: Response): Promise<Response> {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
console.log(err)
|
||||||
if (err instanceof SyntaxError) {
|
if (err instanceof SyntaxError) {
|
||||||
return res.status(400).send("Invalid array in parameters");
|
return res.status(400).send("Invalid array in parameters");
|
||||||
} else return res.sendStatus(500);
|
} else return res.sendStatus(500);
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ import { Category, Service, VideoID, VideoIDHash } from "../types/segments.model
|
|||||||
import { UserID } from "../types/user.model";
|
import { UserID } from "../types/user.model";
|
||||||
import { QueryCacher } from "../utils/queryCacher";
|
import { QueryCacher } from "../utils/queryCacher";
|
||||||
import { isUserVIP } from "../utils/isUserVIP";
|
import { isUserVIP } from "../utils/isUserVIP";
|
||||||
|
import { parseCategories } from "../utils/parseParams";
|
||||||
|
|
||||||
export async function shadowBanUser(req: Request, res: Response): Promise<Response> {
|
export async function shadowBanUser(req: Request, res: Response): Promise<Response> {
|
||||||
const userID = req.query.userID as UserID;
|
const userID = req.query.userID as UserID;
|
||||||
const hashedIP = req.query.hashedIP as string;
|
const hashedIP = req.query.hashedIP as string;
|
||||||
const adminUserIDInput = req.query.adminUserID as UserID;
|
const adminUserIDInput = req.query.adminUserID as UserID;
|
||||||
|
const type = req.query.type as string ?? "1";
|
||||||
|
|
||||||
const enabled = req.query.enabled === undefined
|
const enabled = req.query.enabled === undefined
|
||||||
? true
|
? true
|
||||||
@@ -19,10 +21,9 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
//if enabled is false and the old submissions should be made visible again
|
//if enabled is false and the old submissions should be made visible again
|
||||||
const unHideOldSubmissions = req.query.unHideOldSubmissions !== "false";
|
const unHideOldSubmissions = req.query.unHideOldSubmissions !== "false";
|
||||||
|
|
||||||
const categories: string[] = req.query.categories ? JSON.parse(req.query.categories as string) : config.categoryList;
|
const categories: Category[] = parseCategories(req, config.categoryList as Category[]);
|
||||||
categories.filter((category) => typeof category === "string" && !(/[^a-z|_|-]/.test(category)));
|
|
||||||
|
|
||||||
if (adminUserIDInput == undefined || (userID == undefined && hashedIP == undefined)) {
|
if (adminUserIDInput == undefined || (userID == undefined && hashedIP == undefined || type !== "1" && type !== "2")) {
|
||||||
//invalid request
|
//invalid request
|
||||||
return res.sendStatus(400);
|
return res.sendStatus(400);
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
|
|
||||||
//find all previous submissions and hide them
|
//find all previous submissions and hide them
|
||||||
if (unHideOldSubmissions) {
|
if (unHideOldSubmissions) {
|
||||||
await unHideSubmissions(categories, userID);
|
await unHideSubmissions(categories, userID, type);
|
||||||
}
|
}
|
||||||
} 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
|
||||||
@@ -66,7 +67,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
return segmentsToIgnore.indexOf(item) === -1;
|
return segmentsToIgnore.indexOf(item) === -1;
|
||||||
}).map(async (UUID: string) => {
|
}).map(async (UUID: string) => {
|
||||||
// collect list for unshadowbanning
|
// collect list for unshadowbanning
|
||||||
(await db.prepare("all", `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ? AND "shadowHidden" = 1 AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]))
|
(await db.prepare("all", `SELECT "videoID", "hashedVideoID", "service", "votes", "views", "userID" FROM "sponsorTimes" WHERE "UUID" = ? AND "shadowHidden" >= 1 AND "category" in (${categories.map((c) => `'${c}'`).join(",")})`, [UUID]))
|
||||||
.forEach((videoInfo: {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID}) => {
|
.forEach((videoInfo: {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID}) => {
|
||||||
QueryCacher.clearSegmentCache(videoInfo);
|
QueryCacher.clearSegmentCache(videoInfo);
|
||||||
}
|
}
|
||||||
@@ -79,7 +80,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
} else if (enabled && row.userCount > 0) {
|
} else if (enabled && row.userCount > 0) {
|
||||||
// apply unHideOldSubmissions if applicable
|
// apply unHideOldSubmissions if applicable
|
||||||
if (unHideOldSubmissions) {
|
if (unHideOldSubmissions) {
|
||||||
await unHideSubmissions(categories, userID);
|
await unHideSubmissions(categories, userID, type);
|
||||||
return res.sendStatus(200);
|
return res.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
|
|
||||||
//find all previous submissions and hide them
|
//find all previous submissions and hide them
|
||||||
if (unHideOldSubmissions) {
|
if (unHideOldSubmissions) {
|
||||||
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "timeSubmitted" IN
|
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = ${type} 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]);
|
||||||
}
|
}
|
||||||
@@ -117,8 +118,8 @@ export async function shadowBanUser(req: Request, res: Response): Promise<Respon
|
|||||||
return res.sendStatus(200);
|
return res.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unHideSubmissions(categories: string[], userID: UserID) {
|
async function unHideSubmissions(categories: string[], userID: UserID, type = "1") {
|
||||||
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = 1 WHERE "userID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})
|
await db.prepare("run", `UPDATE "sponsorTimes" SET "shadowHidden" = ${type} WHERE "userID" = ? AND "category" in (${categories.map((c) => `'${c}'`).join(",")})
|
||||||
AND NOT EXISTS ( SELECT "videoID", "category" FROM "lockCategories" WHERE
|
AND NOT EXISTS ( SELECT "videoID", "category" FROM "lockCategories" WHERE
|
||||||
"sponsorTimes"."videoID" = "lockCategories"."videoID" AND "sponsorTimes"."service" = "lockCategories"."service" AND "sponsorTimes"."category" = "lockCategories"."category")`, [userID]);
|
"sponsorTimes"."videoID" = "lockCategories"."videoID" AND "sponsorTimes"."service" = "lockCategories"."service" AND "sponsorTimes"."category" = "lockCategories"."category")`, [userID]);
|
||||||
|
|
||||||
|
|||||||
75
src/utils/parseParams.ts
Normal file
75
src/utils/parseParams.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { Request } from "express";
|
||||||
|
import { ActionType, SegmentUUID, Category } from "../types/segments.model";
|
||||||
|
import { config } from "../config";
|
||||||
|
|
||||||
|
type fn = (req: Request, fallback: any) => any[];
|
||||||
|
|
||||||
|
const syntaxErrorWrapper = (fn: fn, req: Request, fallback: any) => {
|
||||||
|
try { return fn(req, fallback); }
|
||||||
|
catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCategories = (req: Request, fallback: Category[] ): string[] | Category[] =>
|
||||||
|
req.query.categories
|
||||||
|
? JSON.parse(req.query.categories as string)
|
||||||
|
: req.query.category
|
||||||
|
? Array.isArray(req.query.category)
|
||||||
|
? req.query.category
|
||||||
|
: [req.query.category]
|
||||||
|
: fallback;
|
||||||
|
|
||||||
|
const validateString = (array: any[]): any[] => {
|
||||||
|
if (!Array.isArray(array)) return undefined;
|
||||||
|
return array
|
||||||
|
.filter((item: any) => typeof item === "string")
|
||||||
|
.filter((item: string) => !(/[^a-z|_|-]/.test(item)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterActionType = (actionTypes: ActionType[]) => {
|
||||||
|
const filterCategories = new Set();
|
||||||
|
for (const [key, value] of Object.entries(config.categorySupport)) {
|
||||||
|
for (const type of actionTypes) {
|
||||||
|
if (value.includes(type)) {
|
||||||
|
filterCategories.add(key as Category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...filterCategories];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterInvalidCategoryActionType = (categories: Category[], actionTypes: ActionType[]): Category[] =>
|
||||||
|
categories.filter((category: Category) => filterActionType(actionTypes).includes(category));
|
||||||
|
|
||||||
|
const getActionTypes = (req: Request, fallback: ActionType[]): ActionType[] =>
|
||||||
|
req.query.actionTypes
|
||||||
|
? JSON.parse(req.query.actionTypes as string)
|
||||||
|
: req.query.actionType
|
||||||
|
? Array.isArray(req.query.actionType)
|
||||||
|
? req.query.actionType
|
||||||
|
: [req.query.actionType]
|
||||||
|
: fallback;
|
||||||
|
|
||||||
|
// fallback to empty array
|
||||||
|
const getRequiredSegments = (req: Request): SegmentUUID[] =>
|
||||||
|
req.query.requiredSegments
|
||||||
|
? JSON.parse(req.query.requiredSegments as string)
|
||||||
|
: req.query.requiredSegment
|
||||||
|
? Array.isArray(req.query.requiredSegment)
|
||||||
|
? req.query.requiredSegment
|
||||||
|
: [req.query.requiredSegment]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
export const parseCategories = (req: Request, fallback: Category[]): Category[] => {
|
||||||
|
const categories = syntaxErrorWrapper(getCategories, req, fallback);
|
||||||
|
return categories ? validateString(categories) : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseActionTypes = (req: Request, fallback: ActionType[]): ActionType[] => {
|
||||||
|
const actionTypes = syntaxErrorWrapper(getActionTypes, req, fallback);
|
||||||
|
return actionTypes ? validateString(actionTypes) : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseRequiredSegments = (req: Request): SegmentUUID[] | undefined =>
|
||||||
|
syntaxErrorWrapper(getRequiredSegments, req, []); // never fall back
|
||||||
@@ -2,42 +2,7 @@ import { Request } from "express";
|
|||||||
import { ActionType, SegmentUUID, Category, Service } from "../types/segments.model";
|
import { ActionType, SegmentUUID, Category, Service } from "../types/segments.model";
|
||||||
import { getService } from "./getService";
|
import { getService } from "./getService";
|
||||||
|
|
||||||
type fn = (req: Request) => any[];
|
import { parseCategories, parseActionTypes, parseRequiredSegments } from "./parseParams";
|
||||||
|
|
||||||
const syntaxErrorWrapper = (fn: fn, req: Request) => {
|
|
||||||
try { return fn(req); }
|
|
||||||
catch (e) { return undefined; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default to sponsor
|
|
||||||
const getCategories = (req: Request): Category[] =>
|
|
||||||
req.query.categories
|
|
||||||
? JSON.parse(req.query.categories as string)
|
|
||||||
: req.query.category
|
|
||||||
? Array.isArray(req.query.category)
|
|
||||||
? req.query.category
|
|
||||||
: [req.query.category]
|
|
||||||
: ["sponsor"];
|
|
||||||
|
|
||||||
// Default to skip
|
|
||||||
const getActionTypes = (req: Request): ActionType[] =>
|
|
||||||
req.query.actionTypes
|
|
||||||
? JSON.parse(req.query.actionTypes as string)
|
|
||||||
: req.query.actionType
|
|
||||||
? Array.isArray(req.query.actionType)
|
|
||||||
? req.query.actionType
|
|
||||||
: [req.query.actionType]
|
|
||||||
: [ActionType.Skip];
|
|
||||||
|
|
||||||
// Default to empty array
|
|
||||||
const getRequiredSegments = (req: Request): SegmentUUID[] =>
|
|
||||||
req.query.requiredSegments
|
|
||||||
? JSON.parse(req.query.requiredSegments as string)
|
|
||||||
: req.query.requiredSegment
|
|
||||||
? Array.isArray(req.query.requiredSegment)
|
|
||||||
? req.query.requiredSegment
|
|
||||||
: [req.query.requiredSegment]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const errorMessage = (parameter: string) => `${parameter} parameter does not match format requirements.`;
|
const errorMessage = (parameter: string) => `${parameter} parameter does not match format requirements.`;
|
||||||
|
|
||||||
@@ -48,20 +13,14 @@ export function parseSkipSegments(req: Request): {
|
|||||||
service: Service;
|
service: Service;
|
||||||
errors: string[];
|
errors: string[];
|
||||||
} {
|
} {
|
||||||
let categories: Category[] = syntaxErrorWrapper(getCategories, req);
|
const categories: Category[] = parseCategories(req, [ "sponsor" as Category ]);
|
||||||
const actionTypes: ActionType[] = syntaxErrorWrapper(getActionTypes, req);
|
const actionTypes: ActionType[] = parseActionTypes(req, [ActionType.Skip]);
|
||||||
const requiredSegments: SegmentUUID[] = syntaxErrorWrapper(getRequiredSegments, req);
|
const requiredSegments: SegmentUUID[] = parseRequiredSegments(req);
|
||||||
const service: Service = getService(req.query.service, req.body.services);
|
const service: Service = getService(req.query.service, req.body.services);
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
if (!Array.isArray(categories)) errors.push(errorMessage("categories"));
|
if (!Array.isArray(categories)) errors.push(errorMessage("categories"));
|
||||||
else {
|
else if (categories.length === 0) errors.push("No valid categories provided.");
|
||||||
// check category names for invalid characters
|
|
||||||
// and none string elements
|
|
||||||
categories = categories
|
|
||||||
.filter((item: any) => typeof item === "string")
|
|
||||||
.filter((category) => !(/[^a-z|_|-]/.test(category)));
|
|
||||||
if (categories.length === 0) errors.push("No valid categories provided.");
|
|
||||||
}
|
|
||||||
if (!Array.isArray(actionTypes)) errors.push(errorMessage("actionTypes"));
|
if (!Array.isArray(actionTypes)) errors.push(errorMessage("actionTypes"));
|
||||||
if (!Array.isArray(requiredSegments)) errors.push(errorMessage("requiredSegments"));
|
if (!Array.isArray(requiredSegments)) errors.push(errorMessage("requiredSegments"));
|
||||||
// finished parsing
|
// finished parsing
|
||||||
|
|||||||
@@ -11,22 +11,26 @@ describe("shadowBanUser", () => {
|
|||||||
|
|
||||||
const endpoint = "/api/shadowBanUser";
|
const endpoint = "/api/shadowBanUser";
|
||||||
const VIPuserID = "shadow-ban-vip";
|
const VIPuserID = "shadow-ban-vip";
|
||||||
|
const video = "shadowBanVideo";
|
||||||
|
const videohash = getHash(video, 1);
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const insertQuery = `INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
const insertQuery = `INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-1-uuid-0", "shadowBanned", 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-10", "shadowBanned", 0, 50, "sponsor", "YouTube", 0, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-1-uuid-0-1", "shadowBanned", 0, 50, "sponsor", "PeerTube", 120, 0, 0, getHash("testtesttest2", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-11", "shadowBanned", 0, 50, "sponsor", "PeerTube", 0, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-1-uuid-2", "shadowBanned", 0, 50, "intro", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 20, 33, 2, 0, "shadow-12", "shadowBanned", 0, 50, "intro", "YouTube", 0, videohash]);
|
||||||
|
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-2-uuid-0", "shadowBanned2", 0, 50, "sponsor", "YouTube", 100, 0, 0, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-20", "shadowBanned2", 0, 50, "sponsor", "YouTube", 0, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-2-uuid-0-1", "shadowBanned2", 0, 50, "sponsor", "PeerTube", 120, 0, 0, getHash("testtesttest2", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-21", "shadowBanned2", 0, 50, "sponsor", "PeerTube", 0, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-2-uuid-2", "shadowBanned2", 0, 50, "intro", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 20, 33, 2, 0, "shadow-22", "shadowBanned2", 0, 50, "intro", "YouTube", 0, videohash]);
|
||||||
|
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 1, 11, 2, 0, "shadow-3-uuid-0", "shadowBanned3", 0, 50, "sponsor", "YouTube", 100, 0, 1, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-30", "shadowBanned3", 0, 50, "sponsor", "YouTube", 1, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest2", 1, 11, 2, 0, "shadow-3-uuid-0-1", "shadowBanned3", 0, 50, "sponsor", "PeerTube", 120, 0, 1, getHash("testtesttest2", 1)]);
|
await db.prepare("run", insertQuery, [video, 1, 11, 2, 0, "shadow-31", "shadowBanned3", 0, 50, "sponsor", "PeerTube", 1, videohash]);
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 20, 33, 2, 0, "shadow-3-uuid-2", "shadowBanned3", 0, 50, "intro", "YouTube", 101, 0, 1, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 20, 33, 2, 0, "shadow-32", "shadowBanned3", 0, 50, "intro", "YouTube", 1, videohash]);
|
||||||
|
|
||||||
await db.prepare("run", insertQuery, ["testtesttest", 21, 34, 2, 0, "shadow-4-uuid-1", "shadowBanned4", 0, 50, "sponsor", "YouTube", 101, 0, 0, getHash("testtesttest", 1)]);
|
await db.prepare("run", insertQuery, [video, 21, 34, 2, 0, "shadow-40", "shadowBanned4", 0, 50, "sponsor", "YouTube", 0, videohash]);
|
||||||
|
|
||||||
|
await db.prepare("run", insertQuery, [video, 20, 10, 2, 0, "shadow-50", "shadowBanned5", 0, 50, "sponsor", "YouTube", 0, videohash]);
|
||||||
|
|
||||||
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ["shadowBanned3"]);
|
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ["shadowBanned3"]);
|
||||||
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ["shadowBanned4"]);
|
await db.prepare("run", `INSERT INTO "shadowBannedUsers" ("userID") VALUES(?)`, ["shadowBanned4"]);
|
||||||
@@ -220,4 +224,54 @@ describe("shadowBanUser", () => {
|
|||||||
})
|
})
|
||||||
.catch(err => done(err));
|
.catch(err => done(err));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should be able to shadowban user with different type", (done) => {
|
||||||
|
const userID = "shadowBanned5";
|
||||||
|
client({
|
||||||
|
method: "POST",
|
||||||
|
url: endpoint,
|
||||||
|
params: {
|
||||||
|
userID,
|
||||||
|
adminUserID: VIPuserID,
|
||||||
|
enabled: true,
|
||||||
|
categories: `["sponsor"]`,
|
||||||
|
unHideOldSubmissions: true,
|
||||||
|
type: "2"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async res => {
|
||||||
|
assert.strictEqual(res.status, 200);
|
||||||
|
const type2Videos = await getShadowBanSegmentCategory(userID, 2);
|
||||||
|
const type1Videos = await getShadowBanSegmentCategory(userID, 1);
|
||||||
|
const type0Videos = await getShadowBanSegmentCategory(userID, 0);
|
||||||
|
const shadowRow = await getShadowBan(userID);
|
||||||
|
assert.ok(shadowRow); // ban still exists
|
||||||
|
assert.ok(type2Videos.length > 0); // videos at type 2
|
||||||
|
assert.strictEqual(type1Videos.length, 0); // no videos at type 1
|
||||||
|
assert.strictEqual(type0Videos.length, 0); // no videos at type 0
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch(err => done(err));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not be able to shadowban user with invalid type", (done) => {
|
||||||
|
const userID = "shadowBanned5";
|
||||||
|
client({
|
||||||
|
method: "POST",
|
||||||
|
url: endpoint,
|
||||||
|
params: {
|
||||||
|
userID,
|
||||||
|
adminUserID: VIPuserID,
|
||||||
|
enabled: true,
|
||||||
|
categories: `["sponsor"]`,
|
||||||
|
unHideOldSubmissions: true,
|
||||||
|
type: "3"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
assert.strictEqual(res.status, 400);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch(err => done(err));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user