mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-01-22 18:29:26 +00:00
feature: cloudcmd: readonly (#405)
This commit is contained in:
parent
1d3567f3a3
commit
c710b29d6c
11 changed files with 108 additions and 3 deletions
2
HELP.md
2
HELP.md
|
|
@ -88,6 +88,7 @@ Cloud Commander supports the following command-line parameters:
|
|||
| `--config-auth` | enable auth change in config dialog
|
||||
| `--console` | enable console
|
||||
| `--sync-console-path` | sync console path
|
||||
| `--readonly` | disable ui related to filesystem modifications
|
||||
| `--terminal` | enable terminal
|
||||
| `--terminal-path` | set terminal path
|
||||
| `--terminal-command` | set command to run in terminal (shell by default)
|
||||
|
|
@ -403,6 +404,7 @@ Here's a description of all options:
|
|||
"configAuth": true, // enable auth change in config dialog
|
||||
"console": true, // enable console
|
||||
"syncConsolePath": false, // do not sync console path
|
||||
"readonly": false, // disable ui related to filesystem modifications
|
||||
"terminal": false, // disable terminal
|
||||
"terminalPath": "", // path of a terminal
|
||||
"terminalCommand": "", // set command to run in terminal
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ const yargsOptions = {
|
|||
'config-auth',
|
||||
'console',
|
||||
'sync-console-path',
|
||||
'readonly',
|
||||
'contact',
|
||||
'terminal',
|
||||
'terminal-auto-restart',
|
||||
|
|
@ -105,6 +106,7 @@ const yargsOptions = {
|
|||
'port': config('port'),
|
||||
'online': config('online'),
|
||||
'open': choose(env.bool('open'), config('open')),
|
||||
'readonly': env.bool('readonly') || config('readonly'),
|
||||
'editor': env('editor') || config('editor'),
|
||||
'packer': config('packer') || 'tar',
|
||||
'zip': config('zip'),
|
||||
|
|
@ -205,6 +207,8 @@ async function main() {
|
|||
config('configDialog', args.configDialog);
|
||||
config('configAuth', args.configAuth);
|
||||
config('keysPanel', args.keysPanel);
|
||||
config('readonly', args.readonly);
|
||||
|
||||
config('export', args.export);
|
||||
config('exportToken', args.exportToken);
|
||||
config('import', args.import);
|
||||
|
|
|
|||
|
|
@ -169,10 +169,10 @@ function getFileMenuData() {
|
|||
},
|
||||
};
|
||||
|
||||
const menuDataFile = {
|
||||
const menuDataFile = maybeReadonly({
|
||||
...menuTop,
|
||||
...menuBottom,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
isAuth,
|
||||
|
|
@ -180,6 +180,28 @@ function getFileMenuData() {
|
|||
};
|
||||
}
|
||||
|
||||
function maybeReadonly(menu) {
|
||||
const operations = [
|
||||
'Edit',
|
||||
'Rename',
|
||||
'Delete',
|
||||
'Pack',
|
||||
'Extract',
|
||||
'Cut',
|
||||
'Copy',
|
||||
'Paste',
|
||||
'New',
|
||||
'Upload',
|
||||
'Upload From Cloud',
|
||||
];
|
||||
|
||||
for (const operation of operations) {
|
||||
delete menu[operation];
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
function isCurrent(yesFn, noFn) {
|
||||
if (Info.name !== '..')
|
||||
return yesFn();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ const noFilesCheck = () => {
|
|||
};
|
||||
|
||||
module.exports.init = promisify((callback) => {
|
||||
if (config('readonly'))
|
||||
return;
|
||||
|
||||
showLoad();
|
||||
|
||||
exec.series([
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"root": "/",
|
||||
"prefix": "",
|
||||
"prefixSocket": "",
|
||||
"readonly": false,
|
||||
"contact": true,
|
||||
"confirmCopy": true,
|
||||
"confirmMove": true,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ const html = fs.readFileSync(getIndexPath(isDev), 'utf8');
|
|||
const initAuth = currify(_initAuth);
|
||||
const notEmpty = (a) => a;
|
||||
const clean = (a) => a.filter(notEmpty);
|
||||
const createReadonly = (config) => () => config('readonly');
|
||||
|
||||
const isUndefined = (a) => typeof a === 'undefined';
|
||||
const isFn = (a) => typeof a === 'function';
|
||||
|
|
@ -131,6 +132,7 @@ function _initAuth(config, accept, reject, username, password) {
|
|||
function listen({prefixSocket, socket, config}) {
|
||||
const root = apart(config, 'root');
|
||||
const auth = initAuth(config);
|
||||
const readonly = createReadonly(config);
|
||||
|
||||
prefixSocket = getPrefix(prefixSocket);
|
||||
config.listen(socket, auth);
|
||||
|
|
@ -138,18 +140,21 @@ function listen({prefixSocket, socket, config}) {
|
|||
edward.listen(socket, {
|
||||
root,
|
||||
auth,
|
||||
readonly,
|
||||
prefixSocket: `${prefixSocket}/edward`,
|
||||
});
|
||||
|
||||
dword.listen(socket, {
|
||||
root,
|
||||
auth,
|
||||
readonly,
|
||||
prefixSocket: `${prefixSocket}/dword`,
|
||||
});
|
||||
|
||||
deepword.listen(socket, {
|
||||
root,
|
||||
auth,
|
||||
readonly,
|
||||
prefixSocket: `${prefixSocket}/deepword`,
|
||||
});
|
||||
|
||||
|
|
@ -161,6 +166,7 @@ function listen({prefixSocket, socket, config}) {
|
|||
fileop.listen(socket, {
|
||||
root,
|
||||
auth,
|
||||
readonly,
|
||||
prefix: `${prefixSocket}/fileop`,
|
||||
});
|
||||
|
||||
|
|
@ -180,6 +186,7 @@ function cloudcmd({modules, config}) {
|
|||
const diff = apart(config, 'diff');
|
||||
const zip = apart(config, 'zip');
|
||||
const root = apart(config, 'root');
|
||||
const readonly = createReadonly(config);
|
||||
|
||||
const ponseStatic = ponse.static({
|
||||
cache,
|
||||
|
|
@ -201,6 +208,7 @@ function cloudcmd({modules, config}) {
|
|||
zip,
|
||||
dropbox,
|
||||
dropboxToken,
|
||||
readonly,
|
||||
}),
|
||||
dword({
|
||||
root,
|
||||
|
|
@ -209,6 +217,7 @@ function cloudcmd({modules, config}) {
|
|||
zip,
|
||||
dropbox,
|
||||
dropboxToken,
|
||||
readonly,
|
||||
}),
|
||||
deepword({
|
||||
root,
|
||||
|
|
@ -217,6 +226,7 @@ function cloudcmd({modules, config}) {
|
|||
zip,
|
||||
dropbox,
|
||||
dropboxToken,
|
||||
readonly,
|
||||
}),
|
||||
fileop(),
|
||||
nomine(),
|
||||
|
|
@ -233,6 +243,7 @@ function cloudcmd({modules, config}) {
|
|||
}),
|
||||
restafary({
|
||||
prefix: cloudfunc.apiURL + '/fs',
|
||||
readonly,
|
||||
root,
|
||||
}),
|
||||
userMenu({
|
||||
|
|
|
|||
|
|
@ -188,6 +188,9 @@ module.exports._onPUT = onPUT;
|
|||
function onPUT({name, config, body}, callback) {
|
||||
checkPut(name, body, callback);
|
||||
|
||||
if (config('readonly'))
|
||||
callback(UserError('"readonly" mode enabled'));
|
||||
|
||||
const cmd = getCMD(name);
|
||||
const files = json.parse(body);
|
||||
const rootDir = config('root');
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ async function route({config, options, request, response}) {
|
|||
* additional processing of index file
|
||||
*/
|
||||
function indexProcessing(config, options) {
|
||||
const readonly = config('readonly');
|
||||
const oneFilePanel = config('oneFilePanel');
|
||||
const noKeysPanel = !config('keysPanel');
|
||||
const noContact = !config('contact');
|
||||
|
|
@ -124,10 +125,18 @@ function indexProcessing(config, options) {
|
|||
if (noKeysPanel)
|
||||
data = hideKeysPanel(data);
|
||||
|
||||
if (oneFilePanel)
|
||||
if (readonly) {
|
||||
data = data
|
||||
.replace('icon-move', 'icon-move none')
|
||||
.replace('icon-copy', 'icon-copy none')
|
||||
.replace('icon-edit', 'icon-edit none')
|
||||
.replace('icon-directory', 'icon-directory none')
|
||||
.replace('icon-delete', 'icon-delete none');
|
||||
} else if (oneFilePanel) {
|
||||
data = data
|
||||
.replace('icon-move', 'icon-move none')
|
||||
.replace('icon-copy', 'icon-copy none');
|
||||
}
|
||||
|
||||
if (noContact)
|
||||
data = data.replace('icon-contact', 'icon-contact none');
|
||||
|
|
|
|||
|
|
@ -166,6 +166,23 @@ test('cloudcmd: route: keys panel', async (t) => {
|
|||
t.end();
|
||||
});
|
||||
|
||||
test('cloudcmd: route: readonly', async (t) => {
|
||||
const config = {
|
||||
readonly: true,
|
||||
};
|
||||
|
||||
const options = {
|
||||
config,
|
||||
};
|
||||
|
||||
const {body} = await request.get('/', {
|
||||
options,
|
||||
});
|
||||
|
||||
t.match(body, 'icon-edit none', 'should hide edit');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('cloudcmd: route: symlink', async (t) => {
|
||||
const emptyDir = path.join(fixtureDir, 'empty-dir');
|
||||
const root = fixtureDir;
|
||||
|
|
|
|||
|
|
@ -113,3 +113,30 @@ test('cloudcmd: rest: move: no to', async (t) => {
|
|||
t.equal(body, expected);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('cloudcmd: rest: readonly', async (t) => {
|
||||
const cloudcmd = reRequire(cloudcmdPath);
|
||||
const {createConfigManager} = cloudcmd;
|
||||
|
||||
const configManager = createConfigManager();
|
||||
configManager('auth', false);
|
||||
configManager('root', '/');
|
||||
configManager('readonly', true);
|
||||
|
||||
const {request} = serveOnce(cloudcmd, {
|
||||
configManager,
|
||||
});
|
||||
|
||||
const files = {
|
||||
from: '/',
|
||||
};
|
||||
|
||||
const {body} = await request.put(`/api/v1/move`, {
|
||||
body: files,
|
||||
});
|
||||
|
||||
const expected = '"readonly" mode enabled';
|
||||
|
||||
t.equal(body, expected);
|
||||
t.end();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -147,6 +147,12 @@
|
|||
Confirm Move
|
||||
</label>
|
||||
</li>
|
||||
<li title="Readonly">
|
||||
<label>
|
||||
<input data-name="js-readonly" type="checkbox" {{ readonly }}>
|
||||
Readonly
|
||||
</label>
|
||||
</li>
|
||||
<li title="Synchronize path of current directory with Console">
|
||||
<label>
|
||||
<input data-name="js-syncConsolePath" type="checkbox" {{ syncConsolePath }}>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue