1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

Desktop, Mobile: Fixes #13258: Prevent new notes from being created in trashed or missing notebooks in certain cases (#13575)

This commit is contained in:
mrjo118
2025-11-15 09:21:00 +00:00
committed by GitHub
parent b9b07790d7
commit 2ab720ff87
4 changed files with 57 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
import { utils, CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
import { _ } from '@joplin/lib/locale';
import Setting from '@joplin/lib/models/Setting';
import Note from '@joplin/lib/models/Note';
import Folder from '@joplin/lib/models/Folder';
export const newNoteEnabledConditions = 'oneFolderSelected && !inConflictFolder && !folderIsReadOnly && !folderIsTrash';
@@ -14,7 +14,7 @@ export const declaration: CommandDeclaration = {
export const runtime = (): CommandRuntime => {
return {
execute: async (_context: CommandContext, body = '', isTodo = false) => {
const folderId = Setting.value('activeFolderId');
const folderId = await Folder.getValidActiveFolder();
if (!folderId) return;
const defaultValues = Note.previewFieldsWithDefaultValues({ includeTimestamps: false });

View File

@@ -2,7 +2,7 @@ import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/
import Logger from '@joplin/utils/Logger';
import goToNote, { GotoNoteOptions } from './util/goToNote';
import Note from '@joplin/lib/models/Note';
import Setting from '@joplin/lib/models/Setting';
import Folder from '@joplin/lib/models/Folder';
const logger = Logger.create('newNoteCommand');
@@ -13,7 +13,7 @@ export const declaration: CommandDeclaration = {
export const runtime = (): CommandRuntime => {
return {
execute: async (_context: CommandContext, body = '', todo = false, options: GotoNoteOptions = null) => {
const folderId = Setting.value('activeFolderId');
const folderId = await Folder.getValidActiveFolder();
if (!folderId) {
logger.warn('Not creating new note -- no active folder ID.');
return;

View File

@@ -3,6 +3,7 @@ import { FolderEntity } from '../services/database/types';
import { createNTestNotes, setupDatabaseAndSynchronizer, sleep, switchClient, checkThrowAsync, createFolderTree, simulateReadOnlyShareEnv, expectThrow, withWarningSilenced } from '../testing/test-utils';
import Folder from './Folder';
import Note from './Note';
import Setting from './Setting';
async function allItems() {
const folders = await Folder.all();
@@ -440,4 +441,40 @@ describe('models/Folder', () => {
expect(Folder.atLeastOneRealFolderExists(folders)).toBe(false);
});
it('should get active folder when activeFolderId is valid', async () => {
const activeFolder = await Folder.save({ title: 'folder' });
Setting.setValue('activeFolderId', activeFolder.id);
const validFolder = await Folder.getValidActiveFolder();
expect(validFolder).toBe(activeFolder.id);
});
it('should get default folder when activeFolderId is trashed', async () => {
const defaultFolder = await Folder.save({ title: 'default' });
const activeFolder = await Folder.save({ title: 'folder' });
await Folder.delete(activeFolder.id, { toTrash: true });
Setting.setValue('activeFolderId', activeFolder.id);
const validFolder = await Folder.getValidActiveFolder();
expect(validFolder).toBe(defaultFolder.id);
});
it('should get no folder when activeFolderId is undefined', async () => {
Setting.setValue('activeFolderId', undefined);
const validFolder = await Folder.getValidActiveFolder();
expect(validFolder).toBeNull();
});
it('should get no folder when activeFolderId is trashed and there are no other not trashed folders', async () => {
const activeFolder = await Folder.save({ title: 'folder' });
const otherFolder = await Folder.save({ title: 'other' });
await Folder.delete(activeFolder.id, { toTrash: true });
await Folder.delete(otherFolder.id, { toTrash: true });
Setting.setValue('activeFolderId', activeFolder.id);
const validFolder = await Folder.getValidActiveFolder();
expect(validFolder).toBeNull();
});
});

View File

@@ -18,6 +18,7 @@ import { getTrashFolder } from '../services/trash';
import getConflictFolderId from './utils/getConflictFolderId';
import getTrashFolderId from '../services/trash/getTrashFolderId';
import { getCollator } from './utils/getCollator';
import Setting from './Setting';
const { substrWithEllipsis } = require('../string-utils.js');
const logger = Logger.create('models/Folder');
@@ -918,7 +919,7 @@ export default class Folder extends BaseItem {
}
public static defaultFolder() {
return this.modelSelectOne('SELECT * FROM folders ORDER BY created_time DESC LIMIT 1');
return this.modelSelectOne('SELECT * FROM folders WHERE deleted_time = 0 ORDER BY created_time DESC LIMIT 1');
}
public static async canNestUnder(folderId: string, targetFolderId: string) {
@@ -1076,4 +1077,18 @@ export default class Folder extends BaseItem {
return this.getRealFolders(folders).length > 0;
}
public static async getValidActiveFolder() {
const folderId = Setting.value('activeFolderId');
if (!folderId) return null;
const folder = await Folder.load(folderId);
if (!folder || !!folder.deleted_time) {
const defaultFolder = await Folder.defaultFolder();
if (!defaultFolder) return null;
return defaultFolder.id;
}
return folderId;
}
}