Handle watchstatus on movies/series

This commit is contained in:
Zoe Roux 2025-04-06 18:25:28 +02:00
parent 22754442ad
commit 11e1c59698
No known key found for this signature in database
5 changed files with 35 additions and 32 deletions

View File

@ -96,7 +96,7 @@ RABBITMQ_DEFAULT_PASS=aohohunuhouhuhhoahothonseuhaoensuthoaentsuhha
# v5 stuff, does absolutely nothing on master (aka: you can delete this) # v5 stuff, does absolutely nothing on master (aka: you can delete this)
EXTRA_CLAIMS='{"permissions": [], "verified": false}' EXTRA_CLAIMS='{"permissions": ["core.read"], "verified": false}'
FIRST_USER_CLAIMS='{"permissions": ["user.read", "users.write", "users.delete"], "verified": true}' FIRST_USER_CLAIMS='{"permissions": ["user.read", "users.write", "users.delete", "core.read"], "verified": true}'
GUEST_CLAIMS='{"permissions": []}' GUEST_CLAIMS='{"permissions": ["core.read"]}'
PROTECTED_CLAIMS="permissions,verified" PROTECTED_CLAIMS="permissions,verified"

View File

@ -26,35 +26,36 @@ export const auth = new Elysia({ name: "auth" })
authorization: t.TemplateLiteral("Bearer ${string}"), authorization: t.TemplateLiteral("Bearer ${string}"),
}), }),
}) })
.resolve(async ({ headers: { authorization }, error }) => {
const bearer = authorization?.slice(7);
if (!bearer) {
return error(500, {
status: 500,
message: "No jwt, auth server configuration error.",
});
}
// @ts-expect-error ts can't understand that there's two overload idk why
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
issuer: process.env.JWT_ISSUER,
});
const jwt = validator.Decode(payload);
return { jwt };
})
.macro({ .macro({
permissions(perms: string[]) { permissions(perms: string[]) {
return { return {
resolve: async ({ headers: { authorization }, error }) => { beforeHandle: ({ jwt, error }) => {
const bearer = authorization?.slice(7);
if (!bearer) {
return error(500, {
status: 500,
message: "No jwt, auth server configuration error.",
});
}
// @ts-expect-error ts can't understand that there's two overload idk why
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
issuer: process.env.JWT_ISSUER,
});
const jwt = validator.Decode(payload);
for (const perm of perms) { for (const perm of perms) {
if (!jwt.permissions.includes(perm)) { if (!jwt!.permissions.includes(perm)) {
return error(403, { return error(403, {
status: 403, status: 403,
message: `Missing permission: '${perm}'.`, message: `Missing permission: '${perm}'.`,
details: { current: jwt.permissions, required: perms }, details: { current: jwt!.permissions, required: perms },
}); });
} }
} }
return { jwt };
}, },
}; };
}, },

View File

@ -6,6 +6,7 @@ import {
entryTranslations, entryTranslations,
entryVideoJoin, entryVideoJoin,
history, history,
profiles,
showStudioJoin, showStudioJoin,
showTranslations, showTranslations,
shows, shows,
@ -36,7 +37,7 @@ import {
sortToSql, sortToSql,
} from "~/models/utils"; } from "~/models/utils";
import type { EmbeddedVideo } from "~/models/video"; import type { EmbeddedVideo } from "~/models/video";
import { entryVideosQ, getEntryProgressQ } from "../entries"; import { entryVideosQ, getEntryProgressQ, mapProgress } from "../entries";
export const showFilters: FilterDef = { export const showFilters: FilterDef = {
genres: { genres: {
@ -151,7 +152,7 @@ const showRelations = {
firstEntry: ({ firstEntry: ({
languages, languages,
userId, userId,
}: { languages: string[]; userId: number }) => { }: { languages: string[]; userId: string }) => {
const transQ = db const transQ = db
.selectDistinctOn([entryTranslations.pk]) .selectDistinctOn([entryTranslations.pk])
.from(entryTranslations) .from(entryTranslations)
@ -171,7 +172,7 @@ const showRelations = {
...transCol, ...transCol,
number: entries.episodeNumber, number: entries.episodeNumber,
videos: entryVideosQ.videos, videos: entryVideosQ.videos,
progress: getColumns(progressQ), progress: mapProgress(progressQ),
}).as("firstEntry"), }).as("firstEntry"),
}) })
.from(entries) .from(entries)
@ -189,7 +190,7 @@ const showRelations = {
watchStatusQ, watchStatusQ,
}: { }: {
languages: string[]; languages: string[];
userId: number; userId: string;
watchStatusQ: PgSelect<typeof watchlist>; watchStatusQ: PgSelect<typeof watchlist>;
}) => { }) => {
const transQ = db const transQ = db
@ -211,7 +212,7 @@ const showRelations = {
...transCol, ...transCol,
number: entries.episodeNumber, number: entries.episodeNumber,
videos: entryVideosQ.videos, videos: entryVideosQ.videos,
progress: getColumns(progressQ), progress: mapProgress(progressQ),
}).as("nextEntry"), }).as("nextEntry"),
}) })
.from(entries) .from(entries)
@ -244,7 +245,7 @@ export async function getShows({
fallbackLanguage?: boolean; fallbackLanguage?: boolean;
preferOriginal?: boolean; preferOriginal?: boolean;
relations?: (keyof typeof showRelations)[]; relations?: (keyof typeof showRelations)[];
userId: number; userId: string;
}) { }) {
const transQ = db const transQ = db
.selectDistinctOn([showTranslations.pk]) .selectDistinctOn([showTranslations.pk])
@ -263,10 +264,11 @@ export async function getShows({
const watchStatusQ = db const watchStatusQ = db
.select({ .select({
...getColumns(watchlist), ...getColumns(watchlist),
percent: watchlist.seenCount, percent: sql`${watchlist.seenCount}`.as("percent"),
}) })
.from(watchlist) .from(watchlist)
.where(eq(watchlist.profilePk, userId)) .leftJoin(profiles, eq(watchlist.profilePk, profiles.pk))
.where(eq(profiles.id, userId))
.as("watchstatus"); .as("watchstatus");
return await db return await db

View File

@ -56,7 +56,7 @@ export const Movie = t.Intersect([
t.Object({ t.Object({
original: Original, original: Original,
isAvailable: t.Boolean(), isAvailable: t.Boolean(),
watchStatus: t.Omit(WatchStatus, ["seenCount"]), watchStatus: t.Nullable(t.Omit(WatchStatus, ["seenCount"])),
}), }),
]); ]);
export type Movie = Prettify<typeof Movie.static>; export type Movie = Prettify<typeof Movie.static>;

View File

@ -71,7 +71,7 @@ export const Serie = t.Intersect([
availableCount: t.Integer({ availableCount: t.Integer({
description: "The number of episodes that can be played right away", description: "The number of episodes that can be played right away",
}), }),
watchStatus: t.Omit(WatchStatus, ["percent"]), watchStatus: t.Nullable(t.Omit(WatchStatus, ["percent"])),
}), }),
]); ]);
export type Serie = Prettify<typeof Serie.static>; export type Serie = Prettify<typeof Serie.static>;