mirror of https://github.com/keeweb/keeweb.git
sync
This commit is contained in:
parent
00e22f0026
commit
a28067055d
|
@ -31,6 +31,10 @@ var FileInfoCollection = Backbone.Collection.extend({
|
|||
(fi.get('name') || '') === (name || '') &&
|
||||
(fi.get('path') || '') === (path || '');
|
||||
});
|
||||
},
|
||||
|
||||
getByName: function() {
|
||||
return this.find(function(file) { return file.get('name') === name; });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ var AppModel = Backbone.Model.extend({
|
|||
var name;
|
||||
for (var i = 0; ; i++) {
|
||||
name = 'New' + (i || '');
|
||||
if (!this.files.getByName(name)) {
|
||||
if (!this.files.getByName(name) && !this.fileInfos.getByName(name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -317,6 +317,12 @@ var AppModel = Backbone.Model.extend({
|
|||
if (that.files.get(file.id)) {
|
||||
return callback('Duplicate file id');
|
||||
}
|
||||
if (fileInfo && fileInfo.get('modified')) {
|
||||
if (fileInfo.get('editState')) {
|
||||
file.setLocalEditState(fileInfo.get('editState'));
|
||||
}
|
||||
file.setModified();
|
||||
}
|
||||
var cacheId = fileInfo && fileInfo.id || IdGenerator.uuid();
|
||||
if (updateCacheOnSuccess && params.storage !== 'file') {
|
||||
Storage.cache.save(cacheId, params.fileData, function(err) {
|
||||
|
@ -341,7 +347,7 @@ var AppModel = Backbone.Model.extend({
|
|||
storage: file.get('storage'),
|
||||
path: file.get('path'),
|
||||
modified: file.get('modified'),
|
||||
editState: null,
|
||||
editState: file.getLocalEditState(),
|
||||
rev: rev,
|
||||
pullDate: dt,
|
||||
openDate: dt
|
||||
|
@ -361,7 +367,10 @@ var AppModel = Backbone.Model.extend({
|
|||
if (file.get('syncing')) {
|
||||
return callback('Sync in progress');
|
||||
}
|
||||
// todo: save to cache
|
||||
var complete = function(err) {
|
||||
// TODO: save file info
|
||||
callback(err);
|
||||
};
|
||||
var fileInfo = this.fileInfos.getMatch(file.get('storage'), file.get('name'), file.get('path'));
|
||||
if (!fileInfo) {
|
||||
var dt = new Date();
|
||||
|
@ -378,66 +387,77 @@ var AppModel = Backbone.Model.extend({
|
|||
});
|
||||
}
|
||||
var storage = Storage[options.storage || file.get('storage')];
|
||||
var path = options.path || file.get('path');
|
||||
if (!storage) {
|
||||
if (!file.get('modified')) {
|
||||
return callback();
|
||||
return complete();
|
||||
}
|
||||
file.getData(function(data, err) {
|
||||
if (err) { return callback(err); }
|
||||
if (err) { return complete(err); }
|
||||
Storage.cache.save(fileInfo.id, data, function(err) {
|
||||
callback(err);
|
||||
complete(err);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var maxLoadLoops = 3, loadLoops = 0;
|
||||
var loadFromStorageAndMerge = function() {
|
||||
if (++loadLoops === maxLoadLoops) {
|
||||
return callback('Too many load attempts, please try again later');
|
||||
return complete('Too many load attempts, please try again later');
|
||||
}
|
||||
storage.load(file.get('path'), function(err, data, stat) {
|
||||
if (err) { return callback(err); }
|
||||
file.merge(data, function(err) {
|
||||
if (err) { return callback(err); }
|
||||
storage.load(path, function(err, data, stat) {
|
||||
if (err) { return complete(err); }
|
||||
file.mergeOrUpdate(data, function(err) {
|
||||
if (err) { return complete(err); }
|
||||
if (stat && stat.rev) {
|
||||
fileInfo.set('rev', stat.rev);
|
||||
}
|
||||
if (file.get('modified')) {
|
||||
saveToStorage();
|
||||
saveToCacheAndStorage();
|
||||
} else {
|
||||
callback();
|
||||
complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
var saveToStorage = function() {
|
||||
var saveToCacheAndStorage = function() {
|
||||
file.getData(function(data, err) {
|
||||
if (err) { return callback(err); }
|
||||
storage.save(file.get('path'), data, function(err) {
|
||||
if (err && err.revConflict) {
|
||||
loadFromStorageAndMerge();
|
||||
} else if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
if (storage === Storage.file) {
|
||||
Storage.cache.remove(fileInfo.id);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}, fileInfo.get('rev'));
|
||||
if (err) { return complete(err); }
|
||||
if (storage === Storage.file) {
|
||||
saveToStorage(data);
|
||||
} else {
|
||||
Storage.cache.save(fileInfo.id, data, function (err) {
|
||||
if (err) { return complete(err); }
|
||||
saveToStorage(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
var saveToStorage = function(data) {
|
||||
storage.save(path, data, function(err) {
|
||||
if (err && err.revConflict) {
|
||||
loadFromStorageAndMerge();
|
||||
} else if (err) {
|
||||
complete(err);
|
||||
} else {
|
||||
if (storage === Storage.file) {
|
||||
Storage.cache.remove(fileInfo.id);
|
||||
}
|
||||
complete();
|
||||
}
|
||||
}, fileInfo.get('rev'));
|
||||
};
|
||||
if (options.reload) {
|
||||
loadFromStorageAndMerge();
|
||||
} else if (storage === Storage.file) {
|
||||
if (file.get('modified')) {
|
||||
saveToStorage();
|
||||
saveToCacheAndStorage();
|
||||
} else {
|
||||
callback();
|
||||
complete();
|
||||
}
|
||||
} else {
|
||||
storage.stat(file.get('path'), function (err, stat) {
|
||||
storage.stat(path, function (err, stat) {
|
||||
if (stat.rev === fileInfo.get('rev')) {
|
||||
saveToStorage();
|
||||
saveToCacheAndStorage();
|
||||
} else {
|
||||
loadFromStorageAndMerge();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ var FileModel = Backbone.Model.extend({
|
|||
oldKeyFileName: '',
|
||||
passwordChanged: false,
|
||||
keyFileChanged: false,
|
||||
syncing: false
|
||||
syncing: false,
|
||||
syncError: null
|
||||
},
|
||||
|
||||
db: null,
|
||||
|
@ -155,18 +156,39 @@ var FileModel = Backbone.Model.extend({
|
|||
this.trigger('reload', this);
|
||||
},
|
||||
|
||||
merge: function(fileData, callback) {
|
||||
mergeOrUpdate: function(fileData, callback) {
|
||||
kdbxweb.Kdbx.load(fileData, this.db.credentials, (function(remoteDb, err) {
|
||||
if (err) {
|
||||
console.error('Error opening file to merge', err.code, err.message, err);
|
||||
} else {
|
||||
this.db.merge(remoteDb);
|
||||
this.reload();
|
||||
if (this.get('modified')) {
|
||||
try {
|
||||
this.db.merge(remoteDb);
|
||||
} catch (e) {
|
||||
console.error('File merge error', e);
|
||||
return callback(e);
|
||||
}
|
||||
} else {
|
||||
this.db = remoteDb;
|
||||
this.reload();
|
||||
}
|
||||
}
|
||||
callback(err);
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
getLocalEditState: function() {
|
||||
return this.db.getLocalEditState();
|
||||
},
|
||||
|
||||
setLocalEditState: function(editState) {
|
||||
this.db.setLocalEditState(editState);
|
||||
},
|
||||
|
||||
removeLocalEditState: function() {
|
||||
this.db.removeLocalEditState();
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.set({
|
||||
keyFileName: '',
|
||||
|
@ -244,8 +266,20 @@ var FileModel = Backbone.Model.extend({
|
|||
this.db.saveXml(cb);
|
||||
},
|
||||
|
||||
saved: function(path, storage) {
|
||||
this.set({ path: path || '', storage: storage || null, modified: false, created: false, syncing: false });
|
||||
setSyncProgress: function() {
|
||||
this.set({ syncing: true });
|
||||
},
|
||||
|
||||
setSyncComplete: function(path, storage, error) {
|
||||
var modified = this.get('modified') && !!error;
|
||||
this.set({
|
||||
created: false,
|
||||
path: path || this.get('path'),
|
||||
storage: storage || this.get('storage'),
|
||||
modified: modified,
|
||||
syncing: false,
|
||||
syncError: error
|
||||
});
|
||||
this.setOpenFile({ passwordLength: this.get('passwordLength') });
|
||||
this.forEachEntry({}, function(entry) {
|
||||
entry.unsaved = false;
|
||||
|
|
|
@ -322,10 +322,6 @@ var AppView = Backbone.View.extend({
|
|||
}
|
||||
},
|
||||
|
||||
showVisualLock: function() {
|
||||
// TODO: remove cases which lead to this
|
||||
},
|
||||
|
||||
saveAndLock: function(autoInit) {
|
||||
// TODO: move to file manager
|
||||
var pendingCallbacks = 0,
|
||||
|
|
|
@ -137,28 +137,36 @@ var SettingsAboutView = Backbone.View.extend({
|
|||
if (skipValidation !== true && !this.validatePassword(this.saveToFile.bind(this, true))) {
|
||||
return;
|
||||
}
|
||||
var fileName = this.model.get('name') + '.kdbx';
|
||||
var that = this;
|
||||
this.model.getData(function(data) {
|
||||
var fileName = that.model.get('name') + '.kdbx';
|
||||
if (Launcher) {
|
||||
Launcher.getSaveFileName(fileName, function (path) {
|
||||
if (path) {
|
||||
Storage.file.save(path, data, function(err) {
|
||||
if (err) {
|
||||
Alerts.error({
|
||||
header: 'Save error',
|
||||
body: 'Error saving to file ' + path + ': \n' + err
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var blob = new Blob([data], {type: 'application/octet-stream'});
|
||||
FileSaver.saveAs(blob, fileName);
|
||||
that.passwordChanged = false;
|
||||
}
|
||||
});
|
||||
if (Launcher && !this.model.get('storage')) {
|
||||
Launcher.getSaveFileName(fileName, function (path) {
|
||||
if (path) {
|
||||
that.save({storage: 'file', path: path});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.model.getData(function (data) {
|
||||
if (Launcher) {
|
||||
Launcher.getSaveFileName(fileName, function (path) {
|
||||
if (path) {
|
||||
Storage.file.save(path, data, function (err) {
|
||||
if (err) {
|
||||
Alerts.error({
|
||||
header: 'Save error',
|
||||
body: 'Error saving to file ' + path + ': \n' + err
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var blob = new Blob([data], {type: 'application/octet-stream'});
|
||||
FileSaver.saveAs(blob, fileName);
|
||||
that.passwordChanged = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
exportAsXml: function() {
|
||||
|
|
Loading…
Reference in New Issue