mirror of
https://github.com/leanote/desktop-app.git
synced 2025-10-14 07:00:53 +00:00
数据库迁移到独立表
This commit is contained in:
25
node_modules/db.js
generated
vendored
25
node_modules/db.js
generated
vendored
@@ -20,30 +20,36 @@ var db = {
|
||||
|
||||
// 为全部用户共有的表初始化
|
||||
initGlobal: function () {
|
||||
var me = this;
|
||||
var dbNames = ['users', 'g'];
|
||||
this._init(dbNames);
|
||||
this.initIt(me, dbNames);
|
||||
},
|
||||
|
||||
// 为特定用户初始化自己的表
|
||||
initDBForUser: function (userId) {
|
||||
var me = this;
|
||||
var dbNames = ['notebooks', 'notes', 'tags', 'images', 'attachs', 'noteHistories'];
|
||||
this._init(dbNames, userId);
|
||||
this.initIt(me, dbNames, userId);
|
||||
},
|
||||
|
||||
// 过时
|
||||
init: function () {
|
||||
var me = this;
|
||||
var dbNames = ['users', 'notebooks', 'notes', 'tags', 'images', 'attachs', 'noteHistories', 'g'];
|
||||
this._init(dbNames);
|
||||
this.initIt(me, dbNames);
|
||||
},
|
||||
|
||||
// 过时
|
||||
initForLogin: function () {
|
||||
var me = this;
|
||||
// var dbNames = ['users'];
|
||||
var dbNames = ['users', 'notebooks', 'notes', 'tags', 'noteHistories'];
|
||||
this._init(dbNames);
|
||||
this.initIt(me, dbNames);
|
||||
},
|
||||
|
||||
_init: function (dbNames, userId) {
|
||||
// map, 最后的db设到map里
|
||||
// forceAutoload 是否强制加载
|
||||
initIt: function (map, dbNames, userId, forceAutoload) {
|
||||
var me = this;
|
||||
for(var i in dbNames) {
|
||||
var name = dbNames[i];
|
||||
@@ -60,7 +66,8 @@ var db = {
|
||||
// console.log(dbFilepath);
|
||||
(function (name) {
|
||||
// 这部分非常慢!, 会卡界面
|
||||
me[name] = new Datastore({ filename: dbFilepath, autoload: name != 'noteHistories' , onload: function () {
|
||||
var autoload = forceAutoload || name != 'noteHistories';
|
||||
map[name] = new Datastore({ filename: dbFilepath, autoload: autoload, onload: function () {
|
||||
console.log(userId + '/' + name + ' is loaded');
|
||||
}});
|
||||
})(name);
|
||||
@@ -73,11 +80,13 @@ var db = {
|
||||
Datastore.prototype.loadDB = function(callback) {
|
||||
var me = this;
|
||||
if (this.__loaded) {
|
||||
callback();
|
||||
callback(me.__loadedSuccess);
|
||||
} else {
|
||||
this.loadDatabase(function (err) {
|
||||
me.__loaded = true;
|
||||
callback(err);
|
||||
console.log(err);
|
||||
me.__loadedSuccess = !err;
|
||||
callback(me.__loadedSuccess);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
11
node_modules/note.js
generated
vendored
11
node_modules/note.js
generated
vendored
@@ -206,7 +206,7 @@ var Note = {
|
||||
*/
|
||||
addNoteHistory: function(noteId, content) {
|
||||
var me = this;
|
||||
db.noteHistories.loadDB(function () {
|
||||
db.noteHistories.loadDB(function (ok) {
|
||||
// 先判断是否存在, 不存在则新建之
|
||||
db.noteHistories.findOne({_id: noteId}, function(err, history) {
|
||||
// 新建之
|
||||
@@ -217,6 +217,9 @@ var Note = {
|
||||
else {
|
||||
var histories = history.Histories;
|
||||
histories.push({Content: content, UpdatedTime: new Date()});
|
||||
|
||||
// 不能多了, 多了有麻烦
|
||||
|
||||
db.noteHistories.update({_id: noteId}, {$set: {Histories: histories}});
|
||||
}
|
||||
});
|
||||
@@ -231,7 +234,11 @@ var Note = {
|
||||
// 获取笔记历史记录
|
||||
getNoteHistories: function(noteId, callback) {
|
||||
var me = this;
|
||||
db.noteHistories.loadDB(function () {
|
||||
db.noteHistories.loadDB(function (ok) {
|
||||
if (!ok) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
db.noteHistories.findOne({_id: noteId}, function(err, doc) {
|
||||
if(err || !doc) {
|
||||
callback(false);
|
||||
|
18
node_modules/user.js
generated
vendored
18
node_modules/user.js
generated
vendored
@@ -383,7 +383,23 @@ User = {
|
||||
}
|
||||
return callback && callback(users);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 通过id得到用户
|
||||
getUser: function (userId, callback) {
|
||||
db.users.findOne({_id: userId}, function(err, user) {
|
||||
if(err) {
|
||||
return callback && callback(false);
|
||||
}
|
||||
return callback && callback(user);
|
||||
});
|
||||
},
|
||||
|
||||
setUserHasDB: function (userId, callback) {
|
||||
db.users.update({_id: userId}, {$set: {HasDB: true}}, function(err, cnt) {
|
||||
callback();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = User;
|
||||
|
@@ -7,7 +7,8 @@ var Config = {
|
||||
"export_html",
|
||||
"export_leanote",
|
||||
"export_evernote",
|
||||
"langs"
|
||||
"langs",
|
||||
"accounts"
|
||||
],
|
||||
"langs": [
|
||||
{
|
||||
@@ -23,6 +24,6 @@ var Config = {
|
||||
"name": "繁体中文"
|
||||
}
|
||||
],
|
||||
"lang": "en-us",
|
||||
"lang": "zh-cn",
|
||||
"theme": ""
|
||||
};
|
@@ -14,6 +14,7 @@ var Api = {
|
||||
fileService: FileService,
|
||||
noteService: NoteService,
|
||||
userService: UserService,
|
||||
dbService: db,
|
||||
|
||||
// 得到当前版本
|
||||
getCurVersion: function (callback) {
|
||||
|
@@ -1641,8 +1641,10 @@ var Loading = {
|
||||
setProgress: function (rate) {
|
||||
this.$progressBar.width(rate + '%');
|
||||
},
|
||||
hide: function() {
|
||||
$('#loadingDialog').modal('hide');
|
||||
hide: function(timeout) {
|
||||
setTimeout(function () {
|
||||
$('#loadingDialog').modal('hide');
|
||||
}, timeout ? timeout : 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
338
public/plugins/accounts/plugin.js
Normal file
338
public/plugins/accounts/plugin.js
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
*
|
||||
* 帐户管理
|
||||
*
|
||||
*/
|
||||
var async;
|
||||
|
||||
define(function() {
|
||||
var setLang = {
|
||||
langs: {
|
||||
'en-us': {
|
||||
'Accounts': 'Accounts',
|
||||
},
|
||||
'zh-cn': {
|
||||
'Accounts': '帐户管理',
|
||||
"Username": "用户名",
|
||||
"Is Local": "本地帐户",
|
||||
"Yes": "是",
|
||||
"No": "否",
|
||||
"DB Optimization": "数据库优化",
|
||||
"Open DB Dir": "打开数据库目录",
|
||||
"Open Images/Attachs Dir": "打开图片附件目录",
|
||||
"Delete": "删除",
|
||||
"Options": "操作",
|
||||
"Current": "当前"
|
||||
},
|
||||
'zh-hk': {
|
||||
'Accounts': '帐户管理',
|
||||
}
|
||||
},
|
||||
|
||||
_tpl: `
|
||||
<style>
|
||||
#accountsDialog .tab-pane {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
#accountsDialog table {
|
||||
width: 100%;
|
||||
}
|
||||
#accountsDialog td button {
|
||||
padding: 5px 8px;
|
||||
|
||||
}
|
||||
#accountsDialog .modal-dialog {
|
||||
width: 750px ;
|
||||
}
|
||||
</style>
|
||||
<div class="modal fade bs-modal-sm" id="accountsDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle"><span class="lang">Accounts</span></h4>
|
||||
</div>
|
||||
<div class="modal-body" id="">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="lang">Username</th>
|
||||
<th class="lang">Is Local</th>
|
||||
<th class="lang">Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer ">
|
||||
<button type="button" class="btn btn-default upgrade-cancel-btn lang" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
`,
|
||||
|
||||
getMsg: function(txt, data) {
|
||||
return Api.getMsg(txt, 'plugin.accounts', data)
|
||||
},
|
||||
|
||||
// 初始化dialog
|
||||
_inited: false,
|
||||
init: function () {
|
||||
var me = this;
|
||||
if (me._inited) {
|
||||
return;
|
||||
}
|
||||
me._inited = true;
|
||||
$('body').append(me._tpl);
|
||||
me.dialog = $("#accountsDialog");
|
||||
|
||||
me.dialog.find('.lang').each(function() {
|
||||
var txt = $.trim($(this).text());
|
||||
$(this).text(me.getMsg(txt));
|
||||
});
|
||||
|
||||
me.tbody = me.dialog.find('tbody');
|
||||
|
||||
var op2Func = {
|
||||
db: function (userId) {
|
||||
me.dbOptimization(userId);
|
||||
},
|
||||
'open-db-dir': '',
|
||||
'open-files-dir': '',
|
||||
'delete': ''
|
||||
};
|
||||
|
||||
// 事件
|
||||
me.tbody.on('click', 'button', function () {
|
||||
var $this = $(this);
|
||||
var userId = $this.closest('tr').data('id');
|
||||
var option = $this.data('op');
|
||||
|
||||
var func = op2Func[option];
|
||||
if (func) {
|
||||
func(userId);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderUser: function(user) {
|
||||
var me = this;
|
||||
var username = user.Username;
|
||||
if (user.IsActive) {
|
||||
username += ' <span class="label label-success">' + me.getMsg('Current') + '</span>';
|
||||
}
|
||||
if (user.Email) {
|
||||
username += '<br /><i>' + user.Email + '</i>';
|
||||
}
|
||||
var tr = '<tr data-id="' + user.UserId + '"><td>' + username + '</td>';
|
||||
tr += '<td>' + (user.IsLocal ? me.getMsg('Yes') : me.getMsg('No')) + '</td>';
|
||||
|
||||
var disabled = user.IsActive ? 'disabled="disabled"' : '';
|
||||
|
||||
var options = '<div class="btn-group" role="group">'
|
||||
+ '<button class="btn btn-default" data-op="db">' + me.getMsg('DB Optimization') + '</button>'
|
||||
+ '<button class="btn btn-default" data-op="open-db-dir">' + me.getMsg('Open DB Dir') + '</button>'
|
||||
+ '<button class="btn btn-default" data-op="open-files-dir">' + me.getMsg('Open Images/Attachs Dir') + '</button>'
|
||||
+ '<button class="btn btn-danger" ' + disabled + ' data-op="delete">' + me.getMsg('Delete') + '</button>'
|
||||
+ '</div>';
|
||||
tr += '<td>' + options + '</td></tr>';
|
||||
return tr;
|
||||
},
|
||||
|
||||
renderUsers: function (users) {
|
||||
var me = this;
|
||||
var tbody = '';
|
||||
for (var i = 0; i < users.length; ++i) {
|
||||
var user = users[i];
|
||||
tbody += me.renderUser(user);
|
||||
}
|
||||
me.tbody.html(tbody);
|
||||
},
|
||||
|
||||
openModal: function () {
|
||||
var me = this;
|
||||
me.dialog.modal('show');
|
||||
|
||||
Api.userService.getAllUsers(function (users) {
|
||||
me.renderUsers(users);
|
||||
});
|
||||
},
|
||||
|
||||
// 打开前要执行的
|
||||
onOpen: function() {
|
||||
var me = this;
|
||||
var gui = Api.gui;
|
||||
|
||||
var menu = new gui.MenuItem({
|
||||
label: me.getMsg('Accounts'),
|
||||
click: function () {
|
||||
me.init();
|
||||
me.openModal();
|
||||
}
|
||||
});
|
||||
|
||||
// 设置
|
||||
Api.addMoreMenu(menu);
|
||||
},
|
||||
// 打开后
|
||||
onOpenAfter: function() {
|
||||
var me = this;
|
||||
},
|
||||
// 关闭时需要运行的
|
||||
onClose: function() {
|
||||
},
|
||||
|
||||
// 数据库优化
|
||||
// 1. 将数据库迁移到独立的目录
|
||||
// 2. 将数据库读写合并
|
||||
dbOptimization: function (userId) {
|
||||
var me = this;
|
||||
Api.loading.show();
|
||||
Api.userService.getUser(userId, function (user) {
|
||||
if (!user) {
|
||||
alert('Error');
|
||||
Api.loading.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// 已经存在
|
||||
if (user.HasDB) {
|
||||
Api.loading.hide(3000);
|
||||
Api.loading.setMsg('优化完成');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!async) {
|
||||
async = require('async');
|
||||
}
|
||||
|
||||
me.migrateAllDBs(userId, function (ok) {
|
||||
// 迁移成功后, 更新HasDB
|
||||
Api.userService.setUserHasDB(userId, function () {
|
||||
Api.loading.setMsg('优化完成');
|
||||
Api.loading.hide(2000);
|
||||
});
|
||||
}, function (msg) {
|
||||
Api.loading.setMsg(msg);
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
// 迁移历史记录
|
||||
migrateNoteHistories: function (noteId, sDB, dDB, callback) {
|
||||
var me = this;
|
||||
// 加载DB, 如果成功
|
||||
sDB.loadDB(function (ok) {
|
||||
if (ok) {
|
||||
sDB.findOne({_id: noteId}, function (err, doc) {
|
||||
dDB.insert(doc, function(err, retDoc) {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
migrateEach: function (userId, sourceDb, distDb, name, callback) {
|
||||
var me = this;
|
||||
|
||||
var sDB = sourceDb[name];
|
||||
var dDB = distDb[name];
|
||||
|
||||
var query = {UserId: userId};
|
||||
sDB.find(query, function(err, docs) {
|
||||
if(err) {
|
||||
return callback && callback(false);
|
||||
}
|
||||
|
||||
if (name === 'notes') {
|
||||
me._notes = docs;
|
||||
}
|
||||
|
||||
async.eachSeries(docs, function(doc, cb) {
|
||||
dDB.insert(doc, function(err, retDoc) {
|
||||
if (retDoc) {
|
||||
console.log(name + ' ok ' + retDoc._id);
|
||||
|
||||
// 如果是笔记, 则迁移它的笔记历史记录
|
||||
if (name === 'notes') {
|
||||
me.migrateNoteHistories(
|
||||
doc.NoteId,
|
||||
sourceDb['noteHistories'],
|
||||
distDb['noteHistories'],
|
||||
function () {
|
||||
cb();
|
||||
});
|
||||
}
|
||||
else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log(name + ' NO ');
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}, function () {
|
||||
callback(true);
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
// 迁移到独立目录
|
||||
migrateAllDBs: function (userId, callback, msgCallbac) {
|
||||
var me = this;
|
||||
var names = ['notebooks', 'notes', 'tags', 'images', 'attachs', 'noteHistories'];
|
||||
// notes, notebooks, tags, attachs, images, noteHistories
|
||||
// 判断当前db是否是全局的, 如果不是, 则初始化全局的
|
||||
var sourceDb = {};
|
||||
if (Api.userService.hasDB) {
|
||||
Api.dbService.initIt(sourceDb, names, '', false);
|
||||
}
|
||||
else {
|
||||
sourceDb = Api.dbService;
|
||||
}
|
||||
|
||||
// 如果dist数据存在, 则删除之, 不用删除, 大不了插入失败
|
||||
|
||||
// 初始化dist
|
||||
var distDb = {};
|
||||
Api.dbService.initIt(distDb, names, userId, true);
|
||||
|
||||
// OK, 为每个表进行迁移
|
||||
async.eachSeries(names, function(name, cb) {
|
||||
msgCallbac('正在优化 ' + name);
|
||||
console.log('正在优化 ' + name);
|
||||
|
||||
if (name === 'noteHistories') {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
me.migrateEach(userId, sourceDb, distDb, name, function(ok) {
|
||||
if (ok) {
|
||||
console.log(name + ' Over');
|
||||
msgCallbac(name + ' 优化完成');
|
||||
}
|
||||
else {
|
||||
console.log(name + ' 迁移失败');
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}, function () {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return setLang;
|
||||
|
||||
});
|
16
public/plugins/accounts/plugin.json
Normal file
16
public/plugins/accounts/plugin.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "langs",
|
||||
"author": "life",
|
||||
"authorUrl": "http://life.leanote.com",
|
||||
"desc": "语言",
|
||||
"langs": {
|
||||
"en-us": {
|
||||
"pluginName": "Langs",
|
||||
"pluginDesc": ""
|
||||
},
|
||||
"zh-cn": {
|
||||
"pluginName": "设置语言",
|
||||
"pluginDesc": ""
|
||||
}
|
||||
}
|
||||
}
|
@@ -2764,6 +2764,9 @@ background-position:-1px -670px
|
||||
border-top: 1px dashed #eee;
|
||||
padding: 5px 0;
|
||||
}
|
||||
#loadingDialog {
|
||||
z-index: 999999;
|
||||
}
|
||||
#loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
|
@@ -758,6 +758,9 @@ background-position:-1px -670px
|
||||
}
|
||||
}
|
||||
|
||||
#loadingDialog {
|
||||
z-index: 999999;
|
||||
}
|
||||
#loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
|
Reference in New Issue
Block a user