mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-03 03:17:54 +01:00
WI import checking for existing worlds too
- WI import uses the same check as create new world - API endpoint to get server-side sanitized filenames - Small changes to toast messages
This commit is contained in:
parent
29d817d549
commit
a251849f8f
@ -1021,6 +1021,36 @@ export function extractDataFromPng(data, identifier = 'chara') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the server to sanitize a given filename
|
||||||
|
*
|
||||||
|
* @param {string} fileName - The name of the file to sanitize
|
||||||
|
* @returns {Promise<string>} A Promise that resolves to the sanitized filename if successful, or rejects with an error message if unsuccessful
|
||||||
|
*/
|
||||||
|
export async function getSanitizedFilename(fileName) {
|
||||||
|
try {
|
||||||
|
const result = await fetch('/api/files/sanitize-filename', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: getRequestHeaders(),
|
||||||
|
body: JSON.stringify({
|
||||||
|
fileName: fileName,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
const error = await result.text();
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseData = await result.json();
|
||||||
|
return responseData.fileName;
|
||||||
|
} catch (error) {
|
||||||
|
toastr.error(String(error), 'Could not sanitize fileName');
|
||||||
|
console.error('Could not sanitize fileName', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a base64 encoded image to the backend to be saved as a file.
|
* Sends a base64 encoded image to the backend to be saved as a file.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js';
|
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js';
|
||||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, equalsIgnoreCaseAndAccents } from './utils.js';
|
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, equalsIgnoreCaseAndAccents, getSanitizedFilename } from './utils.js';
|
||||||
import { extension_settings, getContext } from './extensions.js';
|
import { extension_settings, getContext } from './extensions.js';
|
||||||
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js';
|
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js';
|
||||||
import { isMobile } from './RossAscends-mods.js';
|
import { isMobile } from './RossAscends-mods.js';
|
||||||
@ -2631,19 +2631,9 @@ async function createNewWorldInfo(worldInfoName, { interactive = false } = {}) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingWorld = world_names.find(x => equalsIgnoreCaseAndAccents(x, worldInfoName));
|
const allowed = await checkCanOverwriteWorldInfo(worldInfoName, { interactive: interactive, actionName: 'Create' });
|
||||||
if (existingWorld) {
|
if (!allowed) {
|
||||||
const overwrite = interactive ? await callPopup(`<h3>Creating New World Info</h3><p>A world with the same name already exists:<br />${existingWorld}</p>Do you want to overwrite it?`, 'confirm') : false;
|
return false;
|
||||||
|
|
||||||
if (!overwrite) {
|
|
||||||
toastr.warning(`World creation cancelled. A world with the same name already exists:<br />${existingWorld}`, 'Creating New World Info', { escapeHtml: false });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
toastr.info(`Overwriting Existing World Info:<br />${existingWorld}`, 'Creating New World Info', { escapeHtml: false });
|
|
||||||
|
|
||||||
// Manually delete, as we want to overwrite. The name might be slightly different so file name would not be the same.
|
|
||||||
await deleteWorldInfo(existingWorld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveWorldInfo(worldInfoName, worldInfoTemplate, true);
|
await saveWorldInfo(worldInfoName, worldInfoTemplate, true);
|
||||||
@ -2659,6 +2649,37 @@ async function createNewWorldInfo(worldInfoName, { interactive = false } = {}) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms if the user wants to overwrite an existing world info with the same name.
|
||||||
|
* If no world info with the name exists, this simply returns true
|
||||||
|
*
|
||||||
|
* @param {string} name - The name of the world info to create
|
||||||
|
* @param {Object} options - Optional parameters
|
||||||
|
* @param {boolean} [options.interactive=false] - Whether to show a confirmation dialog when overwriting an existing world
|
||||||
|
* @param {string} [options.actionName='overwrite'] - The action name to display in the confirmation dialog
|
||||||
|
* @returns {Promise<boolean>} True if the user confirmed the overwrite, false otherwise
|
||||||
|
*/
|
||||||
|
async function checkCanOverwriteWorldInfo(name, { interactive = false, actionName = 'Overwrite' } = {}) {
|
||||||
|
const existingWorld = world_names.find(x => equalsIgnoreCaseAndAccents(x, name));
|
||||||
|
if (!existingWorld) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overwrite = interactive ? await callPopup(`<h3>World Info ${actionName}</h3><p>A world with the same name already exists:<br />${existingWorld}</p>Do you want to overwrite it?`, 'confirm') : false;
|
||||||
|
if (!overwrite) {
|
||||||
|
toastr.warning(`World ${actionName.toLowerCase()} cancelled. A world with the same name already exists:<br />${existingWorld}`, `World Info ${actionName}`, { escapeHtml: false });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
toastr.info(`Overwriting Existing World Info:<br />${existingWorld}`, `World Info ${actionName}`, { escapeHtml: false });
|
||||||
|
|
||||||
|
// Manually delete, as we want to overwrite. The name might be slightly different so file name would not be the same.
|
||||||
|
await deleteWorldInfo(existingWorld);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async function getCharacterLore() {
|
async function getCharacterLore() {
|
||||||
const character = characters[this_chid];
|
const character = characters[this_chid];
|
||||||
const name = character?.name;
|
const name = character?.name;
|
||||||
@ -3589,6 +3610,13 @@ export async function importWorldInfo(file) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const worldName = file.name.substr(0, file.name.lastIndexOf("."));
|
||||||
|
const sanitizedWorldName = await getSanitizedFilename(worldName);
|
||||||
|
const allowed = await checkCanOverwriteWorldInfo(sanitizedWorldName, { interactive: true, actionName: 'Import' });
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: '/api/worldinfo/import',
|
url: '/api/worldinfo/import',
|
||||||
@ -3606,7 +3634,7 @@ export async function importWorldInfo(file) {
|
|||||||
$('#world_editor_select').val(newIndex).trigger('change');
|
$('#world_editor_select').val(newIndex).trigger('change');
|
||||||
}
|
}
|
||||||
|
|
||||||
toastr.info(`World Info "${data.name}" imported successfully!`);
|
toastr.success(`World Info "${data.name}" imported successfully!`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: (_jqXHR, _exception) => { },
|
error: (_jqXHR, _exception) => { },
|
||||||
|
@ -2,11 +2,28 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const writeFileSyncAtomic = require('write-file-atomic').sync;
|
const writeFileSyncAtomic = require('write-file-atomic').sync;
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const sanitize = require('sanitize-filename');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { validateAssetFileName } = require('./assets');
|
const { validateAssetFileName } = require('./assets');
|
||||||
const { jsonParser } = require('../express-common');
|
const { jsonParser } = require('../express-common');
|
||||||
const { clientRelativePath } = require('../util');
|
const { clientRelativePath } = require('../util');
|
||||||
|
|
||||||
|
router.post('/sanitize-filename', jsonParser, async (request, response) => {
|
||||||
|
try {
|
||||||
|
const fileName = String(request.body.fileName);
|
||||||
|
if (!fileName) {
|
||||||
|
return response.status(400).send('No fileName specified');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitizedFilename = sanitize(fileName);
|
||||||
|
console.debug(`Sanitized fileName: ${fileName} -> ${sanitizedFilename}`);
|
||||||
|
return response.send({ fileName: sanitizedFilename });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return response.sendStatus(500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/upload', jsonParser, async (request, response) => {
|
router.post('/upload', jsonParser, async (request, response) => {
|
||||||
try {
|
try {
|
||||||
if (!request.body.name) {
|
if (!request.body.name) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user