This commit is contained in:
Antelle 2015-12-11 00:31:47 +03:00
parent 00e22f0026
commit a28067055d
5 changed files with 124 additions and 62 deletions

View File

@ -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; });
}
});

View File

@ -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();
}

View File

@ -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;

View File

@ -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,

View File

@ -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() {