Added manticore sync API.

This commit is contained in:
2026-06-08 05:50:29 +02:00
parent 1bc7dd3a43
commit 96b1a99e04
6 changed files with 70 additions and 9 deletions

View File

@@ -44,7 +44,7 @@
</a>
<a
v-if="user?.abilities?.some((ability) => ability.plainUrls)"
v-if="user?.abilities?.some((ability) => ability.subject === 'plainUrls')"
:href="entity.url"
target="_blank"
rel="noopener"

View File

@@ -52,7 +52,7 @@
</div>
<Link
:href="user?.abilities?.some((ability) => ability.plainUrls) ? scene.url : scene.watchUrl"
:href="user?.abilities?.some((ability) => ability.subject === 'plainUrls') ? scene.url : scene.watchUrl"
:title="scene.date ? formatDate(scene.date.toISOString(), 'y-MM-dd hh:mm') : `Release date unknown, added ${formatDate(scene.createdAt, 'y-MM-dd')}`"
target="_blank"
class="date nolink"

View File

@@ -203,6 +203,8 @@ export async function verifyKey(userId, key, req) {
.then(() => {
// no need to wait for this
});
return fetchUser(storedKey.user_id);
}
export async function createKey(reqUser) {

View File

@@ -16,6 +16,7 @@ import initRestrictionHandler from './restrictions.js';
import { scenesRouter } from './scenes.js';
import { actorsRouter } from './actors.js';
import { syncRouter } from './sync.js';
import { fetchMoviesApi } from './movies.js';
import { fetchEntitiesApi } from './entities.js';
@@ -122,11 +123,7 @@ export default async function initServer() {
router.use('/api/*', async (req, _res, next) => {
if (req.headers['api-user']) {
await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
req.user = { // eslint-disable-line no-param-reassign
id: Number(req.headers['api-user']),
};
req.user = await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
}
next();
@@ -150,6 +147,7 @@ export default async function initServer() {
router.use(alertsRouter);
router.use(scenesRouter);
router.use(actorsRouter);
router.use(syncRouter);
// MOVIES
router.get('/api/movies', fetchMoviesApi);

49
src/web/sync.js Normal file
View File

@@ -0,0 +1,49 @@
import Router from 'express-promise-router';
import {
syncScenes,
syncMovies,
syncActors,
syncStashes,
} from '../sync.js';
import verifyAbility from '../../utils/verify-ability.js';
export const syncRouter = Router();
async function syncScenesApi(req, res) {
verifyAbility(req.user, 'sync', null, { throwError: true });
await syncScenes(req.body.sceneIds);
res.status(204).send();
}
async function syncMoviesApi(req, res) {
verifyAbility(req.user, 'sync', null, { throwError: true });
await syncMovies(req.body.movieIds);
res.status(204).send();
}
async function syncActorsApi(req, res) {
verifyAbility(req.user, 'sync', null, { throwError: true });
await syncActors(req.body.actorIds);
res.status(204).send();
}
async function syncStashesApi(req, res) {
verifyAbility(req.user, 'sync', null, { throwError: true });
await syncStashes(req.body.stashIds);
res.status(204).send();
}
syncRouter.post('/api/sync/scenes', syncScenesApi);
syncRouter.post('/api/sync/movies', syncMoviesApi);
syncRouter.post('/api/sync/actors', syncActorsApi);
syncRouter.post('/api/sync/stashes', syncStashesApi);

View File

@@ -1,4 +1,6 @@
export default function verifyAbility(user, subject, action) {
import { HttpError } from '../src/errors.js';
function checkAbility(user, subject, action) {
if (!user?.abilities) {
return null;
}
@@ -8,8 +10,18 @@ export default function verifyAbility(user, subject, action) {
}
if (subject) {
return user.abilities.some((ability) => ability[subject] === true);
return user.abilities.some((ability) => ability[subject] === true || (ability.subject === subject && !ability.action));
}
return false;
}
export default function verifyAbility(user, subject, action, options = {}) {
const isAble = checkAbility(user, subject, action);
if (!isAble && options.throwError) {
throw new HttpError(`Insufficient privileges for ${[subject, action].filter(Boolean).join()}`, 403);
}
return isAble;
}