mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-21 23:43:15 +01:00
feat: bruno.json validation for local collections
This commit is contained in:
parent
8a96a0ce71
commit
ff87586a1d
@ -21,9 +21,9 @@ const useLocalCollectionTreeSync = () => {
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const _openCollection = (pathname, uid) => {
|
||||
console.log(`collection uid: ${uid}, pathname: ${pathname}`);
|
||||
dispatch(openLocalCollectionEvent(uid, pathname));
|
||||
const _openCollection = (pathname, uid, name) => {
|
||||
console.log(`collection uid: ${uid}, pathname: ${pathname}, name: ${name}`);
|
||||
dispatch(openLocalCollectionEvent(uid, pathname, name));
|
||||
};
|
||||
|
||||
const _collectionTreeUpdated = (type, val) => {
|
||||
@ -60,16 +60,22 @@ const useLocalCollectionTreeSync = () => {
|
||||
toast.success('Collection is already opened under local collections');
|
||||
};
|
||||
|
||||
const _displayError = (message) => {
|
||||
toast.error(message || 'Something went wrong!');
|
||||
};
|
||||
|
||||
ipcRenderer.invoke('renderer:ready');
|
||||
|
||||
const removeListener1 = ipcRenderer.on('main:collection-opened', _openCollection);
|
||||
const removeListener2 = ipcRenderer.on('main:collection-tree-updated', _collectionTreeUpdated);
|
||||
const removeListener3 = ipcRenderer.on('main:collection-already-opened', _collectionAlreadyOpened);
|
||||
const removeListener4 = ipcRenderer.on('main:display-error', _displayError);
|
||||
|
||||
return () => {
|
||||
removeListener1();
|
||||
removeListener2();
|
||||
removeListener3();
|
||||
removeListener4();
|
||||
};
|
||||
}, [isElectron]);
|
||||
};
|
||||
|
@ -57,11 +57,11 @@ export const loadCollectionsFromIdb = () => (dispatch) => {
|
||||
.catch(() => toast.error("Error occured while loading collections from IndexedDB"));
|
||||
};
|
||||
|
||||
export const openLocalCollectionEvent = (uid, pathname) => (dispatch, getState) => {
|
||||
export const openLocalCollectionEvent = (uid, pathname, name) => (dispatch, getState) => {
|
||||
const localCollection = {
|
||||
version: "1",
|
||||
uid: uid,
|
||||
name: path.basename(pathname),
|
||||
name: name,
|
||||
pathname: pathname,
|
||||
items: []
|
||||
};
|
||||
|
@ -22,7 +22,8 @@
|
||||
"fs-extra": "^10.1.0",
|
||||
"is-valid-path": "^0.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "3.3.4"
|
||||
"nanoid": "3.3.4",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^21.1.1",
|
||||
|
@ -1,8 +1,52 @@
|
||||
const { uuid } = require('../utils/common');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { dialog, ipcMain } = require('electron');
|
||||
const Yup = require('yup');
|
||||
const { isDirectory, normalizeAndResolvePath } = require('../utils/filesystem');
|
||||
|
||||
const openCollection = async (win, watcher) => {
|
||||
const uidSchema = Yup.string()
|
||||
.length(21, 'uid must be 21 characters in length')
|
||||
.matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric')
|
||||
.required('uid is required')
|
||||
.strict();
|
||||
|
||||
const configSchema = Yup.object({
|
||||
uid: uidSchema,
|
||||
name: Yup.string().nullable().max(256, 'name must be 256 characters or less'),
|
||||
type: Yup.string().oneOf(['collection']).required('type is required'),
|
||||
version: Yup.string().oneOf(['1']).required('type is required')
|
||||
}).noUnknown(true).strict();
|
||||
|
||||
const readConfigFile = async (pathname) => {
|
||||
try {
|
||||
const jsonData = fs.readFileSync(pathname, 'utf8');
|
||||
return JSON.parse(jsonData);
|
||||
} catch(err) {
|
||||
return Promise.reject(new Error("Unable to parse json in bruno.json"));
|
||||
}
|
||||
}
|
||||
|
||||
const validateSchema = async (config) => {
|
||||
try {
|
||||
await configSchema.validate(config);
|
||||
} catch(err) {
|
||||
return Promise.reject(new Error("bruno.json format is invalid"));
|
||||
}
|
||||
};
|
||||
|
||||
const getCollectionConfigFile = async (pathname) => {
|
||||
const configFilePath = path.join(pathname, 'bruno.json');
|
||||
if (!fs.existsSync(configFilePath)){
|
||||
throw new Error(`The collection is not valid (bruno.json not found)`);
|
||||
}
|
||||
|
||||
const config = await readConfigFile(configFilePath);
|
||||
await validateSchema(config);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
const openCollectionDialog = async (win, watcher) => {
|
||||
const { filePaths } = await dialog.showOpenDialog(win, {
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
});
|
||||
@ -10,19 +54,37 @@ const openCollection = async (win, watcher) => {
|
||||
if (filePaths && filePaths[0]) {
|
||||
const resolvedPath = normalizeAndResolvePath(filePaths[0]);
|
||||
if (isDirectory(resolvedPath)) {
|
||||
if(!watcher.hasWatcher(resolvedPath)) {
|
||||
const uid = uuid();
|
||||
win.webContents.send('main:collection-opened', resolvedPath, uid);
|
||||
ipcMain.emit('main:collection-opened', win, resolvedPath, uid);
|
||||
} else {
|
||||
win.webContents.send('main:collection-already-opened', resolvedPath);
|
||||
}
|
||||
openCollection(win, watcher, resolvedPath);
|
||||
} else {
|
||||
console.error(`[ERROR] Cannot open unknown folder: "${resolvedPath}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const openCollection = async (win, watcher, collectionPath, options = {}) => {
|
||||
if(!watcher.hasWatcher(collectionPath)) {
|
||||
try {
|
||||
const {
|
||||
uid,
|
||||
name
|
||||
} = await getCollectionConfigFile(collectionPath);
|
||||
|
||||
console.log(uid);
|
||||
console.log(name);
|
||||
|
||||
win.webContents.send('main:collection-opened', collectionPath, uid, name);
|
||||
ipcMain.emit('main:collection-opened', win, collectionPath, uid);
|
||||
} catch(err) {
|
||||
if(!options.dontSendDisplayErrors) {
|
||||
win.webContents.send('main:display-error', err.message || 'An error occured while opening the local collection');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
win.webContents.send('main:collection-already-opened', collectionPath);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
openCollection
|
||||
openCollection,
|
||||
openCollectionDialog
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ const {
|
||||
createDirectory
|
||||
} = require('../utils/filesystem');
|
||||
const { uuid, stringifyJson, parseJson } = require('../utils/common');
|
||||
const { openCollection } = require('../app/collections');
|
||||
const { openCollectionDialog, openCollection } = require('../app/collections');
|
||||
|
||||
const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
// browse directory
|
||||
@ -41,14 +41,14 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
|
||||
const uid = uuid();
|
||||
const content = await stringifyJson({
|
||||
version: '1.0',
|
||||
version: '1',
|
||||
uid: uid,
|
||||
name: collectionName,
|
||||
type: 'collection'
|
||||
});
|
||||
await writeFile(path.join(dirPath, 'bruno.json'), content);
|
||||
|
||||
mainWindow.webContents.send('main:collection-opened', dirPath, uid);
|
||||
mainWindow.webContents.send('main:collection-opened', dirPath, uid, collectionName);
|
||||
ipcMain.emit('main:collection-opened', mainWindow, dirPath, uid);
|
||||
|
||||
return;
|
||||
@ -149,7 +149,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
|
||||
ipcMain.handle('renderer:open-collection', () => {
|
||||
if(watcher && mainWindow) {
|
||||
openCollection(mainWindow, watcher);
|
||||
openCollectionDialog(mainWindow, watcher);
|
||||
}
|
||||
});
|
||||
|
||||
@ -168,9 +168,9 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
if(lastOpened && lastOpened.length) {
|
||||
for(let collectionPath of lastOpened) {
|
||||
if(isDirectory(collectionPath)) {
|
||||
const uid = uuid();
|
||||
mainWindow.webContents.send('main:collection-opened', collectionPath, uid);
|
||||
ipcMain.emit('main:collection-opened', mainWindow, collectionPath, uid);
|
||||
openCollection(mainWindow, watcher, collectionPath, {
|
||||
dontSendDisplayErrors: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,7 +180,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
const registerMainEventHandlers = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
ipcMain.on('main:open-collection', () => {
|
||||
if(watcher && mainWindow) {
|
||||
openCollection(mainWindow, watcher);
|
||||
openCollectionDialog(mainWindow, watcher);
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user