fixed dropbox sync errors

This commit is contained in:
Antelle 2015-10-27 00:07:43 +03:00
parent 423e0a0ae6
commit 554794eb12
6 changed files with 154 additions and 65 deletions

View File

@ -1,6 +1,7 @@
'use strict';
var Dropbox = require('dropbox');
var Dropbox = require('dropbox'),
Alerts = require('./alerts');
var DropboxKeys = {
AppFolder: 'qp7ctun6qt5n9d6'
@ -8,7 +9,7 @@ var DropboxKeys = {
var DropboxLink = {
_getClient: function(complete) {
if (this._dropboxClient) {
if (this._dropboxClient && this._dropboxClient.isAuthenticated()) {
complete(null, this._dropboxClient);
return;
}
@ -22,41 +23,115 @@ var DropboxLink = {
}).bind(this));
},
_handleUiError: function(err, callback) {
switch (err.status) {
case Dropbox.ApiError.INVALID_TOKEN:
Alerts.yesno({
icon: 'dropbox',
header: 'Dropbox Login',
body: 'To continue, you have to sign in to Dropbox.',
buttons: [{result: 'yes', title: 'Sign In'}, {result: '', title: 'Cancel'}],
success: (function() {
this.authenticate(function(err) { callback(!err); });
}).bind(this),
cancel: function() { callback(false); }
});
return;
case Dropbox.ApiError.NOT_FOUND:
Alerts.error({
header: 'Dropbox Sync Error',
body: 'The file was not found. Has it been removed from another computer?'
});
break;
case Dropbox.ApiError.OVER_QUOTA:
Alerts.error({
header: 'Dropbox Full',
body: 'Your Dropbox is full, there\'s no space left anymore.'
});
break;
case Dropbox.ApiError.RATE_LIMITED:
Alerts.error({
header: 'Dropbox Sync Error',
body: 'Too many requests to Dropbox have been made by this app. Please, try again later.'
});
break;
case Dropbox.ApiError.NETWORK_ERROR:
Alerts.error({
header: 'Dropbox Sync Network Error',
body: 'Network error occured during Dropbox sync. Please, check your connection and try again.'
});
break;
case Dropbox.ApiError.INVALID_PARAM:
case Dropbox.ApiError.OAUTH_ERROR:
case Dropbox.ApiError.INVALID_METHOD:
Alerts.error({
header: 'Dropbox Sync Error',
body: 'Something went wrong during Dropbox sync. Please, try again later. Error code: ' + err.status
});
break;
default:
Alerts.error({
header: 'Dropbox Sync Error',
body: 'Something went wrong during Dropbox sync. Please, try again later. Error: ' + err
});
break;
}
callback(false);
},
_callAndHandleError: function(callName, args, callback) {
var that = this;
this._getClient(function(err, client) {
if (err) {
return callback(err);
}
client[callName].apply(client, args.concat(function(err, res) {
if (err) {
that._handleUiError(err, function(repeat) {
if (repeat) {
that._callAndHandleError(callName, args, callback);
} else {
callback(err);
}
});
} else {
callback(err, res);
}
}));
});
},
authenticate: function(copmlete) {
this._getClient(function(err) { copmlete(err); });
},
receive: function() {
Dropbox.AuthDriver.Popup.oauthReceiver();
},
saveFile: function(fileName, data, overwrite, complete) {
this._getClient(function(err, client) {
if (err) { return complete(err); }
if (!overwrite) {
client.readdir('', function(err, files) {
if (err) { return complete(err); }
var exists = files.some(function(file) { return file.toLowerCase() === fileName.toLowerCase(); });
if (exists) { return complete({ exists: true }); }
client.writeFile(fileName, data, complete);
});
} else {
client.writeFile(fileName, data, complete);
}
});
if (overwrite) {
this._callAndHandleError('writeFile', [fileName, data], complete);
} else {
this.getFileList((function(err, files) {
if (err) { return complete(err); }
var exists = files.some(function(file) { return file.toLowerCase() === fileName.toLowerCase(); });
if (exists) { return complete({ exists: true }); }
this._callAndHandleError('writeFile', [fileName, data], complete);
}).bind(this));
}
},
openFile: function(fileName, complete) {
this._getClient(function(err, client) {
if (err) { return complete(err); }
client.readFile(fileName, { blob: true }, complete);
});
this._callAndHandleError('readFile', [fileName, { blob: true }], complete);
},
getFileList: function(complete) {
this._getClient(function(err, client) {
if (err) { return complete(err); }
client.readdir('', function(err, files) {
if (err) { return complete(err); }
this._callAndHandleError('readdir', [''], function(err, files) {
if (files) {
files = files.filter(function(f) { return /\.kdbx$/i.test(f); });
complete(null, files);
});
}
complete(err, files);
});
}
};

View File

@ -181,41 +181,52 @@ var OpenFileView = Backbone.View.extend({
},
openFromDropbox: function() {
this.dropboxLoading = 'opening';
this.render();
DropboxLink.getFileList((function(err, files) {
this.dropboxLoading = null;
if (err) { return; }
var buttons = [];
files.forEach(function(file) {
buttons.push({ result: file, title: file.replace(/\.kdbx/i, '') });
});
if (!buttons.length) {
this.dropboxLoading = null;
this.render();
Alerts.error({
header: 'Nothing found',
body: 'You have no files in your Dropbox which could be opened. Files are searched in your Dropbox app folder: Apps/KeeWeb'
});
if (this.dropboxLoading) {
return;
}
DropboxLink.authenticate((function(err) {
if (err) {
return;
}
buttons.push({ result: '', title: 'Cancel' });
Alerts.alert({
header: 'Select a file',
body: 'Select a file from your Dropbox which you would like to open',
icon: 'dropbox',
buttons: buttons,
esc: '',
click: '',
success: this.openDropboxFile.bind(this),
cancel: this.cancelOpenDropboxFile.bind(this)
});
this.dropboxLoading = 'file list';
this.render();
DropboxLink.getFileList((function(err, files) {
this.dropboxLoading = null;
if (err) {
this.render();
return;
}
var buttons = [];
files.forEach(function(file) {
buttons.push({ result: file, title: file.replace(/\.kdbx/i, '') });
});
if (!buttons.length) {
this.dropboxLoading = null;
this.render();
Alerts.error({
header: 'Nothing found',
body: 'You have no files in your Dropbox which could be opened. Files are searched in your Dropbox app folder: Apps/KeeWeb'
});
return;
}
buttons.push({ result: '', title: 'Cancel' });
Alerts.alert({
header: 'Select a file',
body: 'Select a file from your Dropbox which you would like to open',
icon: 'dropbox',
buttons: buttons,
esc: '',
click: '',
success: this.openDropboxFile.bind(this),
cancel: this.cancelOpenDropboxFile.bind(this)
});
}).bind(this));
}).bind(this));
},
openDropboxFile: function(file) {
var fileName = file.replace(/\.kdbx/i, '');
this.dropboxLoading = 'opening ' + fileName;
this.dropboxLoading = fileName;
this.render();
DropboxLink.openFile(file, (function(err, data) {
this.dropboxLoading = null;

View File

@ -44,6 +44,7 @@ var SettingsAboutView = Backbone.View.extend({
name: this.model.get('name'),
path: this.model.get('path'),
storage: this.model.get('storage'),
syncing: this.model.get('syncing'),
password: PasswordGenerator.present(this.model.get('passwordLength')),
defaultUser: this.model.get('defaultUser'),
recycleBinEnabled: this.model.get('recycleBinEnabled'),
@ -86,9 +87,7 @@ var SettingsAboutView = Backbone.View.extend({
Alerts.error({
header: 'Empty password',
body: 'Please, enter the password. You will use it the next time you open this file.',
complete: (function() {
this.$el.find('#settings__file-master-pass').focus();
}).bind(this)
complete: (function() { this.$el.find('#settings__file-master-pass').focus(); }).bind(this)
});
return false;
}
@ -115,7 +114,9 @@ var SettingsAboutView = Backbone.View.extend({
var blob = new Blob([data], {type: 'application/octet-stream'});
FileSaver.saveAs(blob, fileName);
this.passwordChanged = false;
this.model.saved();
if (this.model.get('storage') !== 'dropbox') {
this.model.saved();
}
}
},
@ -151,12 +152,13 @@ var SettingsAboutView = Backbone.View.extend({
},
saveToDropbox: function(overwrite) {
if (!this.validate()) {
if (this.model.get('syncing') || !this.validate()) {
return;
}
var data = this.model.getData();
var fileName = this.model.get('name') + '.kdbx';
this.model.set('syncing', true);
this.render();
DropboxLink.saveFile(fileName, data, overwrite, (function(err) {
if (err) {
this.model.set('syncing', false);
@ -169,7 +171,8 @@ var SettingsAboutView = Backbone.View.extend({
esc: '',
click: '',
enter: 'yes',
success: this.saveToDropbox.bind(this, true)
success: this.saveToDropbox.bind(this, true),
cancel: (function() { this.$el.find('#settings__file-name').focus(); }).bind(this)
});
} else {
Alerts.error({

View File

@ -3,6 +3,7 @@
<div class="footer__db footer__db-item <%= file.get('open') ? '' : 'footer__db--dimmed' %>" data-file-id="<%= file.cid %>">
<i class="fa fa-<%= file.get('open') ? 'unlock' : 'lock' %>"></i> <%- file.get('name') %>
<% if (file.get('modified') && !file.get('syncing')) { %><i class="fa fa-circle footer__db-sign"></i><% } %>
<% if (file.get('syncing')) { %><i class="fa fa-refresh fa-spin footer__db-sign"></i><% } %>
</div>
<% }); %>
<div class="footer__db footer__db--dimmed footer__db--expanded footer__db-open"><i class="fa fa-plus"></i> Open / New</div>

View File

@ -13,10 +13,10 @@
<a class="open__file-link-name muted-color" <%= opening ? 'disabled' : '' %>>Open another</a>
<% } else { %>
<a class="open__file-link-open muted-color" <%= opening ? 'disabled' : '' %>>Open</a> / <a
class="open__file-link-new muted-color" <%= opening ? 'disabled' : '' %>>New</a><% if (supportsDropbox) { %> / <a
class="open__file-link-new muted-color" <%= opening ? 'disabled' : '' %>>New</a> / <a
class="open__file-link-demo muted-color" <%= opening ? 'disabled' : '' %>>Demo</a><% if (supportsDropbox) { %> / <a
class="open__file-link-dropbox muted-color" <%= (opening || dropboxLoading) ? 'disabled' : '' %>
>Dropbox<%= dropboxLoading ? ' (' + dropboxLoading + '...)' : '' %></a><% } %> / <a
class="open__file-link-demo muted-color" <%= opening ? 'disabled' : '' %>>Demo</a>
>Dropbox<%= dropboxLoading ? ' (loading ' + dropboxLoading + '...)' : '' %></a><% } %>
<% } %>
</div>
<div class="open__file-warning muted-color hide"><i class="fa fa-exclamation-triangle"></i> Caps Lock is on</div>

View File

@ -15,12 +15,11 @@
<% } %>
<div class="settings__file-buttons">
<% if (storage !== 'dropbox') { %>
<button class="settings__file-button-save-file btn-silent">Save to file</button>
<% } %>
<button class="settings__file-button-export-xml btn-silent">Export to XML</button>
<% if (supportsDropbox) { %>
<button class="settings__file-button-save-dropbox btn-silent">Sync with Dropbox</button>
<button class="settings__file-button-save-dropbox btn-silent" <%= syncing ? 'disabled' : '' %>>
Sync with Dropbox <%= syncing ? '(working...)' : '' %></button>
<% } %>
</div>