From 5a195b8f5a4441dbf900767d778ad4d836781692 Mon Sep 17 00:00:00 2001 From: DebaucheryLibrarian Date: Tue, 31 Mar 2026 02:34:38 +0200 Subject: [PATCH] Removed scene revisions. --- .eslintrc | 24 +++- scenes-revisions.mjs | 300 ------------------------------------------- 2 files changed, 22 insertions(+), 302 deletions(-) delete mode 100644 scenes-revisions.mjs diff --git a/.eslintrc b/.eslintrc index 4b0d0e9..be5abec 100755 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,9 @@ { "root": true, "extends": [ - "airbnb-base" + "airbnb-base", + "plugin:import/errors", + "plugin:vue/recommended" ], "parserOptions": { "parser": "@babel/eslint-parser", @@ -19,13 +21,31 @@ "no-console": 0, "no-param-reassign": ["error", { "props": true, - "ignorePropertyModificationsFor": ["state", "acc"] + "ignorePropertyModificationsFor": ["state", "acc", "req"] }], + "vue/multi-word-component-names": 0, + "vue/no-reserved-component-names": 0, "no-tabs": "off", "no-unused-vars": ["error", {"argsIgnorePattern": "^_"}], "prefer-destructuring": 0, "template-curly-spacing": "off", + "vue/html-indent": ["error", "tab"], + "vue/multiline-html-element-content-newline": 0, + "vue/no-v-html": 0, + "vue/singleline-html-element-content-newline": 0, + "vue/comment-directive": 0, }, + "settings": { + "import/resolver": { + "alias": { + "extensions": [".js"], + "map": [ + ["#", "."], + ["#root", "."] + ] + } + } + }, "globals": { "CONFIG": true } diff --git a/scenes-revisions.mjs b/scenes-revisions.mjs deleted file mode 100644 index e6d3aa0..0000000 --- a/scenes-revisions.mjs +++ /dev/null @@ -1,300 +0,0 @@ -const keyMap = { - datePrecision: 'date_precision', - productionDate: 'production_date', - productionLocation: 'production_location', - productionCity: 'production_city', - productionState: 'production_state', -}; - -export default function initSceneRevisions({ - config, - knex, - mj, - fetchScenesById, - logger, -}) { - async function applySceneValueDelta(sceneId, delta, trx) { - return knex('releases') - .where('id', sceneId) - .update(keyMap[delta.key] || delta.key, delta.value) - .transacting(trx); - } - - async function applySceneActorsDelta(sceneId, delta, trx) { - await knex('releases_actors') - .where('release_id', sceneId) - .delete() - .transacting(trx); - - if (delta.value.length > 0) { - await knex('releases_actors') - .insert(delta.value.map((actorId) => ({ - release_id: sceneId, - actor_id: actorId, - }))) - .transacting(trx); - } - } - - async function applySceneTagsDelta(sceneId, delta, trx) { - // don't remove unidentified tags - await knex('releases_tags') - .where('release_id', sceneId) - .whereNotNull('tag_id') - .delete() - .transacting(trx); - - if (delta.value.length > 0) { - await knex('releases_tags') - .insert(delta.value.map((tag) => ({ - release_id: sceneId, - tag_id: tag.id, - actor_id: tag.actorId, - source: 'editor', - }))) - .transacting(trx); - } - } - - async function applySceneMoviesDelta(sceneId, delta, trx) { - await knex('movies_scenes') - .where('scene_id', sceneId) - .delete() - .transacting(trx); - - if (delta.value.length > 0) { - await knex('movies_scenes') - .insert(delta.value.map((movieId) => ({ - scene_id: sceneId, - movie_id: movieId, - }))) - .transacting(trx); - } - } - - async function applySceneDeleteDelta(sceneId, _delta, trx, reqUser) { - if (!reqUser.abilities.some((ability) => ability.subject === 'scene' && ability.action === 'delete')) { - throw new HttpError('You are not privileged to delete scenes', 400); - } - - await knex('releases') - .where('id', sceneId) - .delete() - .transacting(trx); - } - - async function applySceneRevision(revisionIds, reqUser) { - const revisions = await knex('scenes_revisions') - .whereIn('id', revisionIds) - .whereNull('applied_at'); // should not re-apply revision that was already applied - - await revisions.reduce(async (chain, revision) => { - await chain; - - await knex.transaction(async (trx) => { - await Promise.all(revision.deltas.map(async (delta) => { - if (delta.key === 'delete') { - return applySceneDeleteDelta(revision.scene_id, delta, trx, reqUser); - } - - if ([ - 'title', - 'description', - 'date', - 'datePrecision', - 'duration', - 'productionDate', - 'productionLocation', - 'productionCity', - 'productionState', - ].includes(delta.key)) { - return applySceneValueDelta(revision.scene_id, delta, trx); - } - - if (delta.key === 'actors') { - return applySceneActorsDelta(revision.scene_id, delta, trx); - } - - if (delta.key === 'tags') { - return applySceneTagsDelta(revision.scene_id, delta, trx); - } - - if (delta.key === 'movies') { - return applySceneMoviesDelta(revision.scene_id, delta, trx); - } - - return null; - })); - - await knex('scenes_revisions') - .where('id', revision.id) - .update('applied_at', knex.fn.now()) - .transacting(trx); - - // await trx.commit(); - }).catch(async (error) => { - logger.error(`Failed to apply revision ${revision.id} on scene ${revision.scene_id}: ${error.message}`); - throw error; - }); - }, Promise.resolve()); - } - - async function reviewSceneRevision(revisionId, isApproved, { feedback }, reqUser) { - if (!reqUser || reqUser.role === 'user') { - throw new HttpError('You are not permitted to approve revisions', 403); - } - - if (typeof isApproved !== 'boolean') { - throw new HttpError('You must either approve or reject the revision', 400); - } - - const updated = await knex('scenes_revisions') - .where('id', revisionId) - .whereNull('approved') // don't rerun reviewed revision, must be forked into new revision instead - .whereNull('applied_at') - .update({ - approved: isApproved, - reviewed_at: knex.fn.now(), - reviewed_by: reqUser.id, - feedback, - }); - - if (updated === 0) { - throw new HttpError('This revision was already reviewed', 409); - } - - if (isApproved) { - try { - await applySceneRevision([revisionId], reqUser); - } catch (error) { - await knex('scenes_revisions') - .where('id', revisionId) - .update({ - approved: null, - reviewed_at: null, - reviewed_by: null, - }); - - throw error; - } - } - } - - async function createSceneRevision(sceneId, { edits, comment, apply }, reqUser) { - const [ - [scene], - openRevisions, - ] = await Promise.all([ - fetchScenesById([sceneId], { - reqUser, - includeAssets: true, - includePartOf: true, - }), - knex('scenes_revisions') - .where('user_id', reqUser.id) - .whereNull('approved'), - ]); - - if (!scene) { - throw new HttpError(`No scene with ID ${sceneId} found to update`, 404); - } - - if (openRevisions.length >= config.revisions.unapprovedLimit && reqUser.role !== 'admin') { - throw new HttpError(`You have ${config.revisions.unapprovedLimit} unapproved revisions, please wait for approval before submitting another revision.`, 429); - } - - const baseScene = Object.fromEntries(Object.entries(scene).map(([key, values]) => { - if ([ - 'effectiveDate', - 'isNew', - 'network', - 'stashes', - 'watchUrl', - ].includes(key)) { - return null; - } - - if (values?.hash) { - return [key, values.hash]; - } - - if (values?.id) { - return [key, values.id]; - } - - if (key === 'tags') { - return [key, values.map((tag) => ({ - id: tag.id, - actorId: tag.actorId, - }))]; - } - - if (Array.isArray(values)) { - return [key, values.map((value) => value?.hash || value?.id || value)]; - } - - return [key, values]; - }).filter(Boolean)); - - const deltas = Object.entries(edits).map(([key, value]) => { - if (key === 'delete') { - return { key: 'delete' }; - } - - if (baseScene[key] === value || typeof value === 'undefined') { - return null; - } - - if (key === 'tags') { - return { - key, - value: value.map((tag) => ({ - id: tag.id, - actorId: tag.actorId, - })), - }; - } - - if (Array.isArray(value)) { - const valueSet = new Set(value); - const baseSet = new Set(baseScene[key]); - - if (valueSet.size === baseSet.size && baseScene[key].every((id) => valueSet.has(id))) { - return null; - } - - return { key, value: Array.from(valueSet) }; - } - - return { key, value }; - }).filter(Boolean); - - if (deltas.length === 0) { - throw new HttpError('No effective changes provided', 400); - } - - const [revisionEntry] = await knex('scenes_revisions') - .insert({ - user_id: reqUser.id, - scene_id: scene.id, - base: JSON.stringify(baseScene), - deltas: JSON.stringify(deltas), - hash: mj.hash({ - base: baseScene, - deltas, - }), - comment, - }) - .returning('id'); - - if (['admin', 'editor'].includes(reqUser.role) && apply) { - // don't keep the editor waiting for the revision to apply - reviewSceneRevision(revisionEntry.id, true, {}, reqUser).catch(() => {}); - } - } - - return { - createSceneRevision, - reviewSceneRevision, - }; -}