Added elaborate template switching.
This commit is contained in:
@@ -44,10 +44,9 @@ export async function login(credentials, userIp) {
|
||||
throw new HttpError('Logins are currently disabled', 405);
|
||||
}
|
||||
|
||||
const { user, stashes } = await fetchUser(credentials.username.trim(), {
|
||||
const { user } = await fetchUser(credentials.username.trim(), {
|
||||
email: true,
|
||||
raw: true,
|
||||
includeStashes: true,
|
||||
}).catch(() => {
|
||||
throw new HttpError('Username or password incorrect', 401);
|
||||
});
|
||||
@@ -67,7 +66,7 @@ export async function login(credentials, userIp) {
|
||||
}
|
||||
|
||||
// fetched the raw user for password verification, don't return directly to user
|
||||
return curateUser(user, { stashes });
|
||||
return curateUser(user);
|
||||
}
|
||||
|
||||
export async function signup(credentials, userIp) {
|
||||
|
||||
@@ -24,7 +24,7 @@ export function curateStash(stash, assets = {}) {
|
||||
name: stash.name,
|
||||
slug: stash.slug,
|
||||
isPrimary: stash.primary,
|
||||
public: stash.public,
|
||||
isPublic: stash.public,
|
||||
createdAt: stash.created_at,
|
||||
stashedScenes: stash.stashed_scenes ?? null,
|
||||
stashedMovies: stash.stashed_movies ?? null,
|
||||
@@ -45,7 +45,7 @@ function curateStashEntry(stash, user) {
|
||||
user_id: user?.id || undefined,
|
||||
name: stash.name || undefined,
|
||||
slug: slugify(stash.name) || undefined,
|
||||
public: stash.public ?? false,
|
||||
public: stash.isPublic ?? false,
|
||||
};
|
||||
|
||||
return curatedStashEntry;
|
||||
@@ -86,7 +86,21 @@ export async function fetchStashByUsernameAndSlug(username, stashSlug, sessionUs
|
||||
return curateStash(stash, { user });
|
||||
}
|
||||
|
||||
export async function fetchStashes(domain, itemId, sessionUser) {
|
||||
export async function fetchUserStashes(userId, reqUser) {
|
||||
const stashes = await knex('stashes')
|
||||
.select('stashes.*', 'stashes_meta.*')
|
||||
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id')
|
||||
.where('user_id', userId)
|
||||
.modify((builder) => {
|
||||
if (userId !== reqUser?.id) {
|
||||
builder.where('public', true);
|
||||
}
|
||||
});
|
||||
|
||||
return stashes.map((stash) => curateStash(stash, { user: reqUser }));
|
||||
}
|
||||
|
||||
export async function fetchDomainStashes(domain, itemId, sessionUser) {
|
||||
const stashes = await knex(`stashes_${domain}s`)
|
||||
.select('stashes.*')
|
||||
.leftJoin('stashes', 'stashes.id', `stashes_${domain}s.stash_id`)
|
||||
@@ -233,7 +247,7 @@ export async function stashActor(actorId, stashId, sessionUser) {
|
||||
|
||||
refreshView('actors');
|
||||
|
||||
return fetchStashes('actor', actorId, sessionUser);
|
||||
return fetchDomainStashes('actor', actorId, sessionUser);
|
||||
}
|
||||
|
||||
export async function unstashActor(actorId, stashId, sessionUser) {
|
||||
@@ -268,7 +282,7 @@ export async function unstashActor(actorId, stashId, sessionUser) {
|
||||
|
||||
refreshView('actors');
|
||||
|
||||
return fetchStashes('actor', actorId, sessionUser);
|
||||
return fetchDomainStashes('actor', actorId, sessionUser);
|
||||
}
|
||||
|
||||
export async function stashScene(sceneId, stashId, sessionUser) {
|
||||
@@ -297,7 +311,7 @@ export async function stashScene(sceneId, stashId, sessionUser) {
|
||||
|
||||
refreshView('scenes');
|
||||
|
||||
return fetchStashes('scene', sceneId, sessionUser);
|
||||
return fetchDomainStashes('scene', sceneId, sessionUser);
|
||||
}
|
||||
|
||||
export async function unstashScene(sceneId, stashId, sessionUser) {
|
||||
@@ -328,7 +342,7 @@ export async function unstashScene(sceneId, stashId, sessionUser) {
|
||||
|
||||
refreshView('scenes');
|
||||
|
||||
return fetchStashes('scene', sceneId, sessionUser);
|
||||
return fetchDomainStashes('scene', sceneId, sessionUser);
|
||||
}
|
||||
|
||||
export async function stashMovie(movieId, stashId, sessionUser) {
|
||||
@@ -356,7 +370,7 @@ export async function stashMovie(movieId, stashId, sessionUser) {
|
||||
|
||||
refreshView('movies');
|
||||
|
||||
return fetchStashes('movie', movieId, sessionUser);
|
||||
return fetchDomainStashes('movie', movieId, sessionUser);
|
||||
}
|
||||
|
||||
export async function unstashMovie(movieId, stashId, sessionUser) {
|
||||
@@ -387,7 +401,7 @@ export async function unstashMovie(movieId, stashId, sessionUser) {
|
||||
|
||||
refreshView('movies');
|
||||
|
||||
return fetchStashes('movie', movieId, sessionUser);
|
||||
return fetchDomainStashes('movie', movieId, sessionUser);
|
||||
}
|
||||
|
||||
CronJob.from({
|
||||
|
||||
95
src/users.js
95
src/users.js
@@ -1,13 +1,24 @@
|
||||
import { parse } from 'yaml';
|
||||
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
// import { curateStash } from './stashes.js';
|
||||
import { HttpError } from './errors.js';
|
||||
|
||||
export function curateUser(user, assets = {}) {
|
||||
function curateTemplate(template) {
|
||||
return {
|
||||
id: template.id,
|
||||
name: template.name,
|
||||
template: template.template,
|
||||
createdAt: template.created_at,
|
||||
};
|
||||
}
|
||||
|
||||
export function curateUser(user, _assets = {}) {
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const curatedStashes = assets.stashes?.filter(Boolean).map((stash) => curateStash(stash)) || [];
|
||||
// const curatedStashes = assets.stashes?.filter(Boolean).map((stash) => curateStash(stash)) || [];
|
||||
|
||||
const curatedUser = {
|
||||
id: user.id,
|
||||
@@ -17,8 +28,6 @@ export function curateUser(user, assets = {}) {
|
||||
identityVerified: user.identity_verified,
|
||||
avatar: `/media/avatars/${user.id}_${user.username}.png`,
|
||||
createdAt: user.created_at,
|
||||
stashes: curatedStashes,
|
||||
primaryStash: curatedStashes.find((stash) => stash.isPrimary),
|
||||
};
|
||||
|
||||
return curatedUser;
|
||||
@@ -38,7 +47,7 @@ function whereUser(builder, userId, options = {}) {
|
||||
builder.where('users.id', Number(userId));
|
||||
}
|
||||
|
||||
export async function fetchUser(userId, options = {}, reqUser) {
|
||||
export async function fetchUser(userId, options = {}, _reqUser) {
|
||||
const user = await knex('users')
|
||||
.select(knex.raw('users.*, users_roles.abilities as role_abilities'))
|
||||
.modify((builder) => whereUser(builder, userId, options))
|
||||
@@ -50,19 +59,71 @@ export async function fetchUser(userId, options = {}, reqUser) {
|
||||
throw new HttpError(`User '${userId}' not found`, 404);
|
||||
}
|
||||
|
||||
const stashes = await knex('stashes')
|
||||
.select('stashes.*', 'stashes_meta.*')
|
||||
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id')
|
||||
.where('user_id', user.id)
|
||||
.modify((builder) => {
|
||||
if (reqUser?.id !== user.id && !options.includeStashes) {
|
||||
builder.where('public', true);
|
||||
}
|
||||
});
|
||||
/*
|
||||
const [stashes, templates] = await Promise.all([
|
||||
knex('stashes')
|
||||
.select('stashes.*', 'stashes_meta.*')
|
||||
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id')
|
||||
.where('user_id', user.id)
|
||||
.modify((builder) => {
|
||||
if (reqUser?.id !== user.id && !options.includeStashes) {
|
||||
builder.where('public', true);
|
||||
}
|
||||
}),
|
||||
options.includeTemplates
|
||||
? knex('users_templates').where('user_id', user.id)
|
||||
: null,
|
||||
]);
|
||||
*/
|
||||
|
||||
if (options.raw) {
|
||||
return { user, stashes };
|
||||
// return { user, stashes, templates };
|
||||
return { user };
|
||||
}
|
||||
|
||||
return curateUser(user, { stashes });
|
||||
// return curateUser(user, { stashes, templates });
|
||||
return curateUser(user, {});
|
||||
}
|
||||
|
||||
export async function fetchUserTemplates(reqUser) {
|
||||
const templates = await knex('users_templates')
|
||||
.where('user_id', reqUser.id)
|
||||
.orderBy('created_at', 'asc');
|
||||
|
||||
return templates.map((template) => curateTemplate(template));
|
||||
}
|
||||
|
||||
export async function createTemplate(template, reqUser) {
|
||||
if (!template.template) {
|
||||
throw new HttpError('No template specified', 400);
|
||||
}
|
||||
|
||||
if (!template.name) {
|
||||
throw new HttpError('No template name specified', 400);
|
||||
}
|
||||
|
||||
try {
|
||||
parse(template.template);
|
||||
} catch (error) {
|
||||
throw new HttpError(`Invalid YAML: ${error.message}`, 400);
|
||||
}
|
||||
|
||||
const [templateEntry] = await knex('users_templates')
|
||||
.insert({
|
||||
user_id: reqUser.id,
|
||||
name: template.name,
|
||||
template: template.template,
|
||||
})
|
||||
.onConflict(['name', 'user_id'])
|
||||
.merge()
|
||||
.returning('*');
|
||||
|
||||
return curateTemplate(templateEntry);
|
||||
}
|
||||
|
||||
export async function removeTemplate(templateId, reqUser) {
|
||||
await knex('users_templates')
|
||||
.where('id', templateId)
|
||||
.where('user_id', reqUser.id)
|
||||
.delete();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { login, signup } from '../auth.js';
|
||||
import { fetchUser } from '../users.js';
|
||||
|
||||
function getIp(req) {
|
||||
const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress; // See src/ws
|
||||
const ip = req.headers['x-forwarded-for']?.split(',')[0] || req.connection.remoteAddress;
|
||||
|
||||
const unmappedIp = ip?.includes('.')
|
||||
? ip.slice(ip.lastIndexOf(':') + 1)
|
||||
|
||||
70
src/web/main.js
Normal file
70
src/web/main.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import config from 'config';
|
||||
import { renderPage } from 'vike/server'; // eslint-disable-line import/extensions
|
||||
|
||||
import { fetchUserStashes } from '../stashes.js';
|
||||
import { fetchUserTemplates } from '../users.js';
|
||||
import { fetchUnseenNotificationsCount } from '../alerts.js';
|
||||
|
||||
export default async function mainHandler(req, res, next) {
|
||||
const [stashes, templates, unseenNotifications] = req.user && await Promise.all([
|
||||
fetchUserStashes(req.user.id, req.user),
|
||||
fetchUserTemplates(req.user),
|
||||
fetchUnseenNotificationsCount(req.user),
|
||||
]);
|
||||
|
||||
const pageContextInit = {
|
||||
urlOriginal: req.originalUrl,
|
||||
urlQuery: req.query, // vike's own query does not apply boolean parser
|
||||
headers: req.headers,
|
||||
cookies: req.cookies,
|
||||
tagFilter: req.tagFilter,
|
||||
user: req.user && {
|
||||
id: req.user.id,
|
||||
username: req.user.username,
|
||||
email: req.user.email,
|
||||
avatar: req.user.avatar,
|
||||
},
|
||||
assets: req.user ? {
|
||||
stashes,
|
||||
primaryStash: stashes.find((stash) => stash.isPrimary),
|
||||
templates,
|
||||
} : null,
|
||||
env: {
|
||||
theme: req.cookies.theme || req.headers['sec-ch-prefers-color-scheme'] || 'light',
|
||||
selectedTemplate: Number(req.cookies.selectedTemplate) || 0,
|
||||
allowLogin: config.auth.login,
|
||||
allowSignup: config.auth.signup,
|
||||
maxMatches: config.database.manticore.maxMatches,
|
||||
maxAggregateSize: config.database.manticore.maxAggregateSize,
|
||||
media: config.media,
|
||||
psa: config.psa,
|
||||
links: config.links,
|
||||
},
|
||||
meta: {
|
||||
unseenNotifications,
|
||||
},
|
||||
};
|
||||
|
||||
const pageContext = await renderPage(pageContextInit);
|
||||
const { httpResponse } = pageContext;
|
||||
|
||||
if (pageContext.errorWhileRendering) {
|
||||
console.error(pageContext.errorWhileRendering);
|
||||
}
|
||||
|
||||
if (!httpResponse) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
if (res.writeEarlyHints) {
|
||||
res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) });
|
||||
}
|
||||
*/
|
||||
|
||||
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value));
|
||||
res.status(httpResponse.statusCode);
|
||||
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/stream
|
||||
res.send(httpResponse.body);
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import session from 'express-session';
|
||||
import RedisStore from 'connect-redis';
|
||||
import compression from 'compression';
|
||||
import cookie from 'cookie';
|
||||
import { renderPage } from 'vike/server'; // eslint-disable-line import/extensions
|
||||
|
||||
import redis from '../redis.js';
|
||||
|
||||
@@ -22,6 +21,8 @@ import { fetchTagsApi } from './tags.js';
|
||||
|
||||
import { graphqlApi } from './graphql.js';
|
||||
|
||||
import mainHandler from './main.js';
|
||||
|
||||
import {
|
||||
setUserApi,
|
||||
loginApi,
|
||||
@@ -31,9 +32,13 @@ import {
|
||||
|
||||
import {
|
||||
fetchUserApi,
|
||||
fetchUserTemplatesApi,
|
||||
createTemplateApi,
|
||||
removeTemplateApi,
|
||||
} from './users.js';
|
||||
|
||||
import {
|
||||
fetchUserStashesApi,
|
||||
createStashApi,
|
||||
removeStashApi,
|
||||
stashActorApi,
|
||||
@@ -54,8 +59,6 @@ import {
|
||||
updateNotificationsApi,
|
||||
} from './alerts.js';
|
||||
|
||||
import { fetchUnseenNotificationsCount } from '../alerts.js';
|
||||
|
||||
import initLogger from '../logger.js';
|
||||
|
||||
const logger = initLogger();
|
||||
@@ -141,6 +144,7 @@ export default async function initServer() {
|
||||
router.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);
|
||||
|
||||
// STASHES
|
||||
router.get('/api/users/:userId/stashes', fetchUserStashesApi);
|
||||
router.post('/api/stashes', createStashApi);
|
||||
router.patch('/api/stashes/:stashId', updateStashApi);
|
||||
router.delete('/api/stashes/:stashId', removeStashApi);
|
||||
@@ -153,6 +157,11 @@ export default async function initServer() {
|
||||
router.delete('/api/stashes/:stashId/scenes/:sceneId', unstashSceneApi);
|
||||
router.delete('/api/stashes/:stashId/movies/:movieId', unstashMovieApi);
|
||||
|
||||
// SUMMARY TEMPLATES
|
||||
router.get('/api/users/:userId/templates', fetchUserTemplatesApi);
|
||||
router.post('/api/templates', createTemplateApi);
|
||||
router.delete('/api/templates/:templateId', removeTemplateApi);
|
||||
|
||||
// ALERTS
|
||||
router.get('/api/alerts', fetchAlertsApi);
|
||||
router.post('/api/alerts', createAlertApi);
|
||||
@@ -186,61 +195,7 @@ export default async function initServer() {
|
||||
next();
|
||||
});
|
||||
|
||||
router.get('*', async (req, res, next) => {
|
||||
const unseenNotifications = await fetchUnseenNotificationsCount(req.user);
|
||||
|
||||
const pageContextInit = {
|
||||
urlOriginal: req.originalUrl,
|
||||
urlQuery: req.query, // vike's own query does not apply boolean parser
|
||||
headers: req.headers,
|
||||
cookies: req.cookies,
|
||||
tagFilter: req.tagFilter,
|
||||
user: req.user && {
|
||||
id: req.user.id,
|
||||
username: req.user.username,
|
||||
email: req.user.email,
|
||||
avatar: req.user.avatar,
|
||||
stashes: req.user.stashes,
|
||||
primaryStash: req.user.primaryStash,
|
||||
},
|
||||
env: {
|
||||
theme: req.cookies.theme || req.headers['sec-ch-prefers-color-scheme'] || 'light',
|
||||
allowLogin: config.auth.login,
|
||||
allowSignup: config.auth.signup,
|
||||
maxMatches: config.database.manticore.maxMatches,
|
||||
maxAggregateSize: config.database.manticore.maxAggregateSize,
|
||||
media: config.media,
|
||||
psa: config.psa,
|
||||
links: config.links,
|
||||
},
|
||||
meta: {
|
||||
unseenNotifications,
|
||||
},
|
||||
};
|
||||
|
||||
const pageContext = await renderPage(pageContextInit);
|
||||
const { httpResponse } = pageContext;
|
||||
|
||||
if (pageContext.errorWhileRendering) {
|
||||
console.error(pageContext.errorWhileRendering);
|
||||
}
|
||||
|
||||
if (!httpResponse) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
if (res.writeEarlyHints) {
|
||||
res.writeEarlyHints({ link: httpResponse.earlyHints.map((e) => e.earlyHintLink) });
|
||||
}
|
||||
*/
|
||||
|
||||
httpResponse.headers.forEach(([name, value]) => res.setHeader(name, value));
|
||||
res.status(httpResponse.statusCode);
|
||||
// For HTTP streams use httpResponse.pipe() instead, see https://vike.dev/stream
|
||||
res.send(httpResponse.body);
|
||||
});
|
||||
router.get('*', mainHandler);
|
||||
|
||||
router.use(errorHandler);
|
||||
app.use(router);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
fetchUserStashes,
|
||||
createStash,
|
||||
removeStash,
|
||||
stashActor,
|
||||
@@ -10,27 +11,26 @@ import {
|
||||
updateStash,
|
||||
} from '../stashes.js';
|
||||
|
||||
import { updateSessionUser } from './auth.js';
|
||||
export async function fetchUserStashesApi(req, res) {
|
||||
const stashes = await fetchUserStashes(req.user.id, req.user);
|
||||
|
||||
res.send(stashes);
|
||||
}
|
||||
|
||||
export async function createStashApi(req, res) {
|
||||
const stash = await createStash(req.body, req.session.user);
|
||||
|
||||
await updateSessionUser(req);
|
||||
const stash = await createStash(req.body, req.user);
|
||||
|
||||
res.send(stash);
|
||||
}
|
||||
|
||||
export async function updateStashApi(req, res) {
|
||||
const stash = await updateStash(Number(req.params.stashId), req.body, req.session.user);
|
||||
|
||||
await updateSessionUser(req);
|
||||
const stash = await updateStash(Number(req.params.stashId), req.body, req.user);
|
||||
|
||||
res.send(stash);
|
||||
}
|
||||
|
||||
export async function removeStashApi(req, res) {
|
||||
await removeStash(Number(req.params.stashId), req.session.user);
|
||||
await updateSessionUser(req);
|
||||
await removeStash(Number(req.params.stashId), req.user);
|
||||
|
||||
res.status(204).send();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
import { fetchUser } from '../users.js';
|
||||
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
|
||||
|
||||
import {
|
||||
fetchUser,
|
||||
fetchUserTemplates,
|
||||
createTemplate,
|
||||
removeTemplate,
|
||||
} from '../users.js';
|
||||
|
||||
export async function fetchUserApi(req, res) {
|
||||
const user = await fetchUser(req.params.userId, {}, req.user);
|
||||
|
||||
res.send(user);
|
||||
res.send(stringify(user));
|
||||
}
|
||||
|
||||
export async function fetchUserTemplatesApi(req, res) {
|
||||
const templates = await fetchUserTemplates(req.user);
|
||||
|
||||
res.send(templates);
|
||||
}
|
||||
|
||||
export async function createTemplateApi(req, res) {
|
||||
const template = await createTemplate(req.body, req.user);
|
||||
|
||||
res.send(stringify(template));
|
||||
}
|
||||
|
||||
export async function removeTemplateApi(req, res) {
|
||||
await removeTemplate(req.params.templateId, req.user);
|
||||
|
||||
res.status(204).send();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user