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:
parent
7bee25599d
commit
5393a1399c
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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');
|
||||
|
Loading…
Reference in New Issue
Block a user