1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-07-13 00:10:37 +02:00

Desktop: Resolves #591: Add support for multiple profiles (#6385)

This commit is contained in:
Laurent
2022-04-11 16:49:32 +01:00
committed by GitHub
parent 58bf93a112
commit 6458ad0540
32 changed files with 919 additions and 154 deletions

View File

@ -1,12 +1,28 @@
import Setting, { SettingSectionSource } from '../models/Setting';
import Setting, { SettingSectionSource, SettingStorage } from '../models/Setting';
import { setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow, msleep } from '../testing/test-utils';
import * as fs from 'fs-extra';
import { readFile, stat, mkdirp, writeFile, pathExists, readdir } from 'fs-extra';
import Logger from '../Logger';
import { defaultProfileConfig } from '../services/profileConfig/types';
import { createNewProfile, saveProfileConfig } from '../services/profileConfig';
import initProfile from '../services/profileConfig/initProfile';
async function loadSettingsFromFile(): Promise<any> {
return JSON.parse(await fs.readFile(Setting.settingFilePath, 'utf8'));
return JSON.parse(await readFile(Setting.settingFilePath, 'utf8'));
}
const switchToSubProfileSettings = async () => {
await Setting.reset();
const rootProfileDir = Setting.value('profileDir');
const profileConfigPath = `${rootProfileDir}/profiles.json`;
let profileConfig = defaultProfileConfig();
profileConfig = createNewProfile(profileConfig, 'Sub-profile');
profileConfig.currentProfile = 1;
await saveProfileConfig(profileConfigPath, profileConfig);
const { profileDir } = await initProfile(rootProfileDir);
await mkdirp(profileDir);
await Setting.load();
};
describe('models/Setting', function() {
beforeEach(async (done) => {
@ -180,19 +196,19 @@ describe('models/Setting', function() {
{
// Double-check that timestamp is indeed changed when the content is
// changed.
const beforeStat = await fs.stat(Setting.settingFilePath);
const beforeStat = await stat(Setting.settingFilePath);
await msleep(1001);
Setting.setValue('sync.mobileWifiOnly', false);
await Setting.saveAll();
const afterStat = await fs.stat(Setting.settingFilePath);
const afterStat = await stat(Setting.settingFilePath);
expect(afterStat.mtime.getTime()).toBeGreaterThan(beforeStat.mtime.getTime());
}
{
const beforeStat = await fs.stat(Setting.settingFilePath);
const beforeStat = await stat(Setting.settingFilePath);
await msleep(1001);
Setting.setValue('sync.mobileWifiOnly', false);
const afterStat = await fs.stat(Setting.settingFilePath);
const afterStat = await stat(Setting.settingFilePath);
await Setting.saveAll();
expect(afterStat.mtime.getTime()).toBe(beforeStat.mtime.getTime());
}
@ -200,7 +216,7 @@ describe('models/Setting', function() {
it('should handle invalid JSON', (async () => {
const badContent = '{ oopsIforgotTheQuotes: true}';
await fs.writeFile(Setting.settingFilePath, badContent, 'utf8');
await writeFile(Setting.settingFilePath, badContent, 'utf8');
await Setting.reset();
Logger.globalLogger.enabled = false;
@ -208,12 +224,12 @@ describe('models/Setting', function() {
Logger.globalLogger.enabled = true;
// Invalid JSON file has been moved to .bak file
expect(await fs.pathExists(Setting.settingFilePath)).toBe(false);
expect(await pathExists(Setting.settingFilePath)).toBe(false);
const files = await fs.readdir(Setting.value('profileDir'));
const files = await readdir(Setting.value('profileDir'));
expect(files.length).toBe(1);
expect(files[0].endsWith('.bak')).toBe(true);
expect(await fs.readFile(`${Setting.value('profileDir')}/${files[0]}`, 'utf8')).toBe(badContent);
expect(await readFile(`${Setting.value('profileDir')}/${files[0]}`, 'utf8')).toBe(badContent);
}));
it('should allow applying default migrations', (async () => {
@ -256,4 +272,67 @@ describe('models/Setting', function() {
expect(Setting.value('style.editor.contentMaxWidth')).toBe(600); // Changed
}));
it('should load sub-profile settings', async () => {
await Setting.reset();
Setting.setValue('locale', 'fr_FR'); // Global setting
Setting.setValue('theme', Setting.THEME_DARK); // Global setting
Setting.setValue('sync.target', 9); // Local setting
await Setting.saveAll();
await switchToSubProfileSettings();
expect(Setting.value('locale')).toBe('fr_FR'); // Should come from the root profile
expect(Setting.value('theme')).toBe(Setting.THEME_DARK); // Should come from the root profile
expect(Setting.value('sync.target')).toBe(0); // Should come from the local profile
// Also check that the special loadOne() function works as expected
expect((await Setting.loadOne('locale')).value).toBe('fr_FR');
expect((await Setting.loadOne('theme')).value).toBe(Setting.THEME_DARK);
expect((await Setting.loadOne('sync.target')).value).toBe(undefined);
});
it('should save sub-profile settings', async () => {
await Setting.reset();
Setting.setValue('locale', 'fr_FR'); // Global setting
Setting.setValue('theme', Setting.THEME_DARK); // Global setting
await Setting.saveAll();
await switchToSubProfileSettings();
Setting.setValue('locale', 'en_GB'); // Should be saved to global
Setting.setValue('sync.target', 8); // Should be saved to local
await Setting.saveAll();
await Setting.reset();
await Setting.load();
expect(Setting.value('locale')).toBe('en_GB');
expect(Setting.value('theme')).toBe(Setting.THEME_DARK);
expect(Setting.value('sync.target')).toBe(8);
// Double-check that actual file content is correct
const globalSettings = JSON.parse(await readFile(`${Setting.value('rootProfileDir')}/settings-1.json`, 'utf8'));
const localSettings = JSON.parse(await readFile(`${Setting.value('profileDir')}/settings-1.json`, 'utf8'));
expect(globalSettings).toEqual({
'$schema': 'https://joplinapp.org/schema/settings.json',
locale: 'en_GB',
theme: 2,
});
expect(localSettings).toEqual({
'$schema': 'https://joplinapp.org/schema/settings.json',
'sync.target': 8,
});
});
it('all global settings should be saved to file', async () => {
for (const [k, v] of Object.entries(Setting.metadata())) {
if (v.isGlobal && v.storage !== SettingStorage.File) throw new Error(`Setting "${k}" is global but storage is not "file"`);
}
});
});