1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-11 18:24:43 +02:00

Finished WebDAV driver

This commit is contained in:
Laurent Cozic 2018-01-23 20:10:20 +00:00
parent 7bee25599d
commit 5393a1399c
3 changed files with 65 additions and 88 deletions

View File

@ -34,10 +34,6 @@ class WebDavApi {
return this.baseUrl_;
}
davNs(json) {
}
async xmlToJson(xml) {
const nameProcessor = (name) => {
@ -56,7 +52,7 @@ class WebDavApi {
return new Promise((resolve, reject) => {
parseXmlString(xml, options, (error, result) => {
if (error) {
reject(error);
resolve(null); // Error handled by caller which will display the XML text (or plain text) if null is returned from this function
return;
}
resolve(result);
@ -87,36 +83,12 @@ class WebDavApi {
stringFromJson(json, keys) {
return this.valueFromJson(json, keys, 'string');
// let output = json;
// for (let i = 0; i < keys.length; i++) {
// const key = keys[i];
// if (!output || !output[key]) return null;
// output = output[key];
// }
// if (typeof output !== 'string') return null;
// return output;
}
objectFromJson(json, keys) {
return this.valueFromJson(json, keys, 'object');
// let output = json;
// for (let i = 0; i < keys.length; i++) {
// const key = keys[i];
// if (!output || !output[key]) return null;
// output = output[key];
// }
// if (!Array.isArray(output) && typeof output === 'object') return output;
// return null;
}
// isDirectory(propStat) {
// try {
// return propStat[0]['d:prop'][0]['d:resourcetype'][0]['d:collection'];
// } catch (error) {
// return false;
// }
// }
async execPropFind(path, fields = null) {
if (fields === null) fields = ['d:getlastmodified'];
@ -127,17 +99,17 @@ class WebDavApi {
// To find all available properties:
//
const body=`<?xml version="1.0" encoding="utf-8" ?>
<propfind xmlns="DAV:">
<propname/>
</propfind>`;
// const body=`<?xml version="1.0" encoding="utf-8" ?>
// <propfind xmlns="DAV:">
// <propname/>
// </propfind>`;
// const body = `<?xml version="1.0" encoding="UTF-8"?>
// <d:propfind xmlns:d="DAV:">
// <d:prop xmlns:oc="http://owncloud.org/ns">
// ` + fieldsXml + `
// </d:prop>
// </d:propfind>`;
const body = `<?xml version="1.0" encoding="UTF-8"?>
<d:propfind xmlns:d="DAV:">
<d:prop xmlns:oc="http://owncloud.org/ns">
` + fieldsXml + `
</d:prop>
</d:propfind>`;
return this.exec('PROPFIND', path, body);
}
@ -149,8 +121,11 @@ class WebDavApi {
// </d:prop>
// </d:propfind>'
async exec(method, path = '', body = null, headers = null) {
async exec(method, path = '', body = null, headers = null, options = null) {
if (headers === null) headers = {};
if (options === null) options = {};
if (!options.responseFormat) options.responseFormat = 'json';
if (!options.target) options.target = 'string';
const authToken = this.authToken();
@ -159,50 +134,50 @@ class WebDavApi {
const fetchOptions = {};
fetchOptions.headers = headers;
fetchOptions.method = method;
if (options.path) fetchOptions.path = options.path;
if (body) fetchOptions.body = body;
const url = this.baseUrl() + '/' + path;
const response = await shim.fetch(url, fetchOptions);
const responseText = await response.text();
const responseJson = await this.xmlToJson(responseText);
let response = null;
if (!responseJson) throw new Error('Could not parse response: ' + responseText);
if (responseJson['d:error']) {
const code = responseJson['d:error']['s:exception'] ? responseJson['d:error']['s:exception'].join(' ') : null;
const message = responseJson['d:error']['s:message'] ? responseJson['d:error']['s:message'].join("\n") : responseText;
throw new JoplinError(message, code);
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
response = await shim.uploadBlob(url, fetchOptions);
} else if (options.target == 'string') {
response = await shim.fetch(url, fetchOptions);
} else { // file
response = await shim.fetchBlob(url, fetchOptions);
}
return responseJson;
const responseText = await response.text();
let responseJson_ = null;
const loadResponseJson = async () => {
if (!responseText) return null;
if (responseJson_) return responseJson_;
responseJson_ = await this.xmlToJson(responseText);
if (!responseJson_) throw new JoplinError('Cannot parse JSON response: ' + responseText, response.status);
return responseJson_;
}
// //console.info(JSON.stringify(responseJson['d:multistatus']['d:response']));
if (!response.ok) {
// When using fetchBlob we only get a string (not xml or json) back
if (options.target === 'file') throw new JoplinError(responseText, response.status);
const json = await loadResponseJson();
// body = `<?xml version="1.0" encoding="UTF-8"?>
// <d:propfind xmlns:d="DAV:">
// <d:prop xmlns:oc="http://owncloud.org/ns">
// <d:getlastmodified/>
// </d:prop>
// </d:propfind>`;
if (json['d:error']) {
const code = json['d:error']['s:exception'] ? json['d:error']['s:exception'].join(' ') : response.status;
const message = json['d:error']['s:message'] ? json['d:error']['s:message'].join("\n") : responseText;
throw new JoplinError(message + ' (' + code + ')', response.status);
}
// const authToken = this.authToken();
// const url = 'http://nextcloud.local/remote.php/dav/files/admin/Joplin';
// const fetchOptions = {
// method: 'PROPFIND',
// headers: {
// 'Authorization': 'Basic ' + authToken,
// },
// body: body,
// };
throw new JoplinError(responseText, response.status);
}
if (options.responseFormat === 'text') return responseText;
// console.info(url, fetchOptions);
// const response = await shim.fetch(url, fetchOptions);
// console.info(await response.text());
return await loadResponseJson();
}
}

View File

@ -59,23 +59,37 @@ class FileApiDriverWebDav {
}
async get(path, options) {
if (!options) options = {};
if (!options.responseFormat) options.responseFormat = 'text';
try {
return await this.api().exec('GET', path, null, null, options);
} catch (error) {
if (error.code !== 404) throw error;
}
}
async mkdir(path) {
try {
await this.api().exec('MKCOL', path);
} catch (error) {
if (error.code !== 405) throw error; // 405 means that the collection already exists (Method Not Allowed)
}
}
async put(path, content, options = null) {
await this.api().exec('PUT', path, content, null, options);
}
async delete(path) {
try {
await this.api().exec('DELETE', path);
} catch (error) {
if (error.code !== 404) throw error;
}
}
async move(oldPath, newPath) {
throw new Error('Not implemented');
}
format() {

View File

@ -289,18 +289,6 @@ class Synchronizer {
}
if (action == 'createRemote' || action == 'updateRemote') {
// Make the operation atomic by doing the work on a copy of the file
// and then copying it back to the original location.
// let tempPath = this.syncDirName_ + '/' + path + '_' + time.unixMs();
//
// Atomic operation is disabled for now because it's not possible
// to do an atomic move with OneDrive (see file-api-driver-onedrive.js)
// await this.api().put(tempPath, content);
// await this.api().setTimestamp(tempPath, local.updated_time);
// await this.api().move(tempPath, path);
let canSync = true;
try {
if (this.testingHooks_.indexOf('rejectedByTarget') >= 0) throw new JoplinError('Testing rejectedByTarget', 'rejectedByTarget');