mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-08-23 06:42:03 +10:00
Set Age Restrictions on library with a slider (#468)
* Adding groups logic and restrictions * Cleaning up some redundant code * hastily made translations * Linter issues * More linting * PR comments * Covering other APIs with age filters per comment * Add ages to age ratings * Making the linter happy --------- Co-authored-by: Robert Clabough <robert@clabough.tech>
This commit is contained in:
co-authored by
Robert Clabough
parent
b6b28afc2e
commit
26abc584a9
+100
-39
@@ -5,64 +5,71 @@ import { AgeRatingOrganization } from "~/prisma/client/enums";
|
||||
* will be to normalize to these ratings. Admins of course can override and set a separate rating if needed.
|
||||
*
|
||||
* These will change, but historically very infrequently.
|
||||
*
|
||||
* Each rating has a `value` (the string stored in the database) and an `age` (the minimum age for that rating).
|
||||
*/
|
||||
|
||||
interface RatingDef {
|
||||
readonly value: string;
|
||||
readonly age: number;
|
||||
}
|
||||
|
||||
export const ESRBRating = {
|
||||
EC: "EC",
|
||||
E: "E",
|
||||
E10: "E10",
|
||||
T: "T",
|
||||
M: "M",
|
||||
AO: "AO",
|
||||
EC: { value: "EC", age: 3 },
|
||||
E: { value: "E", age: 6 },
|
||||
E10: { value: "E10", age: 10 },
|
||||
T: { value: "T", age: 13 },
|
||||
M: { value: "M", age: 17 },
|
||||
AO: { value: "AO", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const PEGIRating = {
|
||||
"3": "3",
|
||||
"7": "7",
|
||||
"12": "12",
|
||||
"16": "16",
|
||||
"18": "18",
|
||||
"3": { value: "3", age: 3 },
|
||||
"7": { value: "7", age: 7 },
|
||||
"12": { value: "12", age: 12 },
|
||||
"16": { value: "16", age: 16 },
|
||||
"18": { value: "18", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const CEROrating = {
|
||||
A: "A",
|
||||
B: "B",
|
||||
C: "C",
|
||||
D: "D",
|
||||
Z: "Z",
|
||||
A: { value: "A", age: 0 },
|
||||
B: { value: "B", age: 12 },
|
||||
C: { value: "C", age: 15 },
|
||||
D: { value: "D", age: 17 },
|
||||
Z: { value: "Z", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const USKRating = {
|
||||
"0": "0",
|
||||
"6": "6",
|
||||
"12": "12",
|
||||
"16": "16",
|
||||
"18": "18",
|
||||
"0": { value: "0", age: 0 },
|
||||
"6": { value: "6", age: 6 },
|
||||
"12": { value: "12", age: 12 },
|
||||
"16": { value: "16", age: 16 },
|
||||
"18": { value: "18", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const GRACRating = {
|
||||
ALL: "ALL",
|
||||
"12": "12",
|
||||
"15": "15",
|
||||
"18": "18",
|
||||
ALL: { value: "ALL", age: 0 },
|
||||
"12": { value: "12", age: 12 },
|
||||
"15": { value: "15", age: 15 },
|
||||
"18": { value: "18", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const ClassIndRating = {
|
||||
L: "L",
|
||||
"10": "10",
|
||||
"12": "12",
|
||||
"14": "14",
|
||||
"16": "16",
|
||||
"18": "18",
|
||||
L: { value: "L", age: 0 },
|
||||
"10": { value: "10", age: 10 },
|
||||
"12": { value: "12", age: 12 },
|
||||
"14": { value: "14", age: 14 },
|
||||
"16": { value: "16", age: 16 },
|
||||
"18": { value: "18", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const ACBRating = {
|
||||
G: "G",
|
||||
PG: "PG",
|
||||
M: "M",
|
||||
MA15: "MA15",
|
||||
R18: "R18",
|
||||
RC: "RC",
|
||||
G: { value: "G", age: 0 },
|
||||
PG: { value: "PG", age: 8 },
|
||||
M: { value: "M", age: 15 },
|
||||
MA15: { value: "MA15", age: 15 },
|
||||
R18: { value: "R18", age: 18 },
|
||||
RC: { value: "RC", age: 18 },
|
||||
} as const;
|
||||
|
||||
export const RATINGS_FOR_ORGANIZATION = {
|
||||
@@ -73,8 +80,62 @@ export const RATINGS_FOR_ORGANIZATION = {
|
||||
[AgeRatingOrganization.GRAC]: GRACRating,
|
||||
[AgeRatingOrganization.ClassInd]: ClassIndRating,
|
||||
[AgeRatingOrganization.ACB]: ACBRating,
|
||||
} as const satisfies Record<AgeRatingOrganization, Record<string, string>>;
|
||||
} as const satisfies Record<AgeRatingOrganization, Record<string, RatingDef>>;
|
||||
|
||||
export function getAvailableRatings(org: AgeRatingOrganization): string[] {
|
||||
return Object.values(RATINGS_FOR_ORGANIZATION[org]);
|
||||
return Object.values(RATINGS_FOR_ORGANIZATION[org]).map((r) => r.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a maximum allowed age, returns all org:rating pairs that exceed it (should be banned).
|
||||
*/
|
||||
export function getBannedRatingsForMaxAge(
|
||||
maxAge: number,
|
||||
): Array<{ organization: AgeRatingOrganization; rating: string }> {
|
||||
const banned: Array<{ organization: AgeRatingOrganization; rating: string }> =
|
||||
[];
|
||||
for (const org of Object.values(AgeRatingOrganization)) {
|
||||
const ratings = RATINGS_FOR_ORGANIZATION[org];
|
||||
for (const def of Object.values(ratings)) {
|
||||
if (def.age > maxAge) {
|
||||
banned.push({ organization: org, rating: def.value });
|
||||
}
|
||||
}
|
||||
}
|
||||
return banned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of banned ratings, infer what max age slider position would produce them.
|
||||
* Returns null if the set doesn't match any clean slider threshold (manual overrides).
|
||||
*/
|
||||
export function inferMaxAgeFromBannedRatings(
|
||||
banned: Array<{ organization: string; rating: string }>,
|
||||
): number | null {
|
||||
if (banned.length === 0) return 18;
|
||||
|
||||
// Try each possible age and check if the banned set matches exactly
|
||||
const possibleAges = new Set<number>();
|
||||
for (const orgRatings of Object.values(RATINGS_FOR_ORGANIZATION)) {
|
||||
for (const def of Object.values(orgRatings)) {
|
||||
possibleAges.add(def.age);
|
||||
}
|
||||
}
|
||||
|
||||
const bannedSet = new Set(banned.map((b) => `${b.organization}:${b.rating}`));
|
||||
|
||||
for (const age of Array.from(possibleAges).sort((a, b) => b - a)) {
|
||||
const expected = getBannedRatingsForMaxAge(age);
|
||||
const expectedSet = new Set(
|
||||
expected.map((e) => `${e.organization}:${e.rating}`),
|
||||
);
|
||||
if (
|
||||
expectedSet.size === bannedSet.size &&
|
||||
[...expectedSet].every((e) => bannedSet.has(e))
|
||||
) {
|
||||
return age;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user