mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-26 18:58:21 +02:00
Finished WebDAV driver
This commit is contained in:
parent
7bee25599d
commit
5393a1399c
@ -34,10 +34,6 @@ class WebDavApi {
|
|||||||
return this.baseUrl_;
|
return this.baseUrl_;
|
||||||
}
|
}
|
||||||
|
|
||||||
davNs(json) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async xmlToJson(xml) {
|
async xmlToJson(xml) {
|
||||||
|
|
||||||
const nameProcessor = (name) => {
|
const nameProcessor = (name) => {
|
||||||
@ -56,7 +52,7 @@ class WebDavApi {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
parseXmlString(xml, options, (error, result) => {
|
parseXmlString(xml, options, (error, result) => {
|
||||||
if (error) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
@ -87,36 +83,12 @@ class WebDavApi {
|
|||||||
|
|
||||||
stringFromJson(json, keys) {
|
stringFromJson(json, keys) {
|
||||||
return this.valueFromJson(json, keys, 'string');
|
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) {
|
objectFromJson(json, keys) {
|
||||||
return this.valueFromJson(json, keys, 'object');
|
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) {
|
async execPropFind(path, fields = null) {
|
||||||
if (fields === null) fields = ['d:getlastmodified'];
|
if (fields === null) fields = ['d:getlastmodified'];
|
||||||
|
|
||||||
@ -127,17 +99,17 @@ class WebDavApi {
|
|||||||
|
|
||||||
// To find all available properties:
|
// To find all available properties:
|
||||||
//
|
//
|
||||||
const body=`<?xml version="1.0" encoding="utf-8" ?>
|
// const body=`<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<propfind xmlns="DAV:">
|
// <propfind xmlns="DAV:">
|
||||||
<propname/>
|
// <propname/>
|
||||||
</propfind>`;
|
// </propfind>`;
|
||||||
|
|
||||||
// const body = `<?xml version="1.0" encoding="UTF-8"?>
|
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
// <d:propfind xmlns:d="DAV:">
|
<d:propfind xmlns:d="DAV:">
|
||||||
// <d:prop xmlns:oc="http://owncloud.org/ns">
|
<d:prop xmlns:oc="http://owncloud.org/ns">
|
||||||
// ` + fieldsXml + `
|
` + fieldsXml + `
|
||||||
// </d:prop>
|
</d:prop>
|
||||||
// </d:propfind>`;
|
</d:propfind>`;
|
||||||
|
|
||||||
return this.exec('PROPFIND', path, body);
|
return this.exec('PROPFIND', path, body);
|
||||||
}
|
}
|
||||||
@ -149,8 +121,11 @@ class WebDavApi {
|
|||||||
// </d:prop>
|
// </d:prop>
|
||||||
// </d:propfind>'
|
// </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 (headers === null) headers = {};
|
||||||
|
if (options === null) options = {};
|
||||||
|
if (!options.responseFormat) options.responseFormat = 'json';
|
||||||
|
if (!options.target) options.target = 'string';
|
||||||
|
|
||||||
const authToken = this.authToken();
|
const authToken = this.authToken();
|
||||||
|
|
||||||
@ -159,50 +134,50 @@ class WebDavApi {
|
|||||||
const fetchOptions = {};
|
const fetchOptions = {};
|
||||||
fetchOptions.headers = headers;
|
fetchOptions.headers = headers;
|
||||||
fetchOptions.method = method;
|
fetchOptions.method = method;
|
||||||
|
if (options.path) fetchOptions.path = options.path;
|
||||||
if (body) fetchOptions.body = body;
|
if (body) fetchOptions.body = body;
|
||||||
|
|
||||||
const url = this.baseUrl() + '/' + path;
|
const url = this.baseUrl() + '/' + path;
|
||||||
|
|
||||||
const response = await shim.fetch(url, fetchOptions);
|
let response = null;
|
||||||
const responseText = await response.text();
|
|
||||||
const responseJson = await this.xmlToJson(responseText);
|
|
||||||
|
|
||||||
if (!responseJson) throw new Error('Could not parse response: ' + responseText);
|
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
|
||||||
|
response = await shim.uploadBlob(url, fetchOptions);
|
||||||
if (responseJson['d:error']) {
|
} else if (options.target == 'string') {
|
||||||
const code = responseJson['d:error']['s:exception'] ? responseJson['d:error']['s:exception'].join(' ') : null;
|
response = await shim.fetch(url, fetchOptions);
|
||||||
const message = responseJson['d:error']['s:message'] ? responseJson['d:error']['s:message'].join("\n") : responseText;
|
} else { // file
|
||||||
throw new JoplinError(message, code);
|
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"?>
|
if (json['d:error']) {
|
||||||
// <d:propfind xmlns:d="DAV:">
|
const code = json['d:error']['s:exception'] ? json['d:error']['s:exception'].join(' ') : response.status;
|
||||||
// <d:prop xmlns:oc="http://owncloud.org/ns">
|
const message = json['d:error']['s:message'] ? json['d:error']['s:message'].join("\n") : responseText;
|
||||||
// <d:getlastmodified/>
|
throw new JoplinError(message + ' (' + code + ')', response.status);
|
||||||
// </d:prop>
|
}
|
||||||
// </d:propfind>`;
|
|
||||||
|
|
||||||
// const authToken = this.authToken();
|
throw new JoplinError(responseText, response.status);
|
||||||
// const url = 'http://nextcloud.local/remote.php/dav/files/admin/Joplin';
|
}
|
||||||
// const fetchOptions = {
|
|
||||||
// method: 'PROPFIND',
|
if (options.responseFormat === 'text') return responseText;
|
||||||
// headers: {
|
|
||||||
// 'Authorization': 'Basic ' + authToken,
|
|
||||||
// },
|
|
||||||
// body: body,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// console.info(url, fetchOptions);
|
return await loadResponseJson();
|
||||||
|
|
||||||
// const response = await shim.fetch(url, fetchOptions);
|
|
||||||
|
|
||||||
// console.info(await response.text());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -59,23 +59,37 @@ class FileApiDriverWebDav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async get(path, options) {
|
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) {
|
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) {
|
async put(path, content, options = null) {
|
||||||
|
await this.api().exec('PUT', path, content, null, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(path) {
|
async delete(path) {
|
||||||
|
try {
|
||||||
|
await this.api().exec('DELETE', path);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 404) throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async move(oldPath, newPath) {
|
async move(oldPath, newPath) {
|
||||||
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
format() {
|
format() {
|
||||||
|
@ -289,18 +289,6 @@ class Synchronizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == 'createRemote' || action == 'updateRemote') {
|
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;
|
let canSync = true;
|
||||||
try {
|
try {
|
||||||
if (this.testingHooks_.indexOf('rejectedByTarget') >= 0) throw new JoplinError('Testing rejectedByTarget', 'rejectedByTarget');
|
if (this.testingHooks_.indexOf('rejectedByTarget') >= 0) throw new JoplinError('Testing rejectedByTarget', 'rejectedByTarget');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user