fix #163: allow opening same file twice

This commit is contained in:
antelle 2016-06-05 13:25:50 +03:00
parent 5fe2ec0c15
commit c7240edca9
9 changed files with 42 additions and 34 deletions

View File

@ -23,7 +23,7 @@ var FileCollection = Backbone.Collection.extend({
}, },
getById: function(id) { getById: function(id) {
return this.find(function(file) { return file.get('id') === id; }); return this.find(function(file) { return file.id === id; });
} }
}); });

View File

@ -263,7 +263,7 @@ var AppModel = Backbone.Model.extend({
createDemoFile: function() { createDemoFile: function() {
var that = this; var that = this;
if (!this.files.getByName('Demo')) { if (!this.files.getByName('Demo')) {
var demoFile = new FileModel(); var demoFile = new FileModel({ id: IdGenerator.uuid() });
demoFile.openDemo(function() { demoFile.openDemo(function() {
that.addFile(demoFile); that.addFile(demoFile);
}); });
@ -281,7 +281,7 @@ var AppModel = Backbone.Model.extend({
break; break;
} }
} }
var newFile = new FileModel(); var newFile = new FileModel({ id: IdGenerator.uuid() });
newFile.create(name); newFile.create(name);
this.addFile(newFile); this.addFile(newFile);
}, },
@ -383,6 +383,7 @@ var AppModel = Backbone.Model.extend({
params.keyFileData = FileModel.createKeyFileWithHash(fileInfo.get('keyFileHash')); params.keyFileData = FileModel.createKeyFileWithHash(fileInfo.get('keyFileHash'));
} }
var file = new FileModel({ var file = new FileModel({
id: fileInfo ? fileInfo.id : IdGenerator.uuid(),
name: params.name, name: params.name,
storage: params.storage, storage: params.storage,
path: params.path, path: params.path,
@ -407,11 +408,9 @@ var AppModel = Backbone.Model.extend({
if (fileInfo) { if (fileInfo) {
file.set('syncDate', fileInfo.get('syncDate')); file.set('syncDate', fileInfo.get('syncDate'));
} }
var cacheId = fileInfo && fileInfo.id || IdGenerator.uuid();
file.set('cacheId', cacheId);
if (updateCacheOnSuccess) { if (updateCacheOnSuccess) {
logger.info('Save loaded file to cache'); logger.info('Save loaded file to cache');
Storage.cache.save(cacheId, null, params.fileData); Storage.cache.save(file.id, null, params.fileData);
} }
var rev = params.rev || fileInfo && fileInfo.get('rev'); var rev = params.rev || fileInfo && fileInfo.get('rev');
that.setFileOpts(file, params.opts); that.setFileOpts(file, params.opts);
@ -426,6 +425,7 @@ var AppModel = Backbone.Model.extend({
var logger = new Logger('import', params.name); var logger = new Logger('import', params.name);
logger.info('File import request with supplied xml'); logger.info('File import request with supplied xml');
var file = new FileModel({ var file = new FileModel({
id: IdGenerator.uuid(),
name: params.name, name: params.name,
storage: params.storage, storage: params.storage,
path: params.path path: params.path
@ -442,10 +442,10 @@ var AppModel = Backbone.Model.extend({
}, },
addToLastOpenFiles: function(file, rev) { addToLastOpenFiles: function(file, rev) {
this.appLogger.debug('Add last open file', file.get('cacheId'), file.get('name'), file.get('storage'), file.get('path'), rev); this.appLogger.debug('Add last open file', file.id, file.get('name'), file.get('storage'), file.get('path'), rev);
var dt = new Date(); var dt = new Date();
var fileInfo = new FileInfoModel({ var fileInfo = new FileInfoModel({
id: file.get('cacheId'), id: file.id,
name: file.get('name'), name: file.get('name'),
storage: file.get('storage'), storage: file.get('storage'),
path: file.get('path'), path: file.get('path'),
@ -462,7 +462,7 @@ var AppModel = Backbone.Model.extend({
keyFileHash: file.getKeyFileHash() keyFileHash: file.getKeyFileHash()
}); });
} }
this.fileInfos.remove(file.get('cacheId')); this.fileInfos.remove(file.id);
this.fileInfos.unshift(fileInfo); this.fileInfos.unshift(fileInfo);
this.fileInfos.save(); this.fileInfos.save();
}, },
@ -504,7 +504,7 @@ var AppModel = Backbone.Model.extend({
}, },
getFileInfo: function(file) { getFileInfo: function(file) {
return file.get('cacheId') ? this.fileInfos.get(file.get('cacheId')) : return this.fileInfos.get(file.id) ||
this.fileInfos.getMatch(file.get('storage'), file.get('name'), file.get('path')); this.fileInfos.getMatch(file.get('storage'), file.get('name'), file.get('path'));
}, },
@ -549,7 +549,6 @@ var AppModel = Backbone.Model.extend({
if (!err) { savedToCache = true; } if (!err) { savedToCache = true; }
logger.info('Sync finished', err || 'no error'); logger.info('Sync finished', err || 'no error');
file.setSyncComplete(path, storage, err ? err.toString() : null, savedToCache); file.setSyncComplete(path, storage, err ? err.toString() : null, savedToCache);
file.set('cacheId', fileInfo.id);
fileInfo.set({ fileInfo.set({
name: file.get('name'), name: file.get('name'),
storage: storage, storage: storage,
@ -557,8 +556,7 @@ var AppModel = Backbone.Model.extend({
opts: that.getStoreOpts(file), opts: that.getStoreOpts(file),
modified: file.get('modified'), modified: file.get('modified'),
editState: file.getLocalEditState(), editState: file.getLocalEditState(),
syncDate: file.get('syncDate'), syncDate: file.get('syncDate')
cacheId: fileInfo.id
}); });
if (that.settings.get('rememberKeyFiles')) { if (that.settings.get('rememberKeyFiles')) {
fileInfo.set({ fileInfo.set({
@ -573,7 +571,7 @@ var AppModel = Backbone.Model.extend({
if (callback) { callback(err); } if (callback) { callback(err); }
}; };
if (!storage) { if (!storage) {
if (!file.get('modified') && fileInfo.id === file.get('cacheId')) { if (!file.get('modified') && fileInfo.id === file.id) {
logger.info('Local, not modified'); logger.info('Local, not modified');
return complete(); return complete();
} }

View File

@ -21,7 +21,7 @@ var EntryModel = Backbone.Model.extend({
this.entry = entry; this.entry = entry;
this.group = group; this.group = group;
this.file = file; this.file = file;
if (this.id === entry.uuid.id) { if (this.get('uuid') === entry.uuid.id) {
this._checkUpdatedEntry(); this._checkUpdatedEntry();
} }
this._fillByEntry(); this._fillByEntry();
@ -29,7 +29,7 @@ var EntryModel = Backbone.Model.extend({
_fillByEntry: function() { _fillByEntry: function() {
var entry = this.entry; var entry = this.entry;
this.set({id: entry.uuid.id}, {silent: true}); this.set({id: this.file.subId(entry.uuid.id), uuid: entry.uuid.id}, {silent: true});
this.fileName = this.file.get('name'); this.fileName = this.file.get('name');
this.groupName = this.group.get('title'); this.groupName = this.group.get('title');
this.title = entry.fields.Title || ''; this.title = entry.fields.Title || '';

View File

@ -13,6 +13,7 @@ var logger = new Logger('file');
var FileModel = Backbone.Model.extend({ var FileModel = Backbone.Model.extend({
defaults: { defaults: {
id: '', id: '',
uuid: '',
name: '', name: '',
keyFileName: '', keyFileName: '',
passwordLength: 0, passwordLength: 0,
@ -31,8 +32,7 @@ var FileModel = Backbone.Model.extend({
keyFileChanged: false, keyFileChanged: false,
syncing: false, syncing: false,
syncError: null, syncError: null,
syncDate: null, syncDate: null
cacheId: null
}, },
db: null, db: null,
@ -136,7 +136,7 @@ var FileModel = Backbone.Model.extend({
readModel: function() { readModel: function() {
var groups = new GroupCollection(); var groups = new GroupCollection();
this.set({ this.set({
id: this.db.getDefaultGroup().uuid.toString(), uuid: this.db.getDefaultGroup().uuid.toString(),
groups: groups, groups: groups,
defaultUser: this.db.meta.defaultUser, defaultUser: this.db.meta.defaultUser,
recycleBinEnabled: this.db.meta.recycleBinEnabled, recycleBinEnabled: this.db.meta.recycleBinEnabled,
@ -145,18 +145,21 @@ var FileModel = Backbone.Model.extend({
keyEncryptionRounds: this.db.header.keyEncryptionRounds keyEncryptionRounds: this.db.header.keyEncryptionRounds
}, { silent: true }); }, { silent: true });
this.db.groups.forEach(function(group) { this.db.groups.forEach(function(group) {
var groupModel = this.getGroup(group.uuid.id); var groupModel = this.getGroup(this.subId(group.uuid.id));
if (groupModel) { if (groupModel) {
groupModel.setGroup(group, this); groupModel.setGroup(group, this);
} else { } else {
groupModel = GroupModel.fromGroup(group, this); groupModel = GroupModel.fromGroup(group, this);
} }
groupModel.set({title: this.get('name')});
groups.add(groupModel); groups.add(groupModel);
}, this); }, this);
this.buildObjectMap(); this.buildObjectMap();
}, },
subId: function(id) {
return this.id + ':' + id;
},
buildObjectMap: function() { buildObjectMap: function() {
var entryMap = {}; var entryMap = {};
var groupMap = {}; var groupMap = {};
@ -257,7 +260,7 @@ var FileModel = Backbone.Model.extend({
forEachEntry: function(filter, callback) { forEachEntry: function(filter, callback) {
var top = this; var top = this;
if (filter.trash) { if (filter.trash) {
top = this.getGroup(this.db.meta.recycleBinUuid ? this.db.meta.recycleBinUuid.id : null); top = this.getGroup(this.db.meta.recycleBinUuid ? this.subId(this.db.meta.recycleBinUuid.id) : null);
} else if (filter.group) { } else if (filter.group) {
top = this.getGroup(filter.group); top = this.getGroup(filter.group);
} }
@ -282,7 +285,7 @@ var FileModel = Backbone.Model.extend({
}, },
getTrashGroup: function() { getTrashGroup: function() {
return this.db.meta.recycleBinEnabled ? this.getGroup(this.db.meta.recycleBinUuid.id) : null; return this.db.meta.recycleBinEnabled ? this.getGroup(this.subId(this.db.meta.recycleBinUuid.id)) : null;
}, },
setModified: function() { setModified: function() {
@ -455,9 +458,9 @@ var FileModel = Backbone.Model.extend({
}, },
addCustomIcon: function(iconData) { addCustomIcon: function(iconData) {
var id = kdbxweb.KdbxUuid.random(); var uuid = kdbxweb.KdbxUuid.random();
this.db.meta.customIcons[id] = kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData)); this.db.meta.customIcons[uuid] = kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData));
return id.toString(); return uuid.toString();
}, },
renameTag: function(from, to) { renameTag: function(from, to) {

View File

@ -31,13 +31,15 @@ var GroupModel = MenuItemModel.extend({
setGroup: function(group, file, parentGroup) { setGroup: function(group, file, parentGroup) {
var isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id; var isRecycleBin = file.db.meta.recycleBinUuid && file.db.meta.recycleBinUuid.id === group.uuid.id;
var id = file.subId(group.uuid.id);
this.set({ this.set({
id: group.uuid.id, id: id,
uuid: group.uuid.id,
expanded: group.expanded, expanded: group.expanded,
visible: !isRecycleBin, visible: !isRecycleBin,
items: new GroupCollection(), items: new GroupCollection(),
entries: new EntryCollection(), entries: new EntryCollection(),
filterValue: group.uuid.id, filterValue: id,
enableSearching: group.enableSearching, enableSearching: group.enableSearching,
enableAutoType: group.enableAutoType, enableAutoType: group.enableAutoType,
autoTypeSeq: group.defaultAutoTypeSeq, autoTypeSeq: group.defaultAutoTypeSeq,
@ -52,7 +54,7 @@ var GroupModel = MenuItemModel.extend({
var items = this.get('items'), var items = this.get('items'),
entries = this.get('entries'); entries = this.get('entries');
group.groups.forEach(function(subGroup) { group.groups.forEach(function(subGroup) {
var existing = file.getGroup(subGroup.uuid); var existing = file.getGroup(file.subId(subGroup.uuid.id));
if (existing) { if (existing) {
existing.setGroup(subGroup, file, this); existing.setGroup(subGroup, file, this);
items.add(existing); items.add(existing);
@ -61,7 +63,7 @@ var GroupModel = MenuItemModel.extend({
} }
}, this); }, this);
group.entries.forEach(function(entry) { group.entries.forEach(function(entry) {
var existing = file.getEntry(entry.uuid); var existing = file.getEntry(file.subId(entry.uuid.id));
if (existing) { if (existing) {
existing.setEntry(entry, this, file); existing.setEntry(entry, this, file);
entries.add(existing); entries.add(existing);
@ -73,7 +75,7 @@ var GroupModel = MenuItemModel.extend({
_fillByGroup: function(silent) { _fillByGroup: function(silent) {
this.set({ this.set({
title: this.group.name, title: this.parentGroup ? this.group.name : this.file.get('name'),
iconId: this.group.icon, iconId: this.group.icon,
icon: this._iconFromId(this.group.icon), icon: this._iconFromId(this.group.icon),
customIcon: this._buildCustomIcon(), customIcon: this._buildCustomIcon(),

View File

@ -19,7 +19,7 @@ EntryPresenter.prototype = {
} }
return this; return this;
}, },
get id() { return this.entry ? this.entry.id : this.group.get('id'); }, get id() { return this.entry ? this.entry.id : this.group.id; },
get icon() { return this.entry ? this.entry.icon : (this.group.get('icon') || 'folder'); }, get icon() { return this.entry ? this.entry.icon : (this.group.get('icon') || 'folder'); },
get customIcon() { return this.entry ? this.entry.customIcon : undefined; }, get customIcon() { return this.entry ? this.entry.customIcon : undefined; },
get color() { return this.entry ? (this.entry.color || (this.entry.customIcon ? this.noColor : undefined)) : undefined; }, get color() { return this.entry ? (this.entry.color || (this.entry.customIcon ? this.noColor : undefined)) : undefined; },

View File

@ -107,7 +107,7 @@ var StorageWebDav = StorageBase.extend({
fileOptsToStoreOpts: function(opts, file) { fileOptsToStoreOpts: function(opts, file) {
var result = {user: opts.user, encpass: opts.encpass}; var result = {user: opts.user, encpass: opts.encpass};
if (opts.password) { if (opts.password) {
var fileId = file.get('id'); var fileId = file.get('uuid');
var password = opts.password; var password = opts.password;
var encpass = ''; var encpass = '';
for (var i = 0; i < password.length; i++) { for (var i = 0; i < password.length; i++) {
@ -121,7 +121,7 @@ var StorageWebDav = StorageBase.extend({
storeOptsToFileOpts: function(opts, file) { storeOptsToFileOpts: function(opts, file) {
var result = {user: opts.user, password: opts.password}; var result = {user: opts.user, password: opts.password};
if (opts.encpass) { if (opts.encpass) {
var fileId = file.get('id'); var fileId = file.get('uuid');
var encpass = atob(opts.encpass); var encpass = atob(opts.encpass);
var password = ''; var password = '';
for (var i = 0; i < encpass.length; i++) { for (var i = 0; i < encpass.length; i++) {

View File

@ -449,6 +449,10 @@ var OpenView = Backbone.View.extend({
}, },
openDb: function() { openDb: function() {
if (this.params.id && this.model.files.getById(this.params.id)) {
this.trigger('close');
return;
}
if (this.busy || !this.params.name) { if (this.busy || !this.params.name) {
return; return;
} }

View File

@ -16,6 +16,7 @@ Auto-type, ui improvements
`+` logout from remote storages on disable `+` logout from remote storages on disable
`*` don't check updates at startup `*` don't check updates at startup
`*` repos moved to github organization account `*` repos moved to github organization account
`*` allow opening same file twice
`-` prevent second app instance on windows `-` prevent second app instance on windows
`-` fix drag-drop in Safari `-` fix drag-drop in Safari