1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-26 22:41:17 +02:00

All: Improved WebDAV driver compatibility with some services (eg. Seafile)

This commit is contained in:
Laurent Cozic
2018-02-14 19:08:07 +00:00
parent 214a39c3d3
commit 1871123066
8 changed files with 77 additions and 16 deletions

View File

@@ -244,7 +244,7 @@ The following commands are available in [command-line mode](#command-line-mode):
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: "HH:mm"
uncompletedTodosOnTop Show uncompleted todos on top of the lists.
uncompletedTodosOnTop Show uncompleted to-dos on top of the lists.
Type: bool.
Default: true

View File

@@ -133,6 +133,42 @@ class WebDavApi {
return this.valueFromJson(json, keys, 'array');
}
resourcePropByName(resource, outputType, propName) {
const propStats = resource['d:propstat'];
let output = null;
if (!Array.isArray(propStats)) throw new Error('Missing d:propstat property');
for (let i = 0; i < propStats.length; i++) {
const props = propStats[i]['d:prop'];
if (!Array.isArray(props) || !props.length) continue;
const prop = props[0];
if (Array.isArray(prop[propName])) {
output = prop[propName];
break;
}
}
if (outputType === 'string') {
// If the XML has not attribute the value is directly a string
// If the XML node has attributes, the value is under "_".
// Eg for this XML, the string will be under {"_":"Thu, 01 Feb 2018 17:24:05 GMT"}:
// <a:getlastmodified b:dt="dateTime.rfc1123">Thu, 01 Feb 2018 17:24:05 GMT</a:getlastmodified>
// For this XML, the value will be "Thu, 01 Feb 2018 17:24:05 GMT"
// <a:getlastmodified>Thu, 01 Feb 2018 17:24:05 GMT</a:getlastmodified>
output = output[0];
if (typeof output === 'object' && '_' in output) output = output['_'];
if (typeof output !== 'string') return null;
return output;
}
if (outputType === 'array') {
return output;
}
throw new Error('Invalid output type: ' + outputType);
}
async execPropFind(path, depth, fields = null, options = null) {
if (fields === null) fields = ['d:getlastmodified'];

View File

@@ -65,6 +65,11 @@ class ConfigScreenComponent extends BaseScreenComponent {
fontSize: theme.fontSize,
flex: 1,
},
descriptionText: {
color: theme.color,
fontSize: theme.fontSize,
flex: 1,
},
settingControl: {
color: theme.color,
flex: 1,
@@ -181,8 +186,8 @@ class ConfigScreenComponent extends BaseScreenComponent {
const messages = shared.checkSyncConfigMessages(this);
const statusComp = !messages.length ? null : (
<View style={{flex:1, marginTop: 10}}>
<Text>{messages[0]}</Text>
{messages.length >= 1 ? (<Text style={{marginTop:10}}>{messages[1]}</Text>) : null}
<Text style={this.styles().descriptionText}>{messages[0]}</Text>
{messages.length >= 1 ? (<View style={{marginTop:10}}><Text style={this.styles().descriptionText}>{messages[1]}</Text></View>) : null}
</View>);
settingComps.push(

View File

@@ -27,7 +27,7 @@ class FileApiDriverWebDav {
const result = await this.api().execPropFind(path, 0, [
'd:getlastmodified',
'd:resourcetype',
'd:getcontentlength', // Remove this once PUT call issue is sorted out
// 'd:getcontentlength', // Remove this once PUT call issue is sorted out
]);
const resource = this.api().objectFromJson(result, ['d:multistatus', 'd:response', 0]);
@@ -39,22 +39,40 @@ class FileApiDriverWebDav {
}
statFromResource_(resource, path) {
const isCollection = this.api().stringFromJson(resource, ['d:propstat', 0, 'd:prop', 0, 'd:resourcetype', 0, 'd:collection', 0]);
const lastModifiedString = this.api().stringFromJson(resource, ['d:propstat', 0, 'd:prop', 0, 'd:getlastmodified', 0]);
// WebDAV implementations are always slighly different from one server to another but, at the minimum,
// a resource should have a propstat key - if not it's probably an error.
const propStat = this.api().arrayFromJson(resource, ['d:propstat']);
if (!Array.isArray(propStat)) throw new Error('Invalid WebDAV resource format: ' + JSON.stringify(resource));
const resourceTypes = this.api().resourcePropByName(resource, 'array', 'd:resourcetype');
let isDir = false;
if (Array.isArray(resourceTypes)) {
for (let i = 0; i < resourceTypes.length; i++) {
const t = resourceTypes[i];
if (typeof t === 'object' && 'd:collection' in t) {
isDir = true;
break;
}
}
}
const lastModifiedString = this.api().resourcePropByName(resource, 'string', 'd:getlastmodified');
// const sizeDONOTUSE = Number(this.api().stringFromJson(resource, ['d:propstat', 0, 'd:prop', 0, 'd:getcontentlength', 0]));
// if (isNaN(sizeDONOTUSE)) throw new Error('Cannot get content size: ' + JSON.stringify(resource));
if (!lastModifiedString) throw new Error('Could not get lastModified date: ' + JSON.stringify(resource));
const lastModifiedDate = new Date(lastModifiedString);
// Note: Not all WebDAV servers return a getlastmodified date (eg. Seafile, which doesn't return the
// property for folders) so we can only throw an error if it's a file.
if (!lastModifiedString && !isDir) throw new Error('Could not get lastModified date for resource: ' + JSON.stringify(resource));
const lastModifiedDate = lastModifiedString ? new Date(lastModifiedString) : new Date();
if (isNaN(lastModifiedDate.getTime())) throw new Error('Invalid date: ' + lastModifiedString);
return {
path: path,
// created_time: lastModifiedDate.getTime(),
updated_time: lastModifiedDate.getTime(),
isDir: isCollection === '',
isDir: isDir,
// sizeDONOTUSE: sizeDONOTUSE, // This property is used only for the WebDAV PUT hack (see below) so mark it as such so that it can be removed with the hack later on.
};
}
@@ -260,7 +278,7 @@ class FileApiDriverWebDav {
]);
const resources = this.api().arrayFromJson(result, ['d:multistatus', 'd:response']);
const stats = this.statsFromResources_(resources)
const stats = this.statsFromResources_(resources);
return {
items: stats,

View File

@@ -58,7 +58,7 @@ class Setting extends BaseModel {
// recent: _('Non-completed and recently completed ones'),
// nonCompleted: _('Non-completed ones only'),
// })},
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Show uncompleted todos on top of the lists') },
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Show uncompleted to-dos on top of the lists') },
'trackLocation': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Save geo-location with notes') },
'newTodoFocus': { value: 'title', type: Setting.TYPE_STRING, isEnum: true, public: true, appTypes: ['desktop'], label: () => _('When creating a new to-do:'), options: () => {
return {

View File

@@ -391,14 +391,14 @@ $$
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/hr.png" alt=""></td>
<td>Croatian</td>
<td>hr_HR</td>
<td>Hrvoje Mandić <a href="&#x6d;&#97;&#105;&#x6c;&#x74;&#111;&#58;&#x74;&#x72;&#98;&#x75;&#x68;&#111;&#x6d;&#64;&#x6e;&#101;&#x74;&#x2e;&#104;&#114;">&#x74;&#x72;&#98;&#x75;&#x68;&#111;&#x6d;&#64;&#x6e;&#101;&#x74;&#x2e;&#104;&#114;</a></td>
<td>Hrvoje Mandić <a href="&#109;&#x61;&#105;&#108;&#116;&#x6f;&#58;&#x74;&#114;&#x62;&#x75;&#104;&#x6f;&#x6d;&#x40;&#x6e;&#101;&#x74;&#46;&#104;&#x72;">&#x74;&#114;&#x62;&#x75;&#104;&#x6f;&#x6d;&#x40;&#x6e;&#101;&#x74;&#46;&#104;&#x72;</a></td>
<td>72%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/de.png" alt=""></td>
<td>Deutsch</td>
<td>de_DE</td>
<td>Tobias Strobel <a href="&#109;&#x61;&#105;&#x6c;&#x74;&#x6f;&#58;&#x67;&#x69;&#x74;&#64;&#115;&#x74;&#114;&#111;&#98;&#101;&#x6c;&#x74;&#111;&#98;&#x69;&#x61;&#115;&#x2e;&#x64;&#101;">&#x67;&#x69;&#x74;&#64;&#115;&#x74;&#114;&#111;&#98;&#101;&#x6c;&#x74;&#111;&#98;&#x69;&#x61;&#115;&#x2e;&#x64;&#101;</a></td>
<td>Tobias Strobel <a href="&#x6d;&#x61;&#105;&#108;&#x74;&#x6f;&#x3a;&#x67;&#x69;&#x74;&#x40;&#x73;&#x74;&#x72;&#111;&#x62;&#x65;&#108;&#116;&#x6f;&#x62;&#105;&#x61;&#115;&#46;&#100;&#101;">&#x67;&#x69;&#x74;&#x40;&#x73;&#x74;&#x72;&#111;&#x62;&#x65;&#108;&#116;&#x6f;&#x62;&#105;&#x61;&#115;&#46;&#100;&#101;</a></td>
<td>91%</td>
</tr>
<tr>
@@ -454,14 +454,14 @@ $$
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/ru.png" alt=""></td>
<td>Русский</td>
<td>ru_RU</td>
<td>Artyom Karlov <a href="&#109;&#x61;&#105;&#x6c;&#116;&#111;&#x3a;&#x61;&#114;&#x74;&#121;&#111;&#x6d;&#46;&#107;&#97;&#114;&#x6c;&#111;&#x76;&#64;&#x67;&#x6d;&#x61;&#105;&#x6c;&#46;&#99;&#x6f;&#109;">&#x61;&#114;&#x74;&#121;&#111;&#x6d;&#46;&#107;&#97;&#114;&#x6c;&#111;&#x76;&#64;&#x67;&#x6d;&#x61;&#105;&#x6c;&#46;&#99;&#x6f;&#109;</a></td>
<td>Artyom Karlov <a href="&#109;&#x61;&#105;&#x6c;&#116;&#111;&#58;&#97;&#x72;&#116;&#121;&#x6f;&#109;&#x2e;&#107;&#97;&#114;&#x6c;&#111;&#118;&#x40;&#x67;&#109;&#x61;&#x69;&#x6c;&#x2e;&#99;&#111;&#x6d;">&#97;&#x72;&#116;&#121;&#x6f;&#109;&#x2e;&#107;&#97;&#114;&#x6c;&#111;&#118;&#x40;&#x67;&#109;&#x61;&#x69;&#x6c;&#x2e;&#99;&#111;&#x6d;</a></td>
<td>94%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/cn.png" alt=""></td>
<td>中文 (简体)</td>
<td>zh_CN</td>
<td>RCJacH <a href="&#109;&#x61;&#105;&#108;&#116;&#x6f;&#x3a;&#x52;&#67;&#74;&#x61;&#x63;&#x48;&#x40;&#111;&#117;&#x74;&#x6c;&#x6f;&#x6f;&#x6b;&#x2e;&#x63;&#x6f;&#109;">&#x52;&#67;&#74;&#x61;&#x63;&#x48;&#x40;&#111;&#117;&#x74;&#x6c;&#x6f;&#x6f;&#x6b;&#x2e;&#x63;&#x6f;&#109;</a></td>
<td>RCJacH <a href="&#x6d;&#97;&#105;&#x6c;&#116;&#111;&#x3a;&#82;&#x43;&#x4a;&#97;&#99;&#72;&#64;&#x6f;&#117;&#x74;&#108;&#x6f;&#111;&#x6b;&#46;&#x63;&#111;&#x6d;">&#82;&#x43;&#x4a;&#97;&#99;&#72;&#64;&#x6f;&#117;&#x74;&#108;&#x6f;&#111;&#x6b;&#46;&#x63;&#111;&#x6d;</a></td>
<td>75%</td>
</tr>
<tr>

View File

@@ -395,7 +395,7 @@ Possible keys/values:
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: &quot;HH:mm&quot;
uncompletedTodosOnTop Show uncompleted todos on top of the lists.
uncompletedTodosOnTop Show uncompleted to-dos on top of the lists.
Type: bool.
Default: true

View File

@@ -18,6 +18,8 @@
"*.min.js",
"ElectronClient/app/gui/note-viewer/highlight/*.pack.js",
"ElectronClient/app/css/font-awesome.min.css",
"docs/*.html",
"docs/*.svg",
],
"folder_exclude_patterns":
[