1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-24 08:12:24 +02:00

Desktop: Fixes #4426: Improved handling of empty paths for Joplin Server sync target

This commit is contained in:
Laurent Cozic 2021-02-01 10:48:37 +00:00
parent a419e1eb7c
commit b1b5069a23
6 changed files with 40 additions and 50 deletions

View File

@ -552,7 +552,7 @@ async function initFileApi(suiteName: string) {
username: () => 'admin@localhost',
password: () => 'admin',
});
fileApi = new FileApi(`root:/Apps/Joplin-${suiteName}`, new FileApiDriverJoplinServer(api));
fileApi = new FileApi(`Apps/Joplin-${suiteName}`, new FileApiDriverJoplinServer(api));
}
fileApi.setLogger(logger);

View File

@ -31,6 +31,7 @@ export default class JoplinServerApi {
private options_: Options;
private session_: any;
private debugRequests_: boolean = false;
public constructor(options: Options) {
this.options_ = options;
@ -73,22 +74,22 @@ export default class JoplinServerApi {
return `${this.baseUrl()}/shares/${share.id}`;
}
// private requestToCurl_(url: string, options: any) {
// const output = [];
// output.push('curl');
// output.push('-v');
// if (options.method) output.push(`-X ${options.method}`);
// if (options.headers) {
// for (const n in options.headers) {
// if (!options.headers.hasOwnProperty(n)) continue;
// output.push(`${'-H ' + '"'}${n}: ${options.headers[n]}"`);
// }
// }
// if (options.body) output.push(`${'--data ' + '\''}${JSON.stringify(options.body)}'`);
// output.push(url);
private requestToCurl_(url: string, options: any) {
const output = [];
output.push('curl');
output.push('-v');
if (options.method) output.push(`-X ${options.method}`);
if (options.headers) {
for (const n in options.headers) {
if (!options.headers.hasOwnProperty(n)) continue;
output.push(`${'-H ' + '"'}${n}: ${options.headers[n]}"`);
}
}
if (options.body) output.push(`${'--data ' + '\''}${JSON.stringify(options.body)}'`);
output.push(url);
// return output.join(' ');
// }
return output.join(' ');
}
public async exec(method: string, path: string = '', query: Record<string, any> = null, body: any = null, headers: any = null, options: ExecOptions = null) {
if (headers === null) headers = {};
@ -128,8 +129,10 @@ export default class JoplinServerApi {
let response: any = null;
// console.info('Joplin API Call', `${method} ${url}`, headers, options);
// console.info(this.requestToCurl_(url, fetchOptions));
if (this.debugRequests_) {
console.info('Joplin API Call', `${method} ${url}`, headers, options);
console.info(this.requestToCurl_(url, fetchOptions));
}
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
if (fetchOptions.path) {

View File

@ -48,7 +48,7 @@ export default class SyncTargetJoplinServer extends BaseSyncTarget {
const api = new JoplinServerApi(apiOptions);
const driver = new FileApiDriverJoplinServer(api);
const fileApi = new FileApi(() => `root:/${options.directory()}`, driver);
const fileApi = new FileApi(options.directory, driver);
fileApi.setSyncTargetId(this.id());
await fileApi.initialize();
return fileApi;

View File

@ -1,16 +1,8 @@
import JoplinServerApi from './JoplinServerApi';
const { dirname, basename } = require('./path-utils');
import { trimSlashes, dirname, basename } from './path-utils';
function removeTrailingColon(path: string) {
if (!path || !path.length) return '';
if (path[path.length - 1] === ':') return path.substr(0, path.length - 1);
return path;
}
// All input paths should be in the format: "SPECIAL_DIR:/path/to/file"
// The trailing colon must not be included as it's automatically added
// when doing the API call.
// Only supported special dir at the moment is "root"
// All input paths should be in the format: "path/to/file". This is converted to
// "root:/path/to/file:" when doing the API call.
export default class FileApiDriverJoplinServer {
@ -21,19 +13,16 @@ export default class FileApiDriverJoplinServer {
}
public async initialize(basePath: string) {
const pieces = removeTrailingColon(basePath).split('/');
const pieces = trimSlashes(basePath).split('/');
if (!pieces.length) return;
let parent = pieces.splice(0, 1)[0];
const parent: string[] = [];
for (const p of pieces) {
// Syncing with the root, which is ok, and in that
// case there's no sub-dir to create.
if (!p && pieces.length === 1) return;
const subPath = `${parent}/${p}`;
for (let i = 0; i < pieces.length; i++) {
const p = pieces[i];
const subPath = parent.concat(p).join('/');
parent.push(p);
await this.mkdir(subPath);
parent = subPath;
}
}
@ -67,9 +56,10 @@ export default class FileApiDriverJoplinServer {
return output;
}
// Transforms a path such as "Apps/Joplin/file.txt" to a complete a complete
// API URL path: "api/files/root:/Apps/Joplin/file.txt:"
private apiFilePath_(p: string) {
if (p !== 'root') p += ':';
return `api/files/${p}`;
return `api/files/root:/${trimSlashes(p)}:`;
}
public async stat(path: string) {
@ -145,14 +135,7 @@ export default class FileApiDriverJoplinServer {
}
private parentPath_(path: string) {
let output = dirname(path);
// This is the root or a special folder
if (output.split('/').length === 1) {
output = output.substr(0, output.length - 1);
}
return output;
return dirname(path);
}
private basename_(path: string) {

View File

@ -138,6 +138,10 @@ export function ltrimSlashes(path: string) {
return path.replace(/^\/+/, '');
}
export function trimSlashes(path: string): string {
return ltrimSlashes(rtrimSlashes(path));
}
export function quotePath(path: string) {
if (!path) return '';
if (path.indexOf('"') < 0 && path.indexOf(' ') < 0) return path;

View File

@ -269,7 +269,7 @@ export default class FileModel extends BaseModel<File> {
}
if ('name' in file) {
if (this.includesReservedCharacter(file.name)) throw new ErrorUnprocessableEntity(`File name may not contain any of these characters: ${this.reservedCharacters.join('')}`);
if (this.includesReservedCharacter(file.name)) throw new ErrorUnprocessableEntity(`File name may not contain any of these characters: ${this.reservedCharacters.join('')}: ${file.name}`);
}
return file;