Compare commits
11
Commits
1.3.1
..
dev-binnchx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb484b2132 | ||
|
|
4d5a3ffd0f | ||
|
|
f78eb4db49 | ||
|
|
c35aa1eaa4 | ||
|
|
96b094844e | ||
|
|
9af13bcc32 | ||
|
|
29215a1d64 | ||
|
|
d828a10e7b | ||
|
|
a851aaa399 | ||
|
|
a393bb8723 | ||
|
|
599e54de5b |
No files matched your search
+3
-3
@@ -2,9 +2,9 @@
|
|||||||
pkg
|
pkg
|
||||||
bin2
|
bin2
|
||||||
bin/i18n
|
bin/i18n
|
||||||
bin/leanote*
|
bin/leanote-linux
|
||||||
|
bin/leanote-mac
|
||||||
bin/release
|
bin/release
|
||||||
bin/test.sh
|
|
||||||
bin/tmp
|
bin/tmp
|
||||||
bin/test
|
bin/test
|
||||||
bin/src
|
bin/src
|
||||||
@@ -16,4 +16,4 @@ app/tmp/main.go
|
|||||||
.project
|
.project
|
||||||
public/config.codekit
|
public/config.codekit
|
||||||
files
|
files
|
||||||
/node_modules
|
conf/app.conf
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>leanote-public</name>
|
|
||||||
<comment>leanote, your own cloud note!</comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.googlecode.goclipse.goBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>goclipse.goNature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
language: go
|
|
||||||
go: 1.3
|
|
||||||
|
|
||||||
services:
|
|
||||||
- mongodb # 2.4.12
|
|
||||||
|
|
||||||
install:
|
|
||||||
- export PATH=$PATH:$HOME/gopath/bin
|
|
||||||
- go get -v github.com/leanote/leanote/app
|
|
||||||
- go get -u github.com/revel/cmd/revel
|
|
||||||
- ls $GOPATH/src/github.com/revel/
|
|
||||||
# - go get github.com/revel/moudle/revel
|
|
||||||
# - go install github.com/revel/cmd/revel
|
|
||||||
- pwd
|
|
||||||
- ls
|
|
||||||
|
|
||||||
script:
|
|
||||||
- mongo --version
|
|
||||||
- mongorestore -h localhost -d leanote --directoryperdb ./mongodb_backup/leanote_install_data/
|
|
||||||
|
|
||||||
- go test github.com/leanote/leanote/app/tests
|
|
||||||
|
|
||||||
# gen tmp/main.go, routes/routes.go
|
|
||||||
- go run app/cmd/main.go
|
|
||||||
# build
|
|
||||||
- go build -o leanote github.com/leanote/leanote/app/tmp
|
|
||||||
# run with port 9000
|
|
||||||
- ./leanote -importPath=github.com/leanote/leanote -runMode=dev -port=9000 &
|
|
||||||
- sleep 10s;
|
|
||||||
# test
|
|
||||||
- curl http://localhost:9000
|
|
||||||
- curl http://localhost:9000/blog
|
|
||||||
- curl http://localhost:9000/login
|
|
||||||
- curl http://localhost:9000/demo
|
|
||||||
|
|
||||||
# - revel build github.com/leanote/leanote tmp
|
|
||||||
# OK
|
|
||||||
-345
@@ -1,345 +0,0 @@
|
|||||||
var gulp = require('gulp');
|
|
||||||
var clean = require('gulp-clean');
|
|
||||||
var uglify = require('gulp-uglify');
|
|
||||||
var rename = require('gulp-rename');
|
|
||||||
var minifyHtml = require("gulp-minify-html");
|
|
||||||
var concat = require('gulp-concat');
|
|
||||||
var replace = require('gulp-replace');
|
|
||||||
var inject = require('gulp-inject');
|
|
||||||
var gulpSequence = require('gulp-sequence');
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var leanoteBase = './';
|
|
||||||
var base = leanoteBase + '/public'; // public base
|
|
||||||
var noteDev = leanoteBase + '/app/views/note/note-dev.html';
|
|
||||||
var noteProBase = leanoteBase + '/app/views/note';
|
|
||||||
|
|
||||||
// 合并Js, 这些js都是不怎么修改, 且是依赖
|
|
||||||
// 840kb, 非常耗时!!
|
|
||||||
gulp.task('concatDepJs', function() {
|
|
||||||
var jss = [
|
|
||||||
'js/jquery-1.9.0.min.js',
|
|
||||||
'js/jquery.ztree.all-3.5-min.js',
|
|
||||||
'tinymce/tinymce.full.min.js', // 使用打成的包, 加载速度快
|
|
||||||
// 'libs/ace/ace.js',
|
|
||||||
'js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js',
|
|
||||||
'js/contextmenu/jquery.contextmenu-min.js',
|
|
||||||
'js/bootstrap-min.js',
|
|
||||||
'js/object_id-min.js',
|
|
||||||
];
|
|
||||||
|
|
||||||
for(var i in jss) {
|
|
||||||
jss[i] = base + '/' + jss[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return gulp
|
|
||||||
.src(jss)
|
|
||||||
// .pipe(uglify()) // 压缩
|
|
||||||
.pipe(concat('dep.min.js'))
|
|
||||||
.pipe(gulp.dest(base + '/js'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 合并app js 这些js会经常变化 90kb
|
|
||||||
gulp.task('concatAppJs', function() {
|
|
||||||
var jss = [
|
|
||||||
'js/common.js',
|
|
||||||
'js/app/note.js',
|
|
||||||
'js/app/page.js', // 写作模式下, page依赖note
|
|
||||||
'js/app/tag.js',
|
|
||||||
'js/app/notebook.js',
|
|
||||||
'js/app/share.js',
|
|
||||||
];
|
|
||||||
|
|
||||||
for(var i in jss) {
|
|
||||||
jss[i] = base + '/' + jss[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return gulp
|
|
||||||
.src(jss)
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
.pipe(concat('app.min.js'))
|
|
||||||
.pipe(gulp.dest(base + '/js'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// 合并requirejs和markdown为一个文件
|
|
||||||
gulp.task('concatMarkdownJs', function() {
|
|
||||||
var jss = [
|
|
||||||
'js/require.js',
|
|
||||||
'dist/main.min.js',
|
|
||||||
];
|
|
||||||
|
|
||||||
for(var i in jss) {
|
|
||||||
jss[i] = base + '/' + jss[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return gulp
|
|
||||||
.src(jss)
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
.pipe(concat('markdown.min.js'))
|
|
||||||
.pipe(gulp.dest(base + '/js'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// note-dev.html -> note.html, 替换css, js
|
|
||||||
// TODO 加?t=2323232, 强制浏览器更新, 一般只需要把app.min.js上加
|
|
||||||
gulp.task('devToProHtml', function() {
|
|
||||||
return gulp
|
|
||||||
.src(noteDev)
|
|
||||||
.pipe(replace(/<!-- dev -->[.\s\S]+?<!-- \/dev -->/g, '')) // 把dev 去掉
|
|
||||||
.pipe(replace(/<!-- pro_dep_js -->/, '<script src="/js/dep.min.js"></script>')) // 替换
|
|
||||||
.pipe(replace(/<!-- pro_app_js -->/, '<script src="/js/app.min.js"></script>')) // 替换
|
|
||||||
.pipe(replace(/<!-- pro_markdown_js -->/, '<script src="/js/markdown.min.js"></script>')) // 替换
|
|
||||||
.pipe(replace(/<!-- pro_tinymce_init_js -->/, "var tinyMCEPreInit = {base: '/public/tinymce', suffix: '.min'};")) // 替换
|
|
||||||
.pipe(replace(/plugins\/main.js/, "plugins/main.min.js")) // 替换
|
|
||||||
// 连续两个空行换成一个空行, 没用
|
|
||||||
.pipe(replace(/\n\n/g, '\n'))
|
|
||||||
.pipe(replace(/\n\n/g, '\n'))
|
|
||||||
.pipe(replace('console.log(o);', ''))
|
|
||||||
// .pipe(minifyHtml()) // 不行, 压缩后golang报错
|
|
||||||
.pipe(rename('note.html'))
|
|
||||||
.pipe(gulp.dest(noteProBase));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get used keys
|
|
||||||
// 只获取需要js i18n的key
|
|
||||||
var path = require('path');
|
|
||||||
gulp.task('i18n', function() {
|
|
||||||
var keys = {};
|
|
||||||
var reg = /getMsg\(["']+(.+?)["']+/g;
|
|
||||||
function getKey(data) {
|
|
||||||
while(ret = reg.exec(data)) {
|
|
||||||
keys[ret[1]] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 先获取需要的key
|
|
||||||
function ls(ff) {
|
|
||||||
var files = fs.readdirSync(ff);
|
|
||||||
for(fn in files) {
|
|
||||||
var fname = ff + path.sep + files[fn];
|
|
||||||
var stat = fs.lstatSync(fname);
|
|
||||||
if(stat.isDirectory() == true) {
|
|
||||||
ls(fname);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((fname.indexOf('.html') > 0 || fname.indexOf('.js') > 0)) {
|
|
||||||
// console.log(fname);
|
|
||||||
// if (fname.indexOf('min.js') < 0) {
|
|
||||||
var data = fs.readFileSync(fname, "utf-8");
|
|
||||||
// 得到getMsg里的key
|
|
||||||
getKey(data);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('parsing used keys');
|
|
||||||
|
|
||||||
ls(base + '/admin');
|
|
||||||
ls(base + '/blog');
|
|
||||||
ls(base + '/dist');
|
|
||||||
ls(base + '/js');
|
|
||||||
ls(base + '/album');
|
|
||||||
ls(base + '/libs');
|
|
||||||
ls(base + '/member');
|
|
||||||
ls(base + '/tinymce');
|
|
||||||
|
|
||||||
console.log('parsed');
|
|
||||||
|
|
||||||
// msg.zh
|
|
||||||
function getAllMsgs(fname) {
|
|
||||||
var msg = {};
|
|
||||||
|
|
||||||
var data = fs.readFileSync(fname, "utf-8");
|
|
||||||
var lines = data.split('\n');
|
|
||||||
for (var i = 0; i < lines.length; ++i) {
|
|
||||||
var line = lines[i];
|
|
||||||
// 忽略注释
|
|
||||||
if (line[0] == '#' || line[1] == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var lineArr = line.split('=');
|
|
||||||
if (lineArr.length >= 2) {
|
|
||||||
var key = lineArr[0];
|
|
||||||
lineArr.shift();
|
|
||||||
msg[key] = lineArr.join('=');
|
|
||||||
// msg[lineArr[0]] = lineArr[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// msg.zh, msg.js
|
|
||||||
function genI18nJsFile(fromFilename, keys) {
|
|
||||||
var msgs = getAllMsgs(leanoteBase + '/messages/' + fromFilename);
|
|
||||||
var toFilename = fromFilename + '.js';
|
|
||||||
var toMsgs = {};
|
|
||||||
for (var i in msgs) {
|
|
||||||
// 只要需要的
|
|
||||||
if (i in keys) {
|
|
||||||
toMsgs[i] = msgs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var str = 'var MSG=' + JSON.stringify(toMsgs) + ';';
|
|
||||||
str += 'function getMsg(key, data) {var msg = MSG[key];if(msg) {if(data) {if(!isArray(data)) {data = [data];}' +
|
|
||||||
'for(var i = 0; i < data.length; ++i) {' +
|
|
||||||
'msg = msg.replace("%s", data[i]);' +
|
|
||||||
'}' +
|
|
||||||
'}' +
|
|
||||||
'return msg;' +
|
|
||||||
'}' +
|
|
||||||
'return key;' +
|
|
||||||
'}';
|
|
||||||
// 写入到文件中
|
|
||||||
fs.writeFile(base + '/js/i18n/' + toFilename, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
genI18nJsFile('msg.zh', keys);
|
|
||||||
genI18nJsFile('msg.en', keys);
|
|
||||||
genI18nJsFile('msg.fr', keys);
|
|
||||||
genI18nJsFile('blog.zh', keys);
|
|
||||||
genI18nJsFile('blog.en', keys);
|
|
||||||
genI18nJsFile('blog.fr', keys);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// 合并album需要的js
|
|
||||||
gulp.task('concatAlbumJs', function() {
|
|
||||||
/*
|
|
||||||
gulp.src(base + '/album/js/main.js')
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
.pipe(rename({suffix: '.min'}))
|
|
||||||
.pipe(gulp.dest(base + '/album/js/'));
|
|
||||||
*/
|
|
||||||
|
|
||||||
gulp.src(base + '/album/css/style.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/album/css'));
|
|
||||||
|
|
||||||
var jss = [
|
|
||||||
'js/jquery-1.9.0.min.js',
|
|
||||||
'js/bootstrap-min.js',
|
|
||||||
'js/plugins/libs-min/fileupload.js',
|
|
||||||
'js/jquery.pagination.js',
|
|
||||||
'album/js/main.js',
|
|
||||||
];
|
|
||||||
|
|
||||||
for(var i in jss) {
|
|
||||||
jss[i] = base + '/' + jss[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return gulp
|
|
||||||
.src(jss)
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
.pipe(concat('main.all.js'))
|
|
||||||
.pipe(gulp.dest(base + '/album/js'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// plugins压缩
|
|
||||||
gulp.task('plugins', function() {
|
|
||||||
gulp.src(base + '/js/plugins/libs/*.js')
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
// .pipe(concat('main.min.js'))
|
|
||||||
.pipe(gulp.dest(base + '/js/plugins/libs-min'));
|
|
||||||
|
|
||||||
|
|
||||||
// 所有js合并成一个
|
|
||||||
var jss = [
|
|
||||||
'note_info',
|
|
||||||
'tips',
|
|
||||||
'history',
|
|
||||||
'attachment_upload',
|
|
||||||
'editor_drop_paste',
|
|
||||||
'main'
|
|
||||||
];
|
|
||||||
|
|
||||||
for(var i in jss) {
|
|
||||||
jss[i] = base + '/js/plugins/' + jss[i] + '.js';
|
|
||||||
}
|
|
||||||
|
|
||||||
gulp.src(jss)
|
|
||||||
.pipe(uglify()) // 压缩
|
|
||||||
.pipe(concat('main.min.js'))
|
|
||||||
.pipe(gulp.dest(base + '/js/plugins'));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// mincss
|
|
||||||
var minifycss = require('gulp-minify-css');
|
|
||||||
gulp.task('minifycss', function() {
|
|
||||||
gulp.src(base + '/css/bootstrap.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/css'));
|
|
||||||
|
|
||||||
gulp.src(base + '/css/font-awesome-4.2.0/css/font-awesome.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/css/font-awesome-4.2.0/css'));
|
|
||||||
|
|
||||||
gulp.src(base + '/css/zTreeStyle/zTreeStyle.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/css/zTreeStyle'));
|
|
||||||
|
|
||||||
gulp.src(base + '/dist/themes/default.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/dist/themes'));
|
|
||||||
|
|
||||||
gulp.src(base + '/js/contextmenu/css/contextmenu.css')
|
|
||||||
.pipe(rename({suffix: '-min'}))
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/js/contextmenu/css'));
|
|
||||||
|
|
||||||
// theme
|
|
||||||
// 用codekit
|
|
||||||
var as = ['default', 'simple', 'writting', /*'writting-overwrite', */ 'mobile'];
|
|
||||||
/*
|
|
||||||
for(var i = 0; i < as.length; ++i) {
|
|
||||||
gulp.src(base + '/css/theme/' + as[i] + '.css')
|
|
||||||
.pipe(minifycss())
|
|
||||||
.pipe(gulp.dest(base + '/css/theme'));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
|
|
||||||
// tinymce
|
|
||||||
// please set the right path on your own env
|
|
||||||
var tinymceBase = '/Users/life/leanote/leanote-tools/tinymce_4.1.9_leanote_public';
|
|
||||||
gulp.task('tinymce', function() {
|
|
||||||
// 先清理
|
|
||||||
fs.unlink(tinymceBase + '/js/tinymce/tinymce.dev.js');
|
|
||||||
fs.unlink(tinymceBase + '/js/tinymce/tinymce.jquery.dev.js');
|
|
||||||
fs.unlink(tinymceBase + '/js/tinymce/tinymce.full.js');
|
|
||||||
fs.unlink(tinymceBase + '/js/tinymce/tinymce.full.min.js');
|
|
||||||
|
|
||||||
var cp = require('child_process');
|
|
||||||
|
|
||||||
var bundleCmd = 'grunt bundle --themes leanote --plugins autolink,link,leaui_image,lists,hr,paste,searchreplace,leanote_nav,leanote_code,tabfocus,table,directionality,textcolor';
|
|
||||||
// build
|
|
||||||
cp.exec('grunt minify', {cwd: tinymceBase}, function(err, stdout, stderr) {
|
|
||||||
console.log('stdout: ' + stdout);
|
|
||||||
console.log('stderr: ' + stderr);
|
|
||||||
|
|
||||||
// 将所有都合并成一起
|
|
||||||
cp.exec(bundleCmd, {cwd: tinymceBase}, function(err, stdout, stderr) {
|
|
||||||
console.log('stdout: ' + stdout);
|
|
||||||
console.log('stderr: ' + stderr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 合并css, 无用
|
|
||||||
// Deprecated
|
|
||||||
gulp.task('concatCss', function() {
|
|
||||||
return gulp
|
|
||||||
.src([markdownRaw + '/css/default.css', markdownRaw + '/css/md.css'])
|
|
||||||
.pipe(concat('all.css'))
|
|
||||||
.pipe(gulp.dest(markdownMin));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('concat', ['concatDepJs', 'concatAppJs', 'concatMarkdownJs']);
|
|
||||||
gulp.task('html', ['devToProHtml']);
|
|
||||||
gulp.task('default', ['concat', 'plugins', 'minifycss', 'i18n', 'concatAlbumJs', 'html']);
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
LEANOTE - NOT JUST A NOTEPAD!
|
leanote - you own cloud note!
|
||||||
|
|
||||||
Copyright 2014-2015 by the contributors
|
Copyright 2014 by the contributors
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -12,7 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
Leanote is licensed under the GPL v2.
|
leanote is licensed under the GPL v2.
|
||||||
|
|
||||||
life(life@leanote.com, lifephp@gmail.com)
|
life(life@leanote.com, lifephp@gmail.com)
|
||||||
|
|
||||||
|
|||||||
@@ -1,167 +1,113 @@
|
|||||||
# Leanote
|
|
||||||
|
|
||||||
[](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
# Leanote
|
||||||
[](https://travis-ci.org/leanote/leanote)
|
|
||||||
|
|
||||||
## 1. Introduction
|
## 1. Introduction
|
||||||
|
|
||||||
Leanote, Not Just A Notepad!
|
Leanote, not just a notebook!
|
||||||

|

|
||||||
|
|
||||||
**Some Features**
|
**Some Features**
|
||||||
|
|
||||||
* Knowledge: Manage your knowledge in Leanote. Leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
|
* Knowledge: Manage your knowledge in leanote. leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
|
||||||
* Share: Share your knowledge with your friends in Leanote. You can invite your friends to join your notepad in the cloud so you can share knowledge.
|
* Share: Share your knowledge with your friends in leanote. You can invite your friends to join your notepad in the cloud so you can share knowledge.
|
||||||
* Cooperation: Collaborate with friends to improve your skills.
|
* Cooperation: Collaborate with friends to improve your skills.
|
||||||
* Blog: Publish your knowledge and make Leanote your blog.
|
* Blog: Publish your knowledge and make leanote your blog.
|
||||||
|
|
||||||
**Other Features**
|
## 2. Why we created leanote
|
||||||
|
|
||||||
* Support Markdown
|
|
||||||
* Writting mode
|
|
||||||
* Export note to PDF
|
|
||||||
* Note batch operation
|
|
||||||
* Custom theme for blog
|
|
||||||
|
|
||||||
## 2. Why we created Leanote
|
|
||||||
To be honest, our inspiration comes from Evernote. We use Evernote to manage our knowledge everyday. But we find that:
|
To be honest, our inspiration comes from Evernote. We use Evernote to manage our knowledge everyday. But we find that:
|
||||||
* Evernote's editor can't meet our needs, it does not have document navigation, it does not render code properly (as a programmer, syntax highlighted code rendering is a basic need), it cannot resize images and so forth
|
* Evernote's editor can't meet our needs, it does not have document navigation, it does not render code properly (as a programmer, syntax highlighted code rendering is a basic need), it cannot resize images and so forth
|
||||||
* We like markdown, but Evernote does not support it.
|
* We like markdown, but Evernote does not support it.
|
||||||
* We want to share our knowledge, so all of us have our blogs (e.g. on Wordpress) and our Evernote accounts, but why can not those two be one!
|
* We want to share our knowledge, so all of us have our blogs (e.g. on Wordpress) and our Evernote accounts, but why can not those two be one!
|
||||||
* ......
|
* ......
|
||||||
|
|
||||||
## 3. How to install Leanote
|
## 3. How to install leanote
|
||||||
|
|
||||||
Leanote contains: Leanote Web & Server (this repository), [Desktop app](https://github.com/leanote/desktop-app), [iOS](https://github.com/leanote/leanote-ios), [Android](https://github.com/leanote/leanote-android). And all the products are open source!
|
More information about how to install leanote please see:
|
||||||
|
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
||||||
|
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
||||||
|
|
||||||
You can install Leanote on your server, and use Leanote App (Desktop, iOs, Android) to sync notes with your self-hosted server.
|
### 3.1. Download leanote
|
||||||
|
|
||||||
Welcome to sign up on https://leanote.com, Leanote team provide a stable and reliable service for you.
|
Leanote V1.0.2-beta has been released. Binaries:
|
||||||
|
|
||||||
More information about how to install Leanote please see:
|
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.2.tar.gz)
|
||||||
|
|
||||||
* [Leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
Or you can clone [Leanote bin repository](https://github.com/leanote/leanote-bin) (Recommend)
|
||||||
* [Leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
|
||||||
|
|
||||||
## 4. How to develop Leanote
|
### 3.2. Install MongoDB
|
||||||
|
|
||||||
|
Leanote is written in go using [revel](https://revel.github.io/) and [MongoDB](https://www.mongodb.org). Thus, you need to first install MongoDB.
|
||||||
|
|
||||||
|
For more tips please have a look at [our wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
|
### 3.3. Import initial MongoDB data
|
||||||
|
|
||||||
|
The mongodb data is in `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
|
The initial database contains two users:
|
||||||
|
|
||||||
|
```
|
||||||
|
user2 username: admin, password: abc123 (administrator)
|
||||||
|
user3 username: demo, password: demo@leanote.com (this user is for demo)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4. Configuration
|
||||||
|
|
||||||
|
Modify `[PATH_TO_LEANOTE]/conf/app.conf`. Available configuration options are:
|
||||||
|
|
||||||
|
``mongodb`` **required**
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
db.host=localhost
|
||||||
|
db.port=27017
|
||||||
|
db.dbname=leanote
|
||||||
|
db.username=
|
||||||
|
db.password=
|
||||||
|
```
|
||||||
|
|
||||||
|
``app.secret`` **required** **important**
|
||||||
|
The secret key used for cryptographic operations (revel.Sign).
|
||||||
|
|
||||||
|
FOR SECURITY, YOU MUST CHANGE IT!!
|
||||||
|
|
||||||
|
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
|
||||||
|
|
||||||
|
### 3.5. Run leanote
|
||||||
|
|
||||||
|
```
|
||||||
|
$> cd PATH_TO_LEANOTE/bin
|
||||||
|
$> sudo sh run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. How to develop leanote
|
||||||
|
|
||||||
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
## 5. Docs
|
|
||||||
* [Leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
|
||||||
* [Leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
|
||||||
|
|
||||||
More docs please see [wiki](https://github.com/leanote/leanote/wiki).
|
## 5. Contributors
|
||||||
|
|
||||||
## 6. Contributors
|
|
||||||
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
||||||
this project. Your help is much appreciated.
|
this project. Your help is much appreciated.
|
||||||
|
|
||||||
## 7.Join us
|
## 6. Contributing
|
||||||
|
|
||||||
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||||
|
|
||||||
If you find some problems or has some good ideas, please submit [issues](https://github.com/leanote/leanote/issues).
|
## Docs
|
||||||
|
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
||||||
|
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
||||||
|
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
|
||||||
|
|
||||||
You are always welcomed!
|
## Discussion
|
||||||
|
* [leanote bbs](http://bbs.leanote.com)
|
||||||
## 8. Donation
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
Support us, [donate us](http://leanote.org/#donate). And thanks [donators](http://leanote.leanote.com/post/leanote-donation-list).
|
* QQ Group: 158716820
|
||||||
|
|
||||||
## 9. Related projects
|
|
||||||
|
|
||||||
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [Download](http://app.leanote.com)
|
|
||||||
* [Leanote iOS](https://github.com/leanote/leanote-ios), [Download From App Store](https://itunes.apple.com/en/app/leanote/id1022302858?mt=8)
|
|
||||||
* [Leanote Android](https://github.com/leanote/leanote-android), development phase
|
|
||||||
|
|
||||||
Yare are welcome to join us.
|
|
||||||
|
|
||||||
## 9. Support & Join us
|
|
||||||
|
|
||||||
* Email: leanote@leanote.com
|
|
||||||
* [Leanote BBS](http://bbs.leanote.com)
|
|
||||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
|
||||||
* QQ Group: 256076853, 158716820
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
[中文](README_zh.md)
|
||||||
|
|
||||||
# Leanote
|
|
||||||
|
|
||||||
## 1. 介绍
|
|
||||||
|
|
||||||
Leanote, 不只是笔记!
|
|
||||||
|
|
||||||
**特性**
|
|
||||||
|
|
||||||
* 知识管理: 通过Leanote来管理知识, Leanote有易操作的界面, 包含两款编辑器富文本编辑器和Markdown编辑器. 在Leanote, 你可以尽情享受写作.
|
|
||||||
* 博客: Leanote也可以作为你的博客, 将知识公开成博客, 让Leanote把你的知识传播的更远!
|
|
||||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
|
||||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
|
||||||
|
|
||||||
**一些其它特性**
|
|
||||||
|
|
||||||
* 支持Markdown编辑
|
|
||||||
* 写作模式
|
|
||||||
* 支持PDF导出
|
|
||||||
* 支持批量操作
|
|
||||||
* 博客自定义主题, 实现高度定制化
|
|
||||||
|
|
||||||
## 2. 为什么我们要创建Leanote?
|
|
||||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
|
||||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
|
||||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
|
||||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
|
||||||
* 还有...
|
|
||||||
|
|
||||||
## 3.安装Leanote
|
|
||||||
|
|
||||||
Leanote云笔记产品包括: Leanote Web & Server(即本仓库), 桌面客户端, ios, android. 4端全部开源! 你可以下载它安装在自己的服务器上, Leanote的客户端可以连接自建的服务.
|
|
||||||
|
|
||||||
欢迎在 https://leanote.com 上注册, Leanote团队为你提供稳定可靠的服务.
|
|
||||||
|
|
||||||
这里详细整理了Leanote二进版和Leanote开发版的安装教程, 请移步至:
|
|
||||||
|
|
||||||
* [Leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
|
|
||||||
## 4. 如何对Leanote进行二次开发
|
|
||||||
|
|
||||||
请查看 [How-to-develop-Leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
|
||||||
|
|
||||||
## 5 相关文档
|
|
||||||
* [Leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote source Leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
|
||||||
* [Leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
|
||||||
* [How to develop leanote 如何开发Leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
|
||||||
|
|
||||||
更多文档请查看 [wiki](https://github.com/leanote/leanote/wiki).
|
|
||||||
|
|
||||||
## 6. 贡献者
|
|
||||||
|
|
||||||
谢谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, Leanote因有你们而更完美!
|
|
||||||
|
|
||||||
## 7. 加入我们
|
|
||||||
|
|
||||||
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到Leanote.
|
|
||||||
|
|
||||||
有任何问题或建议, 欢迎提交[issue](https://github.com/leanote/leanote/issues).
|
|
||||||
|
|
||||||
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善Leanote.
|
|
||||||
|
|
||||||
## 8. 捐赠
|
|
||||||
支持我们, [捐赠Leanote](http://leanote.org/#donate). 感谢[捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
|
|
||||||
|
|
||||||
## 9. 其它相关项目
|
|
||||||
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
|
|
||||||
* [Leanote iOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
|
|
||||||
* [Leanote Android](https://github.com/leanote/leanote-android), 开发阶段
|
|
||||||
|
|
||||||
欢迎加入我们!
|
|
||||||
|
|
||||||
## 联系&加入我们
|
|
||||||
* Email: leanote@leanote.com
|
|
||||||
* [Leanote 社区](http://bbs.leanote.com)
|
|
||||||
* QQ群: 256076853, 158716820(已满)
|
|
||||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
|
||||||
|
|
||||||
+88
-48
@@ -1,73 +1,113 @@
|
|||||||
# Leanote
|
|
||||||
|
|
||||||
[](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
# Leanote产品
|
||||||
[](https://travis-ci.org/leanote/leanote)
|
|
||||||
## 1. 介绍
|
|
||||||
|
|
||||||
Leanote, 不只是笔记!
|
## 1. 介绍
|
||||||
|
|
||||||
|
Leanote, 不只是笔记!
|
||||||

|

|
||||||
|
|
||||||
**特性**
|
**特性**
|
||||||
|
|
||||||
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||||
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||||
|
|
||||||
## 2. 为什么我们要创建leanote?
|
## 2. 为什么我们要创建leanote?
|
||||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||||
* 还有...
|
* 还有...
|
||||||
|
|
||||||
## 3.安装leanote
|
## 3.安装leanote
|
||||||
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||||
|
|
||||||
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||||
|
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
|
||||||
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
### 3.1. 下载leanote
|
||||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
|
|
||||||
## 4. 如何对leanote进行二次开发
|
Leanote V1.0-beta.2 已发布, 二进制文件(暂时没有windows版的):
|
||||||
|
|
||||||
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
|
||||||
## 5 相关文档
|
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
|
||||||
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
|
||||||
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
|
||||||
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
|
||||||
|
|
||||||
更多文档请查看 [wiki](https://github.com/leanote/leanote/wiki).
|
### 3.2. 安装 MongodbDB
|
||||||
|
|
||||||
## 6. 贡献者
|
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||||
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
|
||||||
|
|
||||||
## 7. 加入我们
|
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
### 3.3. 导入初始数据
|
||||||
|
|
||||||
有任何问题或建议, 欢迎提交[issue](https://github.com/leanote/leanote/issues).
|
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
## 8. 捐赠
|
初始数据包含两个用户:
|
||||||
支持我们, [捐赠Leanote](http://leanote.org/#donate). 感谢[捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
|
|
||||||
|
|
||||||
## 9. 其它相关项目
|
```
|
||||||
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
|
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||||
* [Leanote IOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
|
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||||
* [Leanote Android](https://github.com/Dminter/leanote-android-client), 开发阶段
|
```
|
||||||
|
|
||||||
欢迎加入我们!
|
### 3.4. 配置
|
||||||
|
|
||||||
## 联系&加入我们
|
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||||
* Email: leanote@leanote.com
|
|
||||||
* [leanote 社区](http://bbs.leanote.com)
|
``mongodb`` **必须配置!**
|
||||||
* QQ群: 158716820, 256076853
|
|
||||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
```Shell
|
||||||
|
db.host=localhost
|
||||||
|
db.port=27017
|
||||||
|
db.dbname=leanote
|
||||||
|
db.username=
|
||||||
|
db.password=
|
||||||
|
```
|
||||||
|
|
||||||
|
``app.secret`` **重要**
|
||||||
|
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
|
||||||
|
|
||||||
|
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
|
||||||
|
|
||||||
|
### 3.5. 运行leanote
|
||||||
|
|
||||||
|
```
|
||||||
|
$> cd PATH_TO_LEANOTE/bin
|
||||||
|
$> sudo sh run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 如何对leanote进行二次开发
|
||||||
|
|
||||||
|
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
|
## 5. 贡献者
|
||||||
|
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
||||||
|
|
||||||
|
## 6. 加入我们
|
||||||
|
|
||||||
|
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
||||||
|
|
||||||
|
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
||||||
|
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
||||||
|
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
||||||
|
|
||||||
|
|
||||||
|
## 讨论
|
||||||
|
* [leanote 社区](http://bbs.leanote.com)
|
||||||
|
* QQ群: 158716820
|
||||||
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
[English](README.md)
|
[English](README.md)
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"github.com/revel/cmd/harness"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// go run main.go
|
|
||||||
// 生成routes.go, main.go
|
|
||||||
revel.Init("", "github.com/leanote/leanote", "")
|
|
||||||
_, err := harness.Build() // ok, err
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Println("Ok")
|
|
||||||
// panicOnError(reverr, "Failed to build")
|
|
||||||
}
|
|
||||||
@@ -14,17 +14,12 @@ type Album struct {
|
|||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片管理, iframe
|
|
||||||
func (c Album) Index() revel.Result {
|
|
||||||
c.SetLocale();
|
|
||||||
return c.RenderTemplate("album/index.html")
|
|
||||||
}
|
|
||||||
|
|
||||||
// all albums by userId
|
// all albums by userId
|
||||||
func (c Album) GetAlbums() revel.Result {
|
func (c Album) GetAlbums() revel.Result {
|
||||||
re := albumService.GetAlbums(c.GetUserId())
|
re := albumService.GetAlbums(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
||||||
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
||||||
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
||||||
@@ -39,7 +34,7 @@ func (c Album) AddAlbum(name string) revel.Result {
|
|||||||
UserId: c.GetObjectUserId()}
|
UserId: c.GetObjectUserId()}
|
||||||
re := albumService.AddAlbum(album)
|
re := albumService.AddAlbum(album)
|
||||||
|
|
||||||
if re {
|
if(re) {
|
||||||
return c.RenderJson(album)
|
return c.RenderJson(album)
|
||||||
} else {
|
} else {
|
||||||
return c.RenderJson(false)
|
return c.RenderJson(false)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
|||||||
id := bson.NewObjectId();
|
id := bson.NewObjectId();
|
||||||
fileInfo.AttachId = id
|
fileInfo.AttachId = id
|
||||||
fileId = id.Hex()
|
fileId = id.Hex()
|
||||||
Ok, resultMsg = attachService.AddAttach(fileInfo, false)
|
Ok, resultMsg = attachService.AddAttach(fileInfo)
|
||||||
if resultMsg != "" {
|
if resultMsg != "" {
|
||||||
resultMsg = c.Message(resultMsg)
|
resultMsg = c.Message(resultMsg)
|
||||||
}
|
}
|
||||||
@@ -129,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
|
|||||||
|
|
||||||
// 下载附件
|
// 下载附件
|
||||||
// 权限判断
|
// 权限判断
|
||||||
func (c Attach) Download(attachId string) revel.Result {
|
func (c Attach) Download(attachId, token string) revel.Result {
|
||||||
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
|
if c.GetUserId() == "" && token == "" {
|
||||||
|
return c.RenderText("你需要从分享页面下载附件!")
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
|
||||||
path := attach.Path
|
path := attach.Path
|
||||||
|
|
||||||
|
if token != "" && attach.Path == "" {
|
||||||
|
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
|
||||||
|
}
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return c.RenderText("")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
// "strconv"
|
// "strconv"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
// 用户登录/注销/找回密码
|
||||||
@@ -40,36 +41,36 @@ func (c Auth) Login(email, from string) revel.Result {
|
|||||||
func (c Auth) doLogin(email, pwd string) revel.Result {
|
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.Id()
|
||||||
var msg = ""
|
var msg = ""
|
||||||
|
fmt.Println(sessionId)
|
||||||
userInfo, err := authService.Login(email, pwd)
|
userInfo := authService.Login(email, pwd)
|
||||||
if err != nil {
|
if userInfo.Email != "" {
|
||||||
// 登录错误, 则错误次数++
|
|
||||||
msg = "wrongUsernameOrPassword"
|
|
||||||
} else {
|
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
sessionService.ClearLoginTimes(sessionId)
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
return c.RenderJson(info.Re{Ok: true})
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
||||||
}
|
}
|
||||||
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.Id()
|
||||||
var msg = ""
|
|
||||||
|
|
||||||
|
var msg = ""
|
||||||
// > 5次需要验证码, 直到登录成功
|
// > 5次需要验证码, 直到登录成功
|
||||||
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||||
msg = "captchaError"
|
msg = "captchaError"
|
||||||
} else {
|
} else {
|
||||||
userInfo, err := authService.Login(email, pwd)
|
userInfo := authService.Login(email, pwd)
|
||||||
if err != nil {
|
if userInfo.Email != "" {
|
||||||
// 登录错误, 则错误次数++
|
|
||||||
msg = "wrongUsernameOrPassword"
|
|
||||||
sessionService.IncrLoginTimes(sessionId)
|
|
||||||
} else {
|
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
sessionService.ClearLoginTimes(sessionId)
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
return c.RenderJson(info.Re{Ok: true})
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
|
sessionService.IncrLoginTimes(sessionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,18 +86,9 @@ func (c Auth) Logout() revel.Result {
|
|||||||
|
|
||||||
// 体验一下
|
// 体验一下
|
||||||
func (c Auth) Demo() revel.Result {
|
func (c Auth) Demo() revel.Result {
|
||||||
email := configService.GetGlobalStringConfig("demoUsername")
|
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
|
||||||
pwd := configService.GetGlobalStringConfig("demoPassword")
|
|
||||||
|
|
||||||
userInfo, err := authService.Login(email, pwd)
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
|
||||||
} else {
|
|
||||||
c.SetSession(userInfo)
|
|
||||||
return c.Redirect("/note")
|
return c.Redirect("/note")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
// 注册
|
// 注册
|
||||||
|
|||||||
@@ -84,13 +84,6 @@ func (c BaseController) GetUserInfo() info.User {
|
|||||||
return info.User{}
|
return info.User{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c BaseController) GetUserAndBlogUrl() info.UserAndBlogUrl {
|
|
||||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
|
||||||
return userService.GetUserAndBlogUrl(userId);
|
|
||||||
}
|
|
||||||
return info.UserAndBlogUrl{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这里的session都是cookie中的, 与数据库session无关
|
// 这里的session都是cookie中的, 与数据库session无关
|
||||||
func (c BaseController) GetSession(key string) string {
|
func (c BaseController) GetSession(key string) string {
|
||||||
v, ok := c.Session[key]
|
v, ok := c.Session[key]
|
||||||
|
|||||||
@@ -200,73 +200,29 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
cates := make([]*info.Cate, len(notebooks))
|
cates := make([]map[string]string, len(notebooks))
|
||||||
|
|
||||||
// 先要保证已有的是正确的排序
|
// 先要保证已有的是正确的排序
|
||||||
cateIds := userBlog.CateIds
|
cateIds := userBlog.CateIds
|
||||||
has := map[string]bool{} // cateIds中有的
|
has := map[string]bool{} // cateIds中有的
|
||||||
cateMap := map[string]*info.Cate{}
|
|
||||||
if cateIds != nil && len(cateIds) > 0 {
|
if cateIds != nil && len(cateIds) > 0 {
|
||||||
for _, cateId := range cateIds {
|
for _, cateId := range cateIds {
|
||||||
if n, ok := notebooksMap[cateId]; ok {
|
if n, ok := notebooksMap[cateId]; ok {
|
||||||
parentNotebookId := ""
|
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": n.NotebookId.Hex()}
|
||||||
if n.ParentNotebookId != "" {
|
|
||||||
parentNotebookId = n.ParentNotebookId.Hex()
|
|
||||||
}
|
|
||||||
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: n.NotebookId.Hex(), ParentCateId: parentNotebookId}
|
|
||||||
cateMap[cates[i].CateId] = cates[i]
|
|
||||||
i++
|
i++
|
||||||
has[cateId] = true
|
has[cateId] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 之后
|
||||||
// 之后添加没有排序的
|
|
||||||
for _, n := range notebooks {
|
for _, n := range notebooks {
|
||||||
id := n.NotebookId.Hex()
|
id := n.NotebookId.Hex()
|
||||||
if !has[id] {
|
if !has[id] {
|
||||||
parentNotebookId := ""
|
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": id}
|
||||||
if n.ParentNotebookId != "" {
|
|
||||||
parentNotebookId = n.ParentNotebookId.Hex()
|
|
||||||
}
|
|
||||||
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: id, ParentCateId: parentNotebookId}
|
|
||||||
cateMap[cates[i].CateId] = cates[i]
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogJ(">>")
|
|
||||||
// LogJ(cates)
|
|
||||||
|
|
||||||
// 建立层级
|
|
||||||
hasParent := map[string]bool{} // 有父的cate
|
|
||||||
for _, cate := range cates {
|
|
||||||
parentCateId := cate.ParentCateId
|
|
||||||
if parentCateId != "" {
|
|
||||||
if parentCate, ok := cateMap[parentCateId]; ok {
|
|
||||||
// Log("________")
|
|
||||||
// LogJ(parentCate)
|
|
||||||
// LogJ(cate)
|
|
||||||
if parentCate.Children == nil {
|
|
||||||
parentCate.Children = []*info.Cate{cate}
|
|
||||||
} else {
|
|
||||||
parentCate.Children = append(parentCate.Children, cate)
|
|
||||||
}
|
|
||||||
hasParent[cate.CateId] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到没有父的cate, 作为第一级cate
|
|
||||||
catesTree := []*info.Cate{}
|
|
||||||
for _, cate := range cates {
|
|
||||||
if !hasParent[cate.CateId] {
|
|
||||||
catesTree = append(catesTree, cate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.RenderArgs["cates"] = cates
|
c.RenderArgs["cates"] = cates
|
||||||
c.RenderArgs["catesTree"] = catesTree
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单页
|
// 单页
|
||||||
@@ -348,10 +304,9 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
|
|||||||
// 得到主题信息
|
// 得到主题信息
|
||||||
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
|
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
|
||||||
c.RenderArgs["themeInfo"] = themeInfo
|
c.RenderArgs["themeInfo"] = themeInfo
|
||||||
|
Log(">>")
|
||||||
// Log(">>")
|
Log(userBlog.Style)
|
||||||
// Log(userBlog.Style)
|
Log(userBlog.ThemeId.Hex())
|
||||||
// Log(userBlog.ThemeId.Hex())
|
|
||||||
|
|
||||||
return true, userBlog
|
return true, userBlog
|
||||||
}
|
}
|
||||||
@@ -585,14 +540,19 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
|
|||||||
}
|
}
|
||||||
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
|
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
|
||||||
var ok = false
|
var ok = false
|
||||||
|
fmt.Println("before test...");
|
||||||
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
||||||
|
fmt.Println("404 occur");
|
||||||
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
||||||
}
|
}
|
||||||
|
fmt.Println("after test0...");
|
||||||
// 分页的话, 需要分页信息, totalPage, curPage
|
// 分页的话, 需要分页信息, totalPage, curPage
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
|
|
||||||
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
|
|
||||||
blogs2 := blogService.FixBlogs(blogs)
|
blogs2 := blogService.FixBlogs(blogs)
|
||||||
|
|
||||||
c.RenderArgs["posts"] = blogs2
|
c.RenderArgs["posts"] = blogs2
|
||||||
|
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
@@ -600,6 +560,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
|
|||||||
|
|
||||||
c.RenderArgs["curIsIndex"] = true
|
c.RenderArgs["curIsIndex"] = true
|
||||||
|
|
||||||
|
|
||||||
return c.render("index.html", userBlog.ThemePath)
|
return c.render("index.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,7 +782,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
|
|||||||
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJsonP(callback, re)
|
||||||
}
|
}
|
||||||
func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
func (c Blog) GetComments(noteId string) revel.Result {
|
||||||
// 评论
|
// 评论
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
@@ -834,10 +795,6 @@ func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
|||||||
result["commentUserInfo"] = commentUserInfo
|
result["commentUserInfo"] = commentUserInfo
|
||||||
re.Item = result
|
re.Item = result
|
||||||
|
|
||||||
if callback != "" {
|
|
||||||
return c.RenderJsonP(callback, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
|
||||||
// "strconv"
|
// "strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -75,7 +75,7 @@ func (c File) UploadAvatar() revel.Result {
|
|||||||
|
|
||||||
// leaui image plugin upload image
|
// leaui image plugin upload image
|
||||||
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||||
re := c.uploadImage("", albumId)
|
re := c.uploadImage("", albumId);
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,18 +100,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
// 生成上传路径
|
// 生成上传路径
|
||||||
newGuid := NewGuid()
|
|
||||||
|
|
||||||
userId := c.GetUserId()
|
|
||||||
|
|
||||||
if(from == "logo" || from == "blogLogo") {
|
if(from == "logo" || from == "blogLogo") {
|
||||||
fileUrlPath = "public/upload/" + Digest3(userId) + "/" + userId + "/images/logo"
|
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||||
} else {
|
} else {
|
||||||
fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
|
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
dir := revel.BasePath + "/" + fileUrlPath
|
||||||
err = os.MkdirAll(dir, 0755)
|
err = os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -120,18 +114,18 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
// 生成新的文件名
|
// 生成新的文件名
|
||||||
filename := handel.Filename
|
filename := handel.Filename
|
||||||
|
|
||||||
var ext string
|
var ext string;
|
||||||
if from == "pasteImage" {
|
if from == "pasteImage" {
|
||||||
ext = ".png" // TODO 可能不是png类型
|
ext = ".png"; // TODO 可能不是png类型
|
||||||
} else {
|
} else {
|
||||||
_, ext = SplitFilename(filename)
|
_, ext = SplitFilename(filename)
|
||||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||||
resultMsg = "Please upload image"
|
resultMsg = "Please upload image"
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = newGuid + ext
|
filename = NewGuid() + ext
|
||||||
data, err := ioutil.ReadAll(file)
|
data, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogJ(err)
|
LogJ(err)
|
||||||
@@ -139,25 +133,25 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var maxFileSize float64
|
var maxFileSize float64
|
||||||
if from == "logo" {
|
if(from == "logo") {
|
||||||
maxFileSize = configService.GetUploadSize("uploadAvatarSize")
|
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
|
||||||
} else if from == "blogLogo" {
|
} else if from == "blogLogo" {
|
||||||
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize")
|
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
|
||||||
} else {
|
} else {
|
||||||
maxFileSize = configService.GetUploadSize("uploadImageSize")
|
maxFileSize = configService.GetUploadSize("uploadImageSize");
|
||||||
}
|
}
|
||||||
if maxFileSize <= 0 {
|
if maxFileSize <= 0 {
|
||||||
maxFileSize = 1000
|
maxFileSize = 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
// > 2M?
|
// > 2M?
|
||||||
if float64(len(data)) > maxFileSize*float64(1024*1024) {
|
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||||
resultCode = 0
|
resultCode = 0
|
||||||
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
|
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
toPath := dir + "/" + filename
|
toPath := dir + "/" + filename;
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogJ(err)
|
LogJ(err)
|
||||||
@@ -177,18 +171,17 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
Path: fileUrlPath,
|
Path: fileUrlPath,
|
||||||
Size: filesize}
|
Size: filesize}
|
||||||
|
|
||||||
id := bson.NewObjectId()
|
id := bson.NewObjectId();
|
||||||
fileInfo.FileId = id
|
fileInfo.FileId = id
|
||||||
fileId = id.Hex()
|
fileId = id.Hex()
|
||||||
|
|
||||||
if(from == "logo" || from == "blogLogo") {
|
if(from == "logo" || from == "blogLogo") {
|
||||||
fileId = fileUrlPath
|
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
|
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
|
||||||
resultMsg = c.Message(resultMsg)
|
resultMsg = c.Message(resultMsg)
|
||||||
|
|
||||||
fileInfo.Path = "" // 不要返回
|
fileInfo.Path = ""; // 不要返回
|
||||||
re.Item = fileInfo
|
re.Item = fileInfo
|
||||||
|
|
||||||
return re
|
return re
|
||||||
@@ -211,13 +204,13 @@ func (c File) DeleteImage(fileId string) revel.Result {
|
|||||||
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
// 输出image
|
// 输出image
|
||||||
// 权限判断
|
// 权限判断
|
||||||
func (c File) OutputImage(noteId, fileId string) revel.Result {
|
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
|
||||||
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
|
sessionId := c.Session.Id()
|
||||||
|
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return c.RenderText("")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
@@ -234,16 +227,12 @@ func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
|
|||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制外网的图片
|
// 复制外网的图片, 成公共图片 放在/upload下
|
||||||
// 都要好好的计算大小
|
// 都要好好的计算大小
|
||||||
func (c File) CopyHttpImage(src string) revel.Result {
|
func (c File) CopyHttpImage(src string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
|
fileUrlPath := "upload/" + c.GetUserId() + "/images"
|
||||||
// 生成上传路径
|
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||||
newGuid := NewGuid()
|
|
||||||
userId := c.GetUserId()
|
|
||||||
fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
err := os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
@@ -261,11 +250,11 @@ func (c File) CopyHttpImage(src string) revel.Result {
|
|||||||
Path: fileUrlPath + "/" + filename,
|
Path: fileUrlPath + "/" + filename,
|
||||||
Size: filesize}
|
Size: filesize}
|
||||||
|
|
||||||
id := bson.NewObjectId()
|
id := bson.NewObjectId();
|
||||||
fileInfo.FileId = id
|
fileInfo.FileId = id
|
||||||
|
|
||||||
re.Id = id.Hex()
|
re.Id = id.Hex()
|
||||||
// re.Item = fileInfo.Path
|
re.Item = fileInfo.Path
|
||||||
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
|
|||||||
@@ -21,12 +21,13 @@ func (c Index) Default() revel.Result {
|
|||||||
}
|
}
|
||||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||||
func (c Index) Index() revel.Result {
|
func (c Index) Index() revel.Result {
|
||||||
|
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.RenderArgs["title"] = "leanote"
|
c.RenderArgs["title"] = "leanote"
|
||||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||||
c.SetLocale()
|
lang := c.SetLocale()
|
||||||
|
|
||||||
return c.RenderTemplate("home/index.html");
|
return c.RenderTemplate("home/index_" + lang + ".html");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 建议
|
// 建议
|
||||||
|
|||||||
+117
-193
@@ -3,17 +3,14 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"os"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
// "time"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"fmt"
|
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
// "bytes"
|
// "bytes"
|
||||||
// "os"
|
// "os"
|
||||||
)
|
)
|
||||||
@@ -25,9 +22,9 @@ type Note struct {
|
|||||||
// 笔记首页, 判断是否已登录
|
// 笔记首页, 判断是否已登录
|
||||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||||
// 否则, 转向登录页面
|
// 否则, 转向登录页面
|
||||||
func (c Note) Index(noteId, online string) revel.Result {
|
func (c Note) Index(noteId string) revel.Result {
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
userInfo := c.GetUserAndBlogUrl()
|
userInfo := c.GetUserInfo()
|
||||||
|
|
||||||
userId := userInfo.UserId.Hex()
|
userId := userInfo.UserId.Hex()
|
||||||
|
|
||||||
@@ -52,11 +49,10 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
hasRightNoteId := false
|
hasRightNoteId := false
|
||||||
if IsObjectId(noteId) {
|
if IsObjectId(noteId) {
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
|
|
||||||
if note.NoteId != "" {
|
|
||||||
var noteOwner = note.UserId.Hex()
|
var noteOwner = note.UserId.Hex()
|
||||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||||
|
|
||||||
|
if note.NoteId != "" {
|
||||||
hasRightNoteId = true
|
hasRightNoteId = true
|
||||||
c.RenderArgs["curNoteId"] = noteId
|
c.RenderArgs["curNoteId"] = noteId
|
||||||
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
||||||
@@ -128,9 +124,10 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
|
|
||||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
|
|
||||||
|
|
||||||
// return c.RenderTemplate("note/note.html")
|
// return c.RenderTemplate("note/note.html")
|
||||||
|
|
||||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev && online == "" {
|
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||||
return c.RenderTemplate("note/note-dev.html")
|
return c.RenderTemplate("note/note-dev.html")
|
||||||
} else {
|
} else {
|
||||||
return c.RenderTemplate("note/note.html")
|
return c.RenderTemplate("note/note.html")
|
||||||
@@ -141,13 +138,13 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||||
// 否则, 转向登录页面
|
// 否则, 转向登录页面
|
||||||
func (c Note) ListNotes(notebookId string) revel.Result {
|
func (c Note) ListNotes(notebookId string) revel.Result {
|
||||||
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||||
return c.RenderJson(notes)
|
return c.RenderJson(notes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到trash
|
// 得到trash
|
||||||
func (c Note) ListTrashNotes() revel.Result {
|
func (c Note) ListTrashNotes() revel.Result {
|
||||||
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||||
return c.RenderJson(notes)
|
return c.RenderJson(notes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +169,7 @@ type NoteOrContent struct {
|
|||||||
Title string
|
Title string
|
||||||
Desc string
|
Desc string
|
||||||
ImgSrc string
|
ImgSrc string
|
||||||
Tags string
|
Tags []string
|
||||||
Content string
|
Content string
|
||||||
Abstract string
|
Abstract string
|
||||||
IsNew bool
|
IsNew bool
|
||||||
@@ -195,7 +192,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||||
Title: noteOrContent.Title,
|
Title: noteOrContent.Title,
|
||||||
Tags: strings.Split(noteOrContent.Tags, ","),
|
Tags: noteOrContent.Tags,
|
||||||
Desc: noteOrContent.Desc,
|
Desc: noteOrContent.Desc,
|
||||||
ImgSrc: noteOrContent.ImgSrc,
|
ImgSrc: noteOrContent.ImgSrc,
|
||||||
IsBlog: noteOrContent.IsBlog,
|
IsBlog: noteOrContent.IsBlog,
|
||||||
@@ -228,90 +225,50 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
noteUpdate["Title"] = noteOrContent.Title;
|
noteUpdate["Title"] = noteOrContent.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Has("Tags") {
|
if c.Has("Tags[]") {
|
||||||
needUpdateNote = true
|
needUpdateNote = true
|
||||||
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",");
|
noteUpdate["Tags"] = noteOrContent.Tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// web端不控制
|
|
||||||
if needUpdateNote {
|
if needUpdateNote {
|
||||||
noteService.UpdateNote(c.GetUserId(),
|
noteService.UpdateNote(noteOrContent.UserId, c.GetUserId(),
|
||||||
noteOrContent.NoteId, noteUpdate, -1)
|
noteOrContent.NoteId, noteUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------
|
//-------------
|
||||||
afterContentUsn := 0
|
|
||||||
contentOk := false
|
|
||||||
contentMsg := ""
|
|
||||||
if c.Has("Content") {
|
|
||||||
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
|
||||||
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
|
||||||
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.GetUserId(),
|
|
||||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(afterContentUsn)
|
if c.Has("Content") {
|
||||||
Log(contentOk)
|
noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
||||||
Log(contentMsg)
|
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
||||||
|
}
|
||||||
|
|
||||||
return c.RenderJson(true)
|
return c.RenderJson(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除note/ 删除别人共享给我的笔记
|
// 删除note/ 删除别人共享给我的笔记
|
||||||
// userId 是note.UserId
|
// userId 是note.UserId
|
||||||
func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result {
|
func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
|
||||||
if !isShared {
|
if(!isShared) {
|
||||||
for _, noteId := range noteIds {
|
return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
|
||||||
trashService.DeleteNote(noteId, c.GetUserId())
|
|
||||||
}
|
|
||||||
return c.RenderJson(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, noteId := range noteIds {
|
return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
|
||||||
trashService.DeleteSharedNote(noteId, c.GetUserId())
|
|
||||||
}
|
}
|
||||||
|
// 删除trash
|
||||||
return c.RenderJson(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除trash, 已弃用, 用DeleteNote
|
|
||||||
func (c Note) DeleteTrash(noteId string) revel.Result {
|
func (c Note) DeleteTrash(noteId string) revel.Result {
|
||||||
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()))
|
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动note
|
// 移动note
|
||||||
func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result {
|
func (c Note) MoveNote(noteId, notebookId string) revel.Result {
|
||||||
userId := c.GetUserId()
|
return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
|
||||||
for _, noteId := range noteIds {
|
|
||||||
noteService.MoveNote(noteId, notebookId, userId)
|
|
||||||
}
|
}
|
||||||
return c.RenderJson(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制note
|
// 复制note
|
||||||
func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result {
|
func (c Note) CopyNote(noteId, notebookId string) revel.Result {
|
||||||
copyNotes := make([]info.Note, len(noteIds))
|
return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
|
||||||
userId := c.GetUserId()
|
|
||||||
for i, noteId := range noteIds {
|
|
||||||
copyNotes[i] = noteService.CopyNote(noteId, notebookId, userId)
|
|
||||||
}
|
}
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = copyNotes
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制别人共享的笔记给我
|
// 复制别人共享的笔记给我
|
||||||
func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) revel.Result {
|
func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result {
|
||||||
copyNotes := make([]info.Note, len(noteIds))
|
return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
|
||||||
userId := c.GetUserId()
|
|
||||||
for i, noteId := range noteIds {
|
|
||||||
copyNotes[i] = noteService.CopySharedNote(noteId, notebookId, fromUserId, userId)
|
|
||||||
}
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = copyNotes
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
@@ -321,103 +278,50 @@ func (c Note) SearchNote(key string) revel.Result {
|
|||||||
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
||||||
return c.RenderJson(blogs)
|
return c.RenderJson(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过tags搜索
|
// 通过tags搜索
|
||||||
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
||||||
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
||||||
return c.RenderJson(blogs)
|
return c.RenderJson(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成PDF
|
//------------------
|
||||||
func (c Note) ToPdf(noteId, appKey string) revel.Result {
|
// html2image
|
||||||
|
// 判断是否有权限生成
|
||||||
|
// 博客也可以调用
|
||||||
|
// 这是脚本调用, 没有cookie, 不执行权限控制, 通过传来的appKey判断
|
||||||
|
func (c Note) ToImage(noteId, appKey string) revel.Result {
|
||||||
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
|
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
|
||||||
appKeyTrue, _ := revel.Config.String("app.secret")
|
appKeyTrue, _ := revel.Config.String("app.secret")
|
||||||
if appKeyTrue != appKey {
|
if appKeyTrue != appKey {
|
||||||
return c.RenderText("error")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
return c.RenderText("error")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
noteUserId := note.UserId.Hex()
|
noteUserId := note.UserId.Hex()
|
||||||
content := noteService.GetNoteContent(noteId, noteUserId)
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
userInfo := userService.GetUserInfo(noteUserId)
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
//------------------
|
|
||||||
// 将content的图片转换为base64
|
|
||||||
contentStr := content.Content
|
|
||||||
|
|
||||||
siteUrlPattern := configService.GetSiteUrl()
|
|
||||||
if strings.Contains(siteUrlPattern, "https") {
|
|
||||||
siteUrlPattern = strings.Replace(siteUrlPattern, "https", "https*", 1)
|
|
||||||
} else {
|
|
||||||
siteUrlPattern = strings.Replace(siteUrlPattern, "http", "https*", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
regImage, _ := regexp.Compile(`<img .*?(src=('|")` + siteUrlPattern + `/(file/outputImage|api/file/getImage)\?fileId=([a-z0-9A-Z]{24})("|'))`)
|
|
||||||
|
|
||||||
findsImage := regImage.FindAllStringSubmatch(contentStr, -1) // 查找所有的
|
|
||||||
// [<img src="http://leanote.com/api/getImage?fileId=3354672e8d38f411286b000069" alt="" width="692" height="302" data-mce-src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " file/outputImage 54672e8d38f411286b000069 "]
|
|
||||||
for _, eachFind := range findsImage {
|
|
||||||
if len(eachFind) == 6 {
|
|
||||||
fileId := eachFind[4]
|
|
||||||
// 得到base64编码文件
|
|
||||||
fileBase64 := fileService.GetImageBase64(noteUserId, fileId)
|
|
||||||
if fileBase64 == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1
|
|
||||||
// src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069"
|
|
||||||
allFixed := strings.Replace(eachFind[0], eachFind[1], "src=\""+fileBase64+"\"", -1)
|
|
||||||
contentStr = strings.Replace(contentStr, eachFind[0], allFixed, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// markdown
|
|
||||||
if note.IsMarkdown {
|
|
||||||
// 
|
|
||||||
regImageMarkdown, _ := regexp.Compile(`!\[.*?\]\(` + siteUrlPattern + `/(file/outputImage|api/file/getImage)\?fileId=([a-z0-9A-Z]{24})\)`)
|
|
||||||
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(contentStr, -1) // 查找所有的
|
|
||||||
for _, eachFind := range findsImageMarkdown {
|
|
||||||
if len(eachFind) == 3 {
|
|
||||||
fileId := eachFind[2]
|
|
||||||
// 得到base64编码文件
|
|
||||||
fileBase64 := fileService.GetImageBase64(noteUserId, fileId)
|
|
||||||
if fileBase64 == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1
|
|
||||||
// src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069"
|
|
||||||
allFixed := ""
|
|
||||||
contentStr = strings.Replace(contentStr, eachFind[0], allFixed, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if note.Tags != nil && len(note.Tags) > 0 && note.Tags[0] != "" {
|
|
||||||
} else {
|
|
||||||
note.Tags = nil
|
|
||||||
}
|
|
||||||
c.RenderArgs["blog"] = note
|
c.RenderArgs["blog"] = note
|
||||||
c.RenderArgs["content"] = contentStr
|
c.RenderArgs["content"] = content.Content
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
userBlog := blogService.GetUserBlog(noteUserId)
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
c.RenderArgs["userBlog"] = userBlog
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
return c.RenderTemplate("file/pdf.html")
|
return c.RenderTemplate("html2Image/index.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出成PDF
|
func (c Note) Html2Image(noteId string) revel.Result {
|
||||||
func (c Note) ExportPdf(noteId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
re.Msg = "No Note"
|
re.Msg = "No Note"
|
||||||
return c.RenderText("error")
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
noteUserId := note.UserId.Hex()
|
noteUserId := note.UserId.Hex()
|
||||||
@@ -426,71 +330,91 @@ func (c Note) ExportPdf(noteId string) revel.Result {
|
|||||||
// 是否是有权限协作的
|
// 是否是有权限协作的
|
||||||
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
||||||
re.Msg = "No Perm"
|
re.Msg = "No Perm"
|
||||||
return c.RenderText("error")
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path 判断是否需要重新生成之
|
// path 判断是否需要重新生成之
|
||||||
guid := NewGuid()
|
fileUrlPath := "/upload/" + noteUserId + "/images/weibo"
|
||||||
fileUrlPath := "files/" + Digest3(noteUserId) + "/" + noteUserId + "/" + Digest2(guid) + "/images/pdf"
|
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
if !ClearDir(dir) {
|
||||||
if !MkdirAll(dir) {
|
re.Msg = "No Dir"
|
||||||
return c.RenderText("error, no dir")
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
filename := guid + ".pdf"
|
|
||||||
|
filename := note.NoteId.Hex() + ".png";
|
||||||
path := dir + "/" + filename
|
path := dir + "/" + filename
|
||||||
|
|
||||||
// leanote.com的secret
|
// cookie
|
||||||
appKey, _ := revel.Config.String("app.secretLeanote")
|
cookieName := revel.CookiePrefix + "_SESSION"
|
||||||
if appKey == "" {
|
cookie, err := c.Request.Cookie(cookieName)
|
||||||
appKey, _ = revel.Config.String("app.secret")
|
cookieStr := cookie.String()
|
||||||
|
cookieValue := ""
|
||||||
|
if err == nil && len(cookieStr) > len(cookieName) {
|
||||||
|
cookieValue = cookieStr[len(cookieName)+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appKey, _ := revel.Config.String("app.secret")
|
||||||
|
cookieDomain, _ := revel.Config.String("cookie.domain")
|
||||||
// 生成之
|
// 生成之
|
||||||
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
|
url := configService.GetSiteUrl() + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
||||||
// 默认路径
|
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
|
||||||
|
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
if binPath == "" {
|
if binPath == "" {
|
||||||
binPath = "/usr/local/bin/wkhtmltopdf"
|
return c.RenderJson(re);
|
||||||
}
|
}
|
||||||
|
cc := binPath + " \"" + url + "\" \"" + path + "\" \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
|
|
||||||
// cc := binPath + " --no-stop-slow-scripts --javascript-delay 10000 \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
// cc := binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
// 等待--window-status为done的状态
|
|
||||||
// http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html
|
|
||||||
// wkhtmltopdf参数大全
|
|
||||||
var cc string
|
|
||||||
if note.IsMarkdown {
|
|
||||||
cc = binPath + " --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
} else {
|
|
||||||
cc = binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", cc)
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
_, err := cmd.Output()
|
Log(cc);
|
||||||
if err != nil {
|
b, err := cmd.Output()
|
||||||
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
|
if err == nil {
|
||||||
}
|
re.Ok = true
|
||||||
file, err := os.Open(path)
|
re.Id = fileUrlPath + "/" + filename
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
|
|
||||||
}
|
|
||||||
// http://stackoverflow.com/questions/8588818/chrome-pdf-display-duplicate-headers-received-from-the-server
|
|
||||||
// filenameReturn = strings.Replace(filenameReturn, ",", "-", -1)
|
|
||||||
filenameReturn := note.Title
|
|
||||||
filenameReturn = FixFilename(filenameReturn)
|
|
||||||
if filenameReturn == "" {
|
|
||||||
filenameReturn = "Untitled.pdf"
|
|
||||||
} else {
|
} else {
|
||||||
filenameReturn += ".pdf"
|
re.Msg = string(b)
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
}
|
}
|
||||||
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 这里速度慢, 生成不完全(图片和内容都不全)
|
||||||
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
c.RenderArgs["blog"] = note
|
||||||
|
c.RenderArgs["content"] = content.Content
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
html := c.RenderTemplateStr("html2Image/index.html") // Result类型的
|
||||||
|
contentFile := dir + "/html";
|
||||||
|
fout, err := os.Create(contentFile)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
fout.WriteString(html);
|
||||||
|
fout.Close()
|
||||||
|
|
||||||
|
cc := "/Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/c.js \"" + contentFile + "\" \"" + path + "\""
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
re.Ok = true
|
||||||
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置/取消Blog; 置顶
|
// 设置/取消Blog; 置顶
|
||||||
func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
|
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||||
for _, noteId := range noteIds {
|
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||||
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
return c.RenderJson(re)
|
||||||
}
|
|
||||||
return c.RenderJson(true)
|
|
||||||
}
|
}
|
||||||
@@ -37,8 +37,7 @@ func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.
|
|||||||
if(parentNotebookId != "") {
|
if(parentNotebookId != "") {
|
||||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
||||||
}
|
}
|
||||||
|
re := notebookService.AddNotebook(notebook)
|
||||||
re, notebook := notebookService.AddNotebook(notebook)
|
|
||||||
|
|
||||||
if(re) {
|
if(re) {
|
||||||
return c.RenderJson(notebook)
|
return c.RenderJson(notebook)
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.google.com/p/goauth2/oauth"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/lea/netutil"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Oauth struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
var oauthCfg = &oauth.Config{
|
||||||
|
ClientId: "3790fbf1fc14bc6c5d85",
|
||||||
|
ClientSecret: "e9dadfe601c7caa6df9b33db3e7539945c60dfa2",
|
||||||
|
AuthURL: "https://github.com/login/oauth/authorize",
|
||||||
|
TokenURL: "https://github.com/login/oauth/access_token",
|
||||||
|
RedirectURL: "http://leanote.com/oauth/githubCallback",
|
||||||
|
Scope: "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户允许后, github返回到leanote
|
||||||
|
// 通过code得到token
|
||||||
|
// https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Foauth2callback&response_type=code&scope=user&state=
|
||||||
|
func (c Oauth) GithubCallback(code string) revel.Result {
|
||||||
|
t := &oauth.Transport{Config: oauthCfg}
|
||||||
|
|
||||||
|
// Exchange the received code for a token
|
||||||
|
tok, err := t.Exchange(code)
|
||||||
|
token := tok.AccessToken
|
||||||
|
if err != nil || token == "" {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户信息
|
||||||
|
profileInfoURL := "https://api.github.com/user"
|
||||||
|
url := fmt.Sprintf("%s?access_token=%s", profileInfoURL, token)
|
||||||
|
content, err2 := netutil.GetContent(url)
|
||||||
|
if err2 != nil {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
// 转成map
|
||||||
|
profileInfo := map[string]interface{}{}
|
||||||
|
Log(string(content))
|
||||||
|
err2 = json.Unmarshal(content, &profileInfo)
|
||||||
|
if err2 != nil {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameI := profileInfo["login"]
|
||||||
|
|
||||||
|
username, _ := usernameI.(string)
|
||||||
|
userId := username
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
isExists, userInfo := authService.ThirdRegister("github", userId, username)
|
||||||
|
c.RenderArgs["isExists"] = isExists
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
|
// 登录之
|
||||||
|
c.SetSession(userInfo)
|
||||||
|
|
||||||
|
return c.Redirect("/note")
|
||||||
|
}
|
||||||
@@ -9,12 +9,15 @@ import (
|
|||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Share struct {
|
type Share struct {
|
||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AttachToken = 2
|
||||||
|
|
||||||
// 添加共享note
|
// 添加共享note
|
||||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -36,6 +39,8 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
|||||||
return c.RenderJson(status)
|
return c.RenderJson(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 添加共享notebook
|
// 添加共享notebook
|
||||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -186,3 +191,63 @@ func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result
|
|||||||
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||||
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//生成笔记分享密码及更新到db
|
||||||
|
func (c Share) GenShareLinkPass(noteId string) revel.Result {
|
||||||
|
pass, ok := shareService.GenSharePass(noteId)
|
||||||
|
re := info.Re{Ok : true, Item : pass, List: ok}
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Share) QuerySharePass(noteId string) revel.Result {
|
||||||
|
pass := shareService.QuerySharePass(noteId)
|
||||||
|
re := info.Re{Ok : true, Item : pass}
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
//展示分享笔记
|
||||||
|
func (c Share) ShowShareNote(noteId string) revel.Result {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
//
|
||||||
|
c.RenderArgs["noteId"] = noteId
|
||||||
|
username := userService.GetUsernameById(note.UserId)
|
||||||
|
|
||||||
|
c.RenderArgs["userName"] = username
|
||||||
|
c.RenderArgs["isMarkDown"] = note.IsMarkdown
|
||||||
|
// c.RenderArgs["timestamp"] = time.Now().Unix()
|
||||||
|
c.SetLocale()
|
||||||
|
return c.RenderTemplate("share/show_share_note.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证分享密码
|
||||||
|
func (c Share) Verify4ShareNote(noteId string, sharePass int) revel.Result {
|
||||||
|
ok, note, noteContent := shareService.Verify4ShareNote(noteId, sharePass)
|
||||||
|
|
||||||
|
attaches := []info.Attach{}
|
||||||
|
if ok && note.AttachNum > 0 {
|
||||||
|
attaches = attachService.ListAttachs(noteId, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
token := tokenService.NewToken(noteId, noteId, AttachToken)
|
||||||
|
|
||||||
|
//插入笔记作为链接中的附件
|
||||||
|
noteAttachIds := map[string]bool{}
|
||||||
|
noteContent.Content, noteAttachIds = shareService.AppendToken4URL(token, noteContent.Content)
|
||||||
|
//过滤掉插入笔记的附件
|
||||||
|
filteredAttaches := []info.Attach{}
|
||||||
|
if len(noteAttachIds) > 0 && len(attaches) > 0 {
|
||||||
|
for _, attach := range attaches {
|
||||||
|
if !noteAttachIds[attach.AttachId.Hex()] {
|
||||||
|
filteredAttaches = append(filteredAttaches, attach)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filteredAttaches = attaches
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
sessionService.SetToken(sessionId, token)
|
||||||
|
re := info.Re{Ok : ok, Item: note, List: filteredAttaches, Id: token, Msg: noteContent.Content}
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
// "os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Tag struct {
|
|
||||||
BaseController
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新Tag
|
|
||||||
func (c Tag) UpdateTag(tag string) revel.Result {
|
|
||||||
ret := info.NewRe()
|
|
||||||
ret.Ok = true
|
|
||||||
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
func (c Tag) DeleteTag(tag string) revel.Result {
|
|
||||||
ret := info.Re{}
|
|
||||||
ret.Ok = true
|
|
||||||
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
@@ -29,8 +29,8 @@ func (c User) Account(tab int) revel.Result {
|
|||||||
|
|
||||||
// 修改用户名, 需要重置session
|
// 修改用户名, 需要重置session
|
||||||
func (c User) UpdateUsername(username string) revel.Result {
|
func (c User) UpdateUsername(username string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe();
|
||||||
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
|
if(c.GetUsername() == "demo") {
|
||||||
re.Msg = "cannotUpdateDemo"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderRe(re);
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,8 @@ func (c User) UpdateUsername(username string) revel.Result {
|
|||||||
|
|
||||||
// 修改密码
|
// 修改密码
|
||||||
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe();
|
||||||
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
|
if(c.GetUsername() == "demo") {
|
||||||
re.Msg = "cannotUpdateDemo"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderRe(re);
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
@@ -94,9 +94,9 @@ func (c User) ReSendActiveEmail() revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改Email发送激活邮箱
|
// 修改Email发送激活邮箱
|
||||||
func (c User) updateEmailSendActiveEmail(email, pwd string) revel.Result {
|
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
|
if(c.GetUsername() == "demo") {
|
||||||
re.Msg = "cannotUpdateDemo"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderJson(re);
|
return c.RenderJson(re);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,7 @@ func (c AdminEmail) Demo() revel.Result {
|
|||||||
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
|
|
||||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
userInfo := authService.Login(demoUsername, demoPassword)
|
||||||
if err != nil {
|
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
|
||||||
}
|
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
re.Msg = "The User is Not Exists";
|
re.Msg = "The User is Not Exists";
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
|
|||||||
@@ -56,11 +56,7 @@ func (c AdminSetting) Demo() revel.Result {
|
|||||||
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
|
|
||||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
userInfo := authService.Login(demoUsername, demoPassword)
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
|
||||||
}
|
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
re.Msg = "The User is Not Exists";
|
re.Msg = "The User is Not Exists";
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
@@ -73,9 +69,15 @@ func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
|||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) ExportPdf(path string) revel.Result {
|
// ToImage
|
||||||
|
// 长微博的bin路径phantomJs
|
||||||
|
func (c AdminSetting) ToImage() revel.Result {
|
||||||
|
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
|
return c.RenderTemplate("admin/setting/toImage.html");
|
||||||
|
}
|
||||||
|
func (c AdminSetting) DoToImage(toImageBinPath string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,3 @@ func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
|||||||
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,465 +0,0 @@
|
|||||||
# API 列表
|
|
||||||
|
|
||||||
## 前言
|
|
||||||
|
|
||||||
### api url
|
|
||||||
|
|
||||||
所有api的url前面带/api/, 如:
|
|
||||||
|
|
||||||
`/api/user/info?userId=xxxx&token=xxxx`
|
|
||||||
|
|
||||||
除了/auth/login, /auth/register外其它的都需要另外带参数token=xxxx
|
|
||||||
|
|
||||||
### 文件目录结构
|
|
||||||
* 所有API的Controller都在app/api文件夹下
|
|
||||||
* 文件命名: Api功能Controller.go, 如ApiUserController.go
|
|
||||||
* 结构体命名为 Api功能, 如ApiUser
|
|
||||||
* API公用Controller: ApiBaseController
|
|
||||||
* init.go 注入service和定义拦截器
|
|
||||||
|
|
||||||
### 流程
|
|
||||||
用户登录后返回一个token, 以后所有的请求都携带该token.
|
|
||||||
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
|
|
||||||
|
|
||||||
## 返回值结构
|
|
||||||
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
|
|
||||||
* 错误信息全部返回 {Ok: false, Msg: "相应的错误信息"}
|
|
||||||
* 正确信息返回分两种:
|
|
||||||
1. 一些操作型的api, 比如updateUsername, updateLogo之类的, 成功后返回 {Ok: true, Msg:""}
|
|
||||||
2. 一些获取型api, 如getNote, 全部返回真实的返回数据, 如返回笔记:
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"NoteId": "54bdc7e305fcd13ea3000000",
|
|
||||||
"NotebookId": "54bdc65599c37b0da9000003",
|
|
||||||
"UserId": "54bdc65599c37b0da9000002",
|
|
||||||
"Title": "笔记标题",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": true,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Usn": 15,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"PublicTime": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
## Auth 登录与注册
|
|
||||||
|
|
||||||
### /auth/login 登录
|
|
||||||
|
|
||||||
```
|
|
||||||
参数: email, pwd
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {"Ok":false, "Msg":"用户名或密码有误"}
|
|
||||||
正确: 比如:
|
|
||||||
{
|
|
||||||
"Ok":true,
|
|
||||||
"Token":"5500830738f41138e90003232",
|
|
||||||
"UserId":"52d26b4e99c37b609a000001",
|
|
||||||
"Email":"leanote@leanote.com",
|
|
||||||
"Username":"leanote"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
登录成功后将使用token作为之后的请求
|
|
||||||
|
|
||||||
### /auth/logout 注销
|
|
||||||
```
|
|
||||||
参数: token
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /auth/register 注册
|
|
||||||
```
|
|
||||||
参数: email, pwd
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
## User 用户
|
|
||||||
### /user/info 获取用户信息
|
|
||||||
```
|
|
||||||
参数: userId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.User
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updateUsername 修改用户名
|
|
||||||
```
|
|
||||||
参数: username(新用户名)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updatePwd 修改密码
|
|
||||||
```
|
|
||||||
参数: oldPwd(旧密码), pwd(新密码)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updateLogo 修改头像
|
|
||||||
```
|
|
||||||
参数: file(文件)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/getSyncState 获取最新同步状态
|
|
||||||
```
|
|
||||||
参数: 无
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {LastSyncUsn: 3232, LastSyncTime: "上次同步时间"(暂时无用)}
|
|
||||||
```
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## Notebook 笔记本
|
|
||||||
|
|
||||||
### /notebook/getSyncNotebooks 得到需要同步的笔记本
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的笔记本是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Notebook] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/getNotebooks 得到所有笔记本
|
|
||||||
```
|
|
||||||
无参数
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Notebook] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/addNotebook 添加笔记本
|
|
||||||
```
|
|
||||||
参数: title(string), parentNotebookId(string, 父notebookId, 可空), seq(int) 排列
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg:""}
|
|
||||||
成功: type.Notebook
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/updateNotebook 修改笔记本
|
|
||||||
```
|
|
||||||
参数: notebookId, title, parentNotebookId, seq(int), usn(int)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
|
|
||||||
成功: type.Notebook
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/deleteNotebook 删除笔记本
|
|
||||||
```
|
|
||||||
参数: notebookId, usn(int)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
|
|
||||||
成功: {Ok: true}
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Note 笔记
|
|
||||||
|
|
||||||
|
|
||||||
### /note/getSyncNotes 获取需要同步的笔记
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的笔记是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Note] 数组, 笔记不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### /note/getNotes 获得某笔记本下的笔记(无内容)
|
|
||||||
```
|
|
||||||
参数: notebookId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Note] 数组, 笔记不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/getNoteAndContent 获得笔记与内容
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Note
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/getNoteContent 获得笔记内容
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.NoteContent
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/addNote 添加笔记
|
|
||||||
```
|
|
||||||
参数: (注意首字大写)
|
|
||||||
NotebookId string 必传
|
|
||||||
Title string 必传
|
|
||||||
Tags []string 可选
|
|
||||||
Content string 必传
|
|
||||||
Abstract string 可选, 当是markdown笔记时必须传
|
|
||||||
IsMarkdown bool 可选
|
|
||||||
Files []type.NoteFiles 数组 可选
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Note, 不包含Abstract, Content
|
|
||||||
```
|
|
||||||
|
|
||||||
** 关于笔记中的图片/附件**
|
|
||||||
客户端应该添加一个"图片/附件表"来存元数据, 图片应该要缓存到本地, 附件可在需要的时候再调用相应api获取.
|
|
||||||
|
|
||||||
Content中的数据, 图片,附件在Leanote的链接是, 所以, 不管你在本地的笔记中是以什么形式来保存图片,附件的链接的,请addNote和updateNote时务必将链接修改成leanote服务器上的链接.
|
|
||||||
http://leanote.com/api/file/getImage?fileId=xx
|
|
||||||
单个附件:
|
|
||||||
http://leanote.com/api/file/getAttach?fileId=xx
|
|
||||||
所有附件:
|
|
||||||
http://leanote.com/api/file/getAllAttachs?noteId=xxx
|
|
||||||
|
|
||||||
**注意:**
|
|
||||||
addNote时必须要把Files, 和相关的图片/附件一起传到服务器中
|
|
||||||
其中Files(文件的元数据)和其它字段以POST方式传出, 而真正数据则以http的multipart传入, 每个文件的name为"FileDatas[LocalFileId]"
|
|
||||||
|
|
||||||
图片在笔记内的链接必须为: http://leanote.com/api/file/getImage?fileId=LocalFileId或FileId
|
|
||||||
附件如果插入到了笔记内容内, 其链接必须为: http://leanote.com/api/file/getAttach?fileId=LocalFileId或FileId
|
|
||||||
其中, fileId为文件在本地的LocalFileId或服务器上的FileId
|
|
||||||
|
|
||||||
服务器端会生成FileId传给Client. Client在本地必须要建立LocalFileId与FileId的关联.
|
|
||||||
|
|
||||||
如果笔记内容传了, 且笔记内有图片, 则必须要传Files 文件元数据, 因为Server端还要对内容内的图片, 附件链接进行修改, 可能你传过去的是LocalFileId, 服务器端会将LocalFileId替换成FileId存到数据库中.
|
|
||||||
|
|
||||||
同样适用于 updateNote
|
|
||||||
|
|
||||||
http://leanote.com 不绝对, 因为用户可以自建服务, 所以在开发时需要可配置
|
|
||||||
|
|
||||||
### /note/updateNote 更新笔记
|
|
||||||
|
|
||||||
当更新了笔记某个属性时, 只要传某个属性就行, 其它不用传, 比如把笔记拉入了trash, 那么就传IsTrash: true
|
|
||||||
|
|
||||||
```
|
|
||||||
参数: (注意首字大写)
|
|
||||||
NoteId string 必传
|
|
||||||
Usn int 必传
|
|
||||||
NotebookId string 可选
|
|
||||||
Title string 可选
|
|
||||||
Tags []string 可选
|
|
||||||
Content string 可选
|
|
||||||
Abstract string 可选, 当是markdown笔记时必须传
|
|
||||||
IsMarkdown bool 可选
|
|
||||||
IsTrash bool 是否是trash 可选
|
|
||||||
Files []type.NoteFiles 数组 可选
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
|
|
||||||
成功: type.Note, 不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/deleteTrash 彻底删除笔记
|
|
||||||
```
|
|
||||||
参数: noteId, usn
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
|
|
||||||
成功: type.UpdateRet
|
|
||||||
```
|
|
||||||
|
|
||||||
-------
|
|
||||||
|
|
||||||
## Tag 标签
|
|
||||||
|
|
||||||
### /tag/getSyncTags 获取需要同步的标签
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的标签是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Tag] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /tag/addTag 添加标签
|
|
||||||
```
|
|
||||||
参数: tag(string)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Tag
|
|
||||||
```
|
|
||||||
|
|
||||||
### /tag/deleteTag 删除标签
|
|
||||||
```
|
|
||||||
参数: tag(string)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.UpdateRet
|
|
||||||
```
|
|
||||||
|
|
||||||
### File 文件(获取图片, 附件)
|
|
||||||
|
|
||||||
### /file/getImage 获取图片
|
|
||||||
```
|
|
||||||
参数: fileId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
### /file/getAttach 获取附件
|
|
||||||
```
|
|
||||||
参数: fileId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
### /file/getAllAttachs 获取所有附件
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
--------
|
|
||||||
|
|
||||||
## 数据类型
|
|
||||||
|
|
||||||
### type.User 用户信息
|
|
||||||
|
|
||||||
```
|
|
||||||
User {
|
|
||||||
UserId string
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Verified bool
|
|
||||||
Logo string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Notebook 笔记本
|
|
||||||
|
|
||||||
```
|
|
||||||
Notebook {
|
|
||||||
NotebookId
|
|
||||||
UserId
|
|
||||||
ParentNotebookId // 上级
|
|
||||||
Seq int // 排序
|
|
||||||
Title string
|
|
||||||
IsBlog bool
|
|
||||||
IsDeleted bool
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int // UpdateSequenceNum
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Note 笔记
|
|
||||||
```
|
|
||||||
Note {
|
|
||||||
NoteId string
|
|
||||||
NotebookId string
|
|
||||||
UserId string
|
|
||||||
Title string
|
|
||||||
Tags []string
|
|
||||||
Content string
|
|
||||||
IsMarkdown bool
|
|
||||||
IsBlog bool
|
|
||||||
IsTrash bool
|
|
||||||
Files []NoteFile // 图片, 附件
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
PublicTime time.Time
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.NoteContent 笔记内容
|
|
||||||
```
|
|
||||||
NoteContent {
|
|
||||||
NoteId string
|
|
||||||
UserId string
|
|
||||||
Content string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.NoteFile 笔记文件(图片,附件)
|
|
||||||
```
|
|
||||||
NoteFile {
|
|
||||||
FileId string // 服务器端Id
|
|
||||||
LocalFileId string // 客户端Id
|
|
||||||
Type string // images/png, doc, xls, 根据fileName确定
|
|
||||||
Title string
|
|
||||||
HasBody bool // 传过来的值是否要更新内容, 如果有true, 则必须传文件
|
|
||||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Tag 标签
|
|
||||||
```
|
|
||||||
Tag {
|
|
||||||
TagId string
|
|
||||||
UserId string
|
|
||||||
Tag string
|
|
||||||
CreatedTime
|
|
||||||
UpdatedTime
|
|
||||||
IsDeleted bool // 删除位
|
|
||||||
// 更新序号
|
|
||||||
Usn
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.UpdateRe 更新后返回的值, 包含Usn
|
|
||||||
```
|
|
||||||
ReUpdate {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# API设计
|
|
||||||
|
|
||||||
By life (life@leanote.com)
|
|
||||||
|
|
||||||
## api url
|
|
||||||
|
|
||||||
所有api的url前面带/api/, 如:
|
|
||||||
|
|
||||||
`/api/user/info?userId=xxxx&token=xxxx`
|
|
||||||
|
|
||||||
## 文件目录结构
|
|
||||||
* 所有API的Controller都在app/api文件夹下
|
|
||||||
* 文件命名: Api功能Controller.go, 如ApiUserController.go
|
|
||||||
* 结构体命名为 Api功能, 如ApiUser
|
|
||||||
* API公用Controller: ApiBaseController
|
|
||||||
* init.go 注入service和定义拦截器
|
|
||||||
|
|
||||||
## 流程
|
|
||||||
用户登录后返回一个token, 以后所有的请求都携带该token.
|
|
||||||
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
|
|
||||||
|
|
||||||
## 返回值结构
|
|
||||||
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
|
|
||||||
* 错误信息全部返回 {Ok: false, Msg: ""}
|
|
||||||
* 正确信息全部返回真实的返回数据, 如返回笔记:
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"NoteId": "54bdc7e305fcd13ea3000000",
|
|
||||||
"NotebookId": "54bdc65599c37b0da9000003",
|
|
||||||
"UserId": "54bdc65599c37b0da9000002",
|
|
||||||
"Title": "asdfads",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": true,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Usn": 15,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"PublicTime": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
// "strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 用户登录后生成一个token, 将这个token保存到session中
|
|
||||||
// 以后每次的请求必须带这个token, 并从session中获取userId
|
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
|
||||||
|
|
||||||
type ApiAuth struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 登录
|
|
||||||
// [ok]
|
|
||||||
// 成功返回 {Ok: true, Item: token }
|
|
||||||
// 失败返回 {Ok: false, Msg: ""}
|
|
||||||
func (c ApiAuth) Login(email, pwd string) revel.Result {
|
|
||||||
var msg = ""
|
|
||||||
|
|
||||||
userInfo, err := authService.Login(email, pwd)
|
|
||||||
if err == nil {
|
|
||||||
token := bson.NewObjectId().Hex()
|
|
||||||
sessionService.SetUserId(token, userInfo.UserId.Hex())
|
|
||||||
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
|
|
||||||
} else {
|
|
||||||
// 登录错误, 则错误次数++
|
|
||||||
msg = "wrongUsernameOrPassword"
|
|
||||||
}
|
|
||||||
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注销
|
|
||||||
// [Ok]
|
|
||||||
func (c ApiAuth) Logout() revel.Result {
|
|
||||||
token := c.getToken()
|
|
||||||
sessionService.Clear(token)
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Ok = true
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册
|
|
||||||
// [Ok]
|
|
||||||
// 成功后并不返回用户ID, 需要用户重新登录
|
|
||||||
func (c ApiAuth) Register(email, pwd string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if !configService.IsOpenRegister() {
|
|
||||||
re.Msg = "notOpenRegister" // 未开放注册
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册
|
|
||||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
// "encoding/json"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/leanote/leanote/app/controllers"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"os"
|
|
||||||
// "fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "math"
|
|
||||||
// "strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 公用Controller, 其它Controller继承它
|
|
||||||
type ApiBaseContrller struct {
|
|
||||||
controllers.BaseController // 不能用*BaseController
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到token, 这个token是在AuthInterceptor设到Session中的
|
|
||||||
func (c ApiBaseContrller) getToken() string {
|
|
||||||
return c.Session["_token"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// userId
|
|
||||||
// _userId是在AuthInterceptor设置的
|
|
||||||
func (c ApiBaseContrller) getUserId() string {
|
|
||||||
return c.Session["_userId"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户信息
|
|
||||||
func (c ApiBaseContrller) getUserInfo() info.User {
|
|
||||||
userId := c.Session["_userId"]
|
|
||||||
if userId == "" {
|
|
||||||
return info.User{}
|
|
||||||
}
|
|
||||||
return userService.GetUserInfo(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传附件
|
|
||||||
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
|
|
||||||
userId := c.getUserId();
|
|
||||||
|
|
||||||
// 判断是否有权限为笔记添加附件
|
|
||||||
// 如果笔记还没有添加是不是会有问题
|
|
||||||
/*
|
|
||||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
file, handel, err := c.Request.FormFile(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// > 5M?
|
|
||||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
|
||||||
if maxFileSize <= 0 {
|
|
||||||
maxFileSize = 1000
|
|
||||||
}
|
|
||||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成上传路径
|
|
||||||
newGuid := NewGuid()
|
|
||||||
filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
|
|
||||||
|
|
||||||
dir := revel.BasePath + "/" + filePath
|
|
||||||
err = os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 生成新的文件名
|
|
||||||
filename := handel.Filename
|
|
||||||
_, ext := SplitFilename(filename) // .doc
|
|
||||||
filename = newGuid + ext
|
|
||||||
toPath := dir + "/" + filename;
|
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add File to db
|
|
||||||
fileType := ""
|
|
||||||
if ext != "" {
|
|
||||||
fileType = strings.ToLower(ext[1:])
|
|
||||||
}
|
|
||||||
filesize := GetFilesize(toPath)
|
|
||||||
fileInfo := info.Attach{AttachId: bson.NewObjectId(),
|
|
||||||
Name: filename,
|
|
||||||
Title: handel.Filename,
|
|
||||||
NoteId: bson.ObjectIdHex(noteId),
|
|
||||||
UploadUserId: bson.ObjectIdHex(userId),
|
|
||||||
Path: filePath + "/" + filename,
|
|
||||||
Type: fileType,
|
|
||||||
Size: filesize}
|
|
||||||
|
|
||||||
ok, msg = attachService.AddAttach(fileInfo, true)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
id = fileInfo.AttachId.Hex()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传图片
|
|
||||||
func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok bool, msg string, id string) {
|
|
||||||
if isAttach {
|
|
||||||
return c.uploadAttach(name, noteId)
|
|
||||||
}
|
|
||||||
file, handel, err := c.Request.FormFile(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
newGuid := NewGuid()
|
|
||||||
// 生成上传路径
|
|
||||||
userId := c.getUserId()
|
|
||||||
fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
|
|
||||||
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
err = os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 生成新的文件名
|
|
||||||
filename := handel.Filename
|
|
||||||
_, ext := SplitFilename(filename)
|
|
||||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
|
||||||
msg = "notImage"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = newGuid + ext
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
maxFileSize := configService.GetUploadSize("uploadImageSize");
|
|
||||||
if maxFileSize <= 0 {
|
|
||||||
maxFileSize = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// > 2M?
|
|
||||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
toPath := dir + "/" + filename;
|
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 改变成gif图片
|
|
||||||
_, toPathGif := TransToGif(toPath, 0, true)
|
|
||||||
filename = GetFilename(toPathGif)
|
|
||||||
filesize := GetFilesize(toPathGif)
|
|
||||||
fileUrlPath += "/" + filename
|
|
||||||
|
|
||||||
// File
|
|
||||||
fileInfo := info.File{FileId: bson.NewObjectId(),
|
|
||||||
Name: filename,
|
|
||||||
Title: handel.Filename,
|
|
||||||
Path: fileUrlPath,
|
|
||||||
Size: filesize}
|
|
||||||
ok, msg = fileService.AddImage(fileInfo, "", c.getUserId(), true)
|
|
||||||
if ok {
|
|
||||||
id = fileInfo.FileId.Hex()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// "github.com/leanote/leanote/app/lea/netutil"
|
|
||||||
// "github.com/leanote/leanote/app/info"
|
|
||||||
// "io/ioutil"
|
|
||||||
"os"
|
|
||||||
// "strconv"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
"strings"
|
|
||||||
"archive/tar"
|
|
||||||
"compress/gzip"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 文件操作, 图片, 头像上传, 输出
|
|
||||||
|
|
||||||
type ApiFile struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// 协作时复制图片到owner
|
|
||||||
func (c ApiFile) CopyImage(userId, fileId, toUserId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
|
|
||||||
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
|
||||||
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all images by userId with page
|
|
||||||
func (c ApiFile) GetImages(albumId, key string, page int) revel.Result {
|
|
||||||
imagesPage := fileService.ListImagesWithPage(c.getUserId(), albumId, key, page, 12)
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = imagesPage
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ApiFile) DeleteImage(fileId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
// 输出image
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetImage(fileId string) revel.Result {
|
|
||||||
path := fileService.GetFile(c.getUserId(), fileId) // 得到路径
|
|
||||||
if path == "" {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
|
||||||
file, _ := os.Open(fn)
|
|
||||||
return c.RenderFile(file, revel.Inline) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载附件
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetAttach(fileId string) revel.Result {
|
|
||||||
attach := attachService.GetAttach(fileId, c.getUserId()); // 得到路径
|
|
||||||
path := attach.Path
|
|
||||||
if path == "" {
|
|
||||||
return c.RenderText("No Such File")
|
|
||||||
}
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
|
||||||
file, _ := os.Open(fn)
|
|
||||||
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载所有附件
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetAllAttachs(noteId string) revel.Result {
|
|
||||||
note := noteService.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
// 得到文件列表
|
|
||||||
attachs := attachService.ListAttachs(noteId, c.getUserId())
|
|
||||||
if attachs == nil || len(attachs) == 0 {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
dir := revel.BasePath + "/files/tmp"
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
filename := note.Title + ".tar.gz"
|
|
||||||
if note.Title == "" {
|
|
||||||
filename = "all.tar.gz"
|
|
||||||
}
|
|
||||||
|
|
||||||
// file write
|
|
||||||
fw, err := os.Create(revel.BasePath + "/files/" + filename)
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
|
|
||||||
|
|
||||||
// gzip write
|
|
||||||
gw := gzip.NewWriter(fw)
|
|
||||||
defer gw.Close()
|
|
||||||
|
|
||||||
// tar write
|
|
||||||
tw := tar.NewWriter(gw)
|
|
||||||
defer tw.Close()
|
|
||||||
|
|
||||||
// 遍历文件列表
|
|
||||||
for _, attach := range attachs {
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
|
|
||||||
fr, err := os.Open(fn)
|
|
||||||
fileInfo, _ := fr.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
defer fr.Close()
|
|
||||||
|
|
||||||
// 信息头
|
|
||||||
h := new(tar.Header)
|
|
||||||
h.Name = attach.Title
|
|
||||||
h.Size = fileInfo.Size()
|
|
||||||
h.Mode = int64(fileInfo.Mode())
|
|
||||||
h.ModTime = fileInfo.ModTime()
|
|
||||||
|
|
||||||
// 写信息头
|
|
||||||
err = tw.WriteHeader(h)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写文件
|
|
||||||
_, err = io.Copy(tw, fr)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
} // for
|
|
||||||
|
|
||||||
// tw.Close()
|
|
||||||
// gw.Close()
|
|
||||||
// fw.Close()
|
|
||||||
// file, _ := os.Open(dir + "/" + filename)
|
|
||||||
// fw.Seek(0, 0)
|
|
||||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,664 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"os/exec"
|
|
||||||
"os"
|
|
||||||
// "github.com/leanote/leanote/app/types"
|
|
||||||
// "io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "bytes"
|
|
||||||
// "os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 笔记API
|
|
||||||
|
|
||||||
type ApiNote struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的笔记
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 无Desc, Abstract, 有Files
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"NoteId": "55195fa199c37b79be000005",
|
|
||||||
"NotebookId": "55195fa199c37b79be000002",
|
|
||||||
"UserId": "55195fa199c37b79be000001",
|
|
||||||
"Title": "Leanote语法Leanote语法Leanote语法Leanote语法Leanote语法",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": true,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": false,
|
|
||||||
"Usn": 5,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-03-30T22:37:21.695+08:00",
|
|
||||||
"UpdatedTime": "2015-03-30T22:37:21.724+08:00",
|
|
||||||
"PublicTime": "2015-03-30T22:37:21.695+08:00"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(notes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到笔记本下的笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNotes(notebookId string) revel.Result {
|
|
||||||
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "notebookIdInvalid"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到trash
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetTrashNotes() revel.Result {
|
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// get Note
|
|
||||||
// [OK]
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"NoteId": "550c0bee2ec82a2eb5000000",
|
|
||||||
"NotebookId": "54a1676399c37b1c77000004",
|
|
||||||
"UserId": "54a1676399c37b1c77000002",
|
|
||||||
"Title": "asdfadsf--=",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": [
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": false,
|
|
||||||
"Usn": 8,
|
|
||||||
"Files": [
|
|
||||||
{
|
|
||||||
"FileId": "551975d599c37b970f000002",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "",
|
|
||||||
"Title": "",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FileId": "551975de99c37b970f000003",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "doc",
|
|
||||||
"Title": "李铁-简历-ali-print-en.doc",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FileId": "551975de99c37b970f000004",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "doc",
|
|
||||||
"Title": "李铁-简历-ali-print.doc",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"CreatedTime": "2015-03-20T20:00:52.463+08:00",
|
|
||||||
"UpdatedTime": "2015-03-31T00:12:44.967+08:00",
|
|
||||||
"PublicTime": "2015-03-20T20:00:52.463+08:00"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiNote) GetNote(noteId string) revel.Result {
|
|
||||||
if !bson.IsObjectIdHex(noteId) {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "noteIdInvalid"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
note := noteService.GetNote(noteId, c.getUserId())
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "notExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
apiNotes := noteService.ToApiNotes([]info.Note{note})
|
|
||||||
return c.RenderJson(apiNotes[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到note和内容
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNoteAndContent(noteId string) revel.Result {
|
|
||||||
noteAndContent := noteService.GetNoteAndContent(noteId, c.getUserId())
|
|
||||||
|
|
||||||
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
|
|
||||||
apiNote := apiNotes[0]
|
|
||||||
apiNote.Content = noteAndContent.Content
|
|
||||||
return c.RenderJson(apiNote)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理笔记内容数据 http://leanote.com/file/outputImage -> https://leanote.com/api/file/getImage
|
|
||||||
// 图片, 附件都替换
|
|
||||||
func (c ApiNote) fixContent(content string) string {
|
|
||||||
// TODO, 这个url需要从config中取
|
|
||||||
// baseUrl := "http://leanote.com"
|
|
||||||
baseUrl := configService.GetSiteUrl()
|
|
||||||
// baseUrl := "http://localhost:9000"
|
|
||||||
|
|
||||||
patterns := []map[string]string{
|
|
||||||
map[string]string{"src": "src", "middle": "/file/outputImage", "param": "fileId", "to": "getImage?fileId="},
|
|
||||||
map[string]string{"src": "href", "middle": "/attach/download", "param": "attachId", "to": "getAttach?fileId="},
|
|
||||||
map[string]string{"src": "href", "middle": "/attach/downloadAll", "param": "noteId", "to": "getAllAttachs?noteId="},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, eachPattern := range patterns {
|
|
||||||
|
|
||||||
// src="http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1"
|
|
||||||
// href="http://leanote.com/attach/download?attachId=5504243a38f4111dcb00017d"
|
|
||||||
// href="http://leanote.com/attach/downloadAll?noteId=55041b6a38f4111dcb000159"
|
|
||||||
|
|
||||||
regImage, _ := regexp.Compile(eachPattern["src"] + `=('|")`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})("|')`)
|
|
||||||
findsImage := regImage.FindAllStringSubmatch(content, -1) // 查找所有的
|
|
||||||
|
|
||||||
// [[src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "]]
|
|
||||||
for _, eachFind := range findsImage {
|
|
||||||
// [src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "]
|
|
||||||
if len(eachFind) == 4 {
|
|
||||||
content = strings.Replace(content,
|
|
||||||
eachFind[0],
|
|
||||||
eachPattern["src"] + "=\"" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + "\"",
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// markdown处理
|
|
||||||
// 
|
|
||||||
// [selection 2.html](http://leanote.com/attach/download?attachId=5504262638f4111dcb00017f)
|
|
||||||
// [all.tar.gz](http://leanote.com/attach/downloadAll?noteId=5503b57d59f81b4eb4000000)
|
|
||||||
|
|
||||||
pre := "!" // 默认图片
|
|
||||||
if eachPattern["src"] == "href" { // 是attach
|
|
||||||
pre = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
regImageMarkdown, _ := regexp.Compile(pre + `\[(.*?)\]\(`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})\)`)
|
|
||||||
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(content, -1) // 查找所有的
|
|
||||||
// [[ 5503537b38f4111dcb0000d1] [ 5503537b38f4111dcb0000d1]]
|
|
||||||
for _, eachFind := range findsImageMarkdown {
|
|
||||||
// [ 你好啊, 我很好, 为什么? 5503537b38f4111dcb0000d1]
|
|
||||||
if len(eachFind) == 3 {
|
|
||||||
content = strings.Replace(content, eachFind[0], pre + "[" + eachFind[1] + "](" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + ")", 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|
||||||
// content里的image, attach链接是
|
|
||||||
// https://leanote.com/api/file/getImage?fileId=xx
|
|
||||||
// https://leanote.com/api/file/getAttach?fileId=xx
|
|
||||||
// 将fileId=映射成ServerFileId, 这里的fileId可能是本地的FileId
|
|
||||||
func (c ApiNote) fixPostNotecontent(noteOrContent *info.ApiNote) {
|
|
||||||
if noteOrContent.Content == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
files := noteOrContent.Files
|
|
||||||
if files != nil && len(files) > 0 {
|
|
||||||
for _, file := range files {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
noteOrContent.Content = strings.Replace(noteOrContent.Content, "fileId=" + file.LocalFileId, "fileId=" + file.FileId, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到内容
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNoteContent(noteId string) revel.Result {
|
|
||||||
// re := info.NewRe()
|
|
||||||
noteContent := noteService.GetNoteContent(noteId, c.getUserId())
|
|
||||||
if noteContent.Content != "" {
|
|
||||||
noteContent.Content = c.fixContent(noteContent.Content)
|
|
||||||
}
|
|
||||||
|
|
||||||
apiNoteContent := info.ApiNoteContent{
|
|
||||||
NoteId: noteContent.NoteId,
|
|
||||||
UserId: noteContent.UserId,
|
|
||||||
Content: noteContent.Content,
|
|
||||||
}
|
|
||||||
|
|
||||||
// re.Item = noteContent
|
|
||||||
return c.RenderJson(apiNoteContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|
||||||
userId := bson.ObjectIdHex(c.getUserId())
|
|
||||||
re := info.NewRe()
|
|
||||||
myUserId := userId
|
|
||||||
// 为共享新建?
|
|
||||||
/*
|
|
||||||
if noteOrContent.FromUserId != "" {
|
|
||||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Log(noteOrContent.Title)
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
/*
|
|
||||||
LogJ(c.Params)
|
|
||||||
for name, _ := range c.Params.Files {
|
|
||||||
Log(name)
|
|
||||||
file, _, _ := c.Request.FormFile(name)
|
|
||||||
LogJ(file)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// return c.RenderJson(re)
|
|
||||||
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
|
||||||
re.Msg = "notebookIdNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteId := bson.NewObjectId()
|
|
||||||
// TODO 先上传图片/附件, 如果不成功, 则返回false
|
|
||||||
//
|
|
||||||
attachNum := 0
|
|
||||||
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
|
|
||||||
for i, file := range noteOrContent.Files {
|
|
||||||
if file.HasBody {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
// FileDatas[54c7ae27d98d0329dd000000]
|
|
||||||
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId.Hex(), file.IsAttach)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
re.Ok = false
|
|
||||||
if msg != "" {
|
|
||||||
Log(msg)
|
|
||||||
Log(file.LocalFileId)
|
|
||||||
re.Msg = "fileUploadError"
|
|
||||||
}
|
|
||||||
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
|
|
||||||
if msg != "notImage" {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 建立映射
|
|
||||||
file.FileId = fileId
|
|
||||||
noteOrContent.Files[i] = file
|
|
||||||
|
|
||||||
if file.IsAttach {
|
|
||||||
attachNum++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.fixPostNotecontent(¬eOrContent)
|
|
||||||
|
|
||||||
// Log("Add")
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
|
|
||||||
// return c.RenderJson(re)
|
|
||||||
|
|
||||||
note := info.Note{UserId: userId,
|
|
||||||
NoteId: noteId,
|
|
||||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
|
||||||
Title: noteOrContent.Title,
|
|
||||||
Tags: noteOrContent.Tags,
|
|
||||||
Desc: noteOrContent.Desc,
|
|
||||||
// ImgSrc: noteOrContent.ImgSrc,
|
|
||||||
IsBlog: noteOrContent.IsBlog,
|
|
||||||
IsMarkdown: noteOrContent.IsMarkdown,
|
|
||||||
AttachNum: attachNum,
|
|
||||||
}
|
|
||||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
|
||||||
UserId: userId,
|
|
||||||
IsBlog: note.IsBlog,
|
|
||||||
Content: noteOrContent.Content,
|
|
||||||
Abstract: noteOrContent.Abstract}
|
|
||||||
|
|
||||||
// 通过内容得到Desc, abstract
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
note.Desc = SubStringHTMLToRaw(noteContent.Content, 200)
|
|
||||||
noteContent.Abstract = SubStringHTML(noteContent.Content, 200, "")
|
|
||||||
} else {
|
|
||||||
note.Desc = SubStringHTMLToRaw(noteContent.Abstract, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
note = noteService.AddNoteAndContentApi(note, noteContent, myUserId)
|
|
||||||
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re.Ok = false
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加需要返回的
|
|
||||||
noteOrContent.NoteId = note.NoteId.Hex()
|
|
||||||
noteOrContent.Usn = note.Usn
|
|
||||||
noteOrContent.CreatedTime = note.CreatedTime
|
|
||||||
noteOrContent.UpdatedTime = note.UpdatedTime
|
|
||||||
noteOrContent.UserId = c.getUserId()
|
|
||||||
noteOrContent.IsMarkdown = note.IsMarkdown
|
|
||||||
// 删除一些不要返回的, 删除Desc?
|
|
||||||
noteOrContent.Content = ""
|
|
||||||
noteOrContent.Abstract = ""
|
|
||||||
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
|
|
||||||
return c.RenderJson(noteOrContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
|
|
||||||
noteUpdate := bson.M{}
|
|
||||||
needUpdateNote := false
|
|
||||||
|
|
||||||
noteId := noteOrContent.NoteId
|
|
||||||
|
|
||||||
if noteOrContent.NoteId == "" {
|
|
||||||
re.Msg = "noteIdNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if noteOrContent.Usn <= 0 {
|
|
||||||
re.Msg = "usnNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log("_____________")
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
/*
|
|
||||||
LogJ(c.Params.Files)
|
|
||||||
LogJ(c.Request.Header)
|
|
||||||
LogJ(c.Params.Values)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 先判断USN的问题, 因为很可能添加完附件后, 会有USN冲突, 这时附件就添错了
|
|
||||||
userId := c.getUserId()
|
|
||||||
note := noteService.GetNote(noteId, userId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re.Msg = "notExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if note.Usn != noteOrContent.Usn {
|
|
||||||
re.Msg = "conflict"
|
|
||||||
Log("conflict")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果传了files
|
|
||||||
// TODO 测试
|
|
||||||
/*
|
|
||||||
for key, v := range c.Params.Values {
|
|
||||||
Log(key)
|
|
||||||
Log(v)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Log(c.Has("Files[0]"))
|
|
||||||
if c.Has("Files[0][LocalFileId]") {
|
|
||||||
// LogJ(c.Params.Files)
|
|
||||||
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
|
|
||||||
for i, file := range noteOrContent.Files {
|
|
||||||
if file.HasBody {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
// FileDatas[54c7ae27d98d0329dd000000]
|
|
||||||
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId, file.IsAttach)
|
|
||||||
if !ok {
|
|
||||||
Log("upload file error")
|
|
||||||
re.Ok = false
|
|
||||||
if msg == "" {
|
|
||||||
re.Msg = "fileUploadError"
|
|
||||||
} else {
|
|
||||||
re.Msg = msg
|
|
||||||
}
|
|
||||||
return c.RenderJson(re)
|
|
||||||
} else {
|
|
||||||
// 建立映射
|
|
||||||
file.FileId = fileId
|
|
||||||
noteOrContent.Files[i] = file
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log("after upload")
|
|
||||||
// LogJ(noteOrContent.Files)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移到外面来, 删除最后一个file时也要处理, 不然总删不掉
|
|
||||||
// 附件问题, 根据Files, 有些要删除的, 只留下这些
|
|
||||||
attachService.UpdateOrDeleteAttachApi(noteId, userId, noteOrContent.Files)
|
|
||||||
|
|
||||||
// Desc前台传来
|
|
||||||
if c.Has("Desc") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Desc"] = noteOrContent.Desc
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if c.Has("ImgSrc") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if c.Has("Title") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Title"] = noteOrContent.Title
|
|
||||||
}
|
|
||||||
if c.Has("IsTrash") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["IsTrash"] = noteOrContent.IsTrash
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否是博客
|
|
||||||
if c.Has("IsBlog") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["IsBlog"] = noteOrContent.IsBlog
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Log(c.Has("tags[0]"))
|
|
||||||
Log(c.Has("Tags[]"))
|
|
||||||
for key, v := range c.Params.Values {
|
|
||||||
Log(key)
|
|
||||||
Log(v)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if c.Has("Tags[0]") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Tags"] = noteOrContent.Tags
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Has("NotebookId") {
|
|
||||||
if bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["NotebookId"] = bson.ObjectIdHex(noteOrContent.NotebookId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Has("Content") {
|
|
||||||
// 通过内容得到Desc, 如果有Abstract, 则用Abstract生成Desc
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Content, 200)
|
|
||||||
} else {
|
|
||||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Abstract, 200)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
afterNoteUsn := 0
|
|
||||||
noteOk := false
|
|
||||||
noteMsg := ""
|
|
||||||
if needUpdateNote {
|
|
||||||
noteOk, noteMsg, afterNoteUsn = noteService.UpdateNote(c.getUserId(), noteOrContent.NoteId, noteUpdate, noteOrContent.Usn)
|
|
||||||
if !noteOk {
|
|
||||||
re.Ok = false
|
|
||||||
re.Msg = noteMsg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
afterContentUsn := 0
|
|
||||||
contentOk := false
|
|
||||||
contentMsg := ""
|
|
||||||
if c.Has("Content") {
|
|
||||||
// 把fileId替换下
|
|
||||||
c.fixPostNotecontent(¬eOrContent)
|
|
||||||
// 如果传了Abstract就用之
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
noteOrContent.Abstract = SubStringHTML(noteOrContent.Content, 200, "")
|
|
||||||
}
|
|
||||||
// Log("--------> afte fixed")
|
|
||||||
// Log(noteOrContent.Content)
|
|
||||||
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.getUserId(),
|
|
||||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, noteOrContent.Usn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if needUpdateNote {
|
|
||||||
re.Ok = noteOk
|
|
||||||
re.Msg = noteMsg
|
|
||||||
re.Usn = afterNoteUsn
|
|
||||||
} else {
|
|
||||||
re.Ok = contentOk
|
|
||||||
re.Msg = contentMsg
|
|
||||||
re.Usn = afterContentUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
if !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteOrContent.Content = ""
|
|
||||||
noteOrContent.Usn = re.Usn
|
|
||||||
noteOrContent.UpdatedTime = time.Now()
|
|
||||||
|
|
||||||
// Log("after upload")
|
|
||||||
// LogJ(noteOrContent.Files)
|
|
||||||
noteOrContent.UserId = c.getUserId()
|
|
||||||
|
|
||||||
return c.RenderJson(noteOrContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除trash
|
|
||||||
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到历史列表
|
|
||||||
/*
|
|
||||||
func (c ApiNote) GetHistories(noteId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
histories := noteContentHistoryService.ListHistories(noteId, c.getUserId())
|
|
||||||
if len(histories) > 0 {
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = histories
|
|
||||||
}
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 0.2 新增
|
|
||||||
// 导出成PDF
|
|
||||||
// test localhost:9000/api/note/exportPdf?noteId=554f07bf05fcd15fa9000000&token=562211dc99c37ba6a7000001
|
|
||||||
func (c ApiNote) ExportPdf(noteId string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
userId := c.getUserId()
|
|
||||||
if noteId == "" {
|
|
||||||
re.Msg = "noteNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
note := noteService.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re.Msg = "noteNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteUserId := note.UserId.Hex()
|
|
||||||
// 是否有权限
|
|
||||||
if noteUserId != userId {
|
|
||||||
// 是否是有权限协作的
|
|
||||||
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
|
||||||
re.Msg = "noteNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// path 判断是否需要重新生成之
|
|
||||||
guid := NewGuid()
|
|
||||||
fileUrlPath := "files/" + Digest3(noteUserId) + "/" + noteUserId + "/" + Digest2(guid) + "/images/pdf"
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
if !MkdirAll(dir) {
|
|
||||||
re.Msg = "noDir"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
filename := guid + ".pdf"
|
|
||||||
path := dir + "/" + filename
|
|
||||||
|
|
||||||
appKey, _ := revel.Config.String("app.secretLeanote")
|
|
||||||
if appKey == "" {
|
|
||||||
appKey, _ = revel.Config.String("app.secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成之
|
|
||||||
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
|
|
||||||
// 默认路径
|
|
||||||
if binPath == "" {
|
|
||||||
binPath = "/usr/local/bin/wkhtmltopdf"
|
|
||||||
}
|
|
||||||
|
|
||||||
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
|
|
||||||
var cc string
|
|
||||||
if(note.IsMarkdown) {
|
|
||||||
cc = binPath + " --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
} else {
|
|
||||||
cc = binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", cc)
|
|
||||||
_, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
re.Msg = "sysError"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
re.Msg = "sysError"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
filenameReturn := note.Title
|
|
||||||
filenameReturn = FixFilename(filenameReturn)
|
|
||||||
if filenameReturn == "" {
|
|
||||||
filenameReturn = "Untitled.pdf"
|
|
||||||
} else {
|
|
||||||
filenameReturn += ".pdf"
|
|
||||||
}
|
|
||||||
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
// "io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 笔记本API
|
|
||||||
|
|
||||||
type ApiNotebook struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从Notebook -> ApiNotebook
|
|
||||||
func (c ApiNotebook) fixNotebooks(notebooks []info.Notebook) []info.ApiNotebook {
|
|
||||||
if notebooks == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
apiNotebooks := make([]info.ApiNotebook, len(notebooks))
|
|
||||||
for i, notebook := range notebooks {
|
|
||||||
apiNotebooks[i] = c.fixNotebook(¬ebook)
|
|
||||||
}
|
|
||||||
return apiNotebooks
|
|
||||||
}
|
|
||||||
func (c ApiNotebook) fixNotebook(notebook *info.Notebook) info.ApiNotebook {
|
|
||||||
if notebook == nil {
|
|
||||||
return info.ApiNotebook{}
|
|
||||||
}
|
|
||||||
return info.ApiNotebook{
|
|
||||||
NotebookId : notebook.NotebookId,
|
|
||||||
UserId : notebook.UserId,
|
|
||||||
ParentNotebookId : notebook.ParentNotebookId,
|
|
||||||
Seq : notebook.Seq,
|
|
||||||
Title : notebook.Title,
|
|
||||||
UrlTitle : notebook.UrlTitle,
|
|
||||||
IsBlog : notebook.IsBlog,
|
|
||||||
CreatedTime : notebook.CreatedTime,
|
|
||||||
UpdatedTime : notebook.UpdatedTime,
|
|
||||||
Usn: notebook.Usn,
|
|
||||||
IsDeleted: notebook.IsDeleted,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的笔记本
|
|
||||||
// [OK]
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
|
|
||||||
func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户的所有笔记本
|
|
||||||
// [OK]
|
|
||||||
// info.SubNotebooks
|
|
||||||
func (c ApiNotebook) GetNotebooks() revel.Result {
|
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
|
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加notebook
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.Result {
|
|
||||||
notebook := info.Notebook{NotebookId: bson.NewObjectId(),
|
|
||||||
Title: title,
|
|
||||||
Seq: seq,
|
|
||||||
UserId: bson.ObjectIdHex(c.getUserId())}
|
|
||||||
if parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId) {
|
|
||||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
|
||||||
}
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, notebook = notebookService.AddNotebook(notebook)
|
|
||||||
if !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string, seq, usn int) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
|
|
||||||
ok, msg, notebook := notebookService.UpdateNotebookApi(c.getUserId(), notebookId, title, parentNotebookId, seq, usn)
|
|
||||||
if !ok {
|
|
||||||
re.Ok = false
|
|
||||||
re.Msg = msg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
LogJ(notebook)
|
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除笔记本
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
// "io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 标签API
|
|
||||||
|
|
||||||
type ApiTag struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的标签
|
|
||||||
// [OK]
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
|
|
||||||
func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加Tag
|
|
||||||
// [OK]
|
|
||||||
// 不会产生冲突, 即使里面有
|
|
||||||
// 返回
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"TagId": "551978dd99c37b9bc5000001",
|
|
||||||
"UserId": "54a1676399c37b1c77000002",
|
|
||||||
"Tag": "32",
|
|
||||||
"Usn": 25,
|
|
||||||
"Count": 1,
|
|
||||||
"CreatedTime": "2015-03-31T00:25:01.149312407+08:00",
|
|
||||||
"UpdatedTime": "2015-03-31T00:25:01.149312407+08:00",
|
|
||||||
"IsDeleted": false
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiTag) AddTag(tag string) revel.Result {
|
|
||||||
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
// [OK]
|
|
||||||
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"time"
|
|
||||||
// "github.com/leanote/leanote/app/types"
|
|
||||||
"io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "math"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
// "path"
|
|
||||||
// "strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ApiUser struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) Info() revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
|
|
||||||
userInfo := c.getUserInfo()
|
|
||||||
if userInfo.UserId == "" {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
apiUser := info.ApiUser{
|
|
||||||
UserId: userInfo.UserId.Hex(),
|
|
||||||
Username: userInfo.Username,
|
|
||||||
Email: userInfo.Email,
|
|
||||||
Logo: userInfo.Logo,
|
|
||||||
Verified: userInfo.Verified,
|
|
||||||
}
|
|
||||||
return c.RenderJson(apiUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改用户名
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdateUsername(username string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if c.GetUsername() == "demo" {
|
|
||||||
re.Msg = "cannotUpdateDemo"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改密码
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if c.GetUsername() == "demo" {
|
|
||||||
re.Msg = "cannotUpdateDemo"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获得同步状态
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) GetSyncState() revel.Result {
|
|
||||||
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 头像设置
|
|
||||||
// 参数file=文件
|
|
||||||
// 成功返回{Logo: url} 头像新url
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdateLogo() revel.Result {
|
|
||||||
ok, msg, url := c.uploadImage()
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
ok = userService.UpdateAvatar(c.getUserId(), url)
|
|
||||||
return c.RenderJson(map[string]string{"Logo": url})
|
|
||||||
} else {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = msg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传图片
|
|
||||||
func (c ApiUser) uploadImage() (ok bool, msg, url string) {
|
|
||||||
var fileUrlPath = ""
|
|
||||||
ok = false
|
|
||||||
|
|
||||||
file, handel, err := c.Request.FormFile("file")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
// 生成上传路径
|
|
||||||
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
|
|
||||||
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
err = os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 生成新的文件名
|
|
||||||
filename := handel.Filename
|
|
||||||
|
|
||||||
var ext string
|
|
||||||
|
|
||||||
_, ext = SplitFilename(filename)
|
|
||||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
|
||||||
msg = "notImage"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = NewGuid() + ext
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
LogJ(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// > 5M?
|
|
||||||
if len(data) > 5*1024*1024 {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
toPath := dir + "/" + filename
|
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
|
||||||
if err != nil {
|
|
||||||
LogJ(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true
|
|
||||||
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/info"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
// "strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApiUser struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户名, 需要重置session
|
||||||
|
func (c ApiUser) Info() revel.Result {
|
||||||
|
Log("APIUser");
|
||||||
|
return c.RenderTemplate("home/index.html");
|
||||||
|
// return nil;
|
||||||
|
}
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/leanote/leanote/app/service"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var userService *service.UserService
|
|
||||||
var noteService *service.NoteService
|
|
||||||
var trashService *service.TrashService
|
|
||||||
var notebookService *service.NotebookService
|
|
||||||
var noteContentHistoryService *service.NoteContentHistoryService
|
|
||||||
var authService *service.AuthService
|
|
||||||
var shareService *service.ShareService
|
|
||||||
var blogService *service.BlogService
|
|
||||||
var tagService *service.TagService
|
|
||||||
var pwdService *service.PwdService
|
|
||||||
var tokenService *service.TokenService
|
|
||||||
var suggestionService *service.SuggestionService
|
|
||||||
var albumService *service.AlbumService
|
|
||||||
var noteImageService *service.NoteImageService
|
|
||||||
var fileService *service.FileService
|
|
||||||
var attachService *service.AttachService
|
|
||||||
var configService *service.ConfigService
|
|
||||||
var emailService *service.EmailService
|
|
||||||
var sessionService *service.SessionService
|
|
||||||
|
|
||||||
var pageSize = 1000
|
|
||||||
var defaultSortField = "UpdatedTime"
|
|
||||||
var leanoteUserId = "admin" // 不能更改
|
|
||||||
|
|
||||||
// 状态
|
|
||||||
const (
|
|
||||||
S_DEFAULT = iota // 0
|
|
||||||
S_NOT_LOGIN // 1
|
|
||||||
S_WRONG_USERNAME_PASSWORD // 2
|
|
||||||
S_WRONG_CAPTCHA // 3
|
|
||||||
S_NEED_CAPTCHA // 4
|
|
||||||
S_NOT_OPEN_REGISTER // 4
|
|
||||||
)
|
|
||||||
|
|
||||||
// 拦截器
|
|
||||||
// 不需要拦截的url
|
|
||||||
var commonUrl = map[string]map[string]bool{"ApiAuth": map[string]bool{"Login": true,
|
|
||||||
"Register": true,
|
|
||||||
},
|
|
||||||
// 文件的操作也不用登录, userId会从session中获取
|
|
||||||
"ApiFile": map[string]bool{"GetImage": true,
|
|
||||||
"GetAttach": true,
|
|
||||||
"GetAllAttachs": true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func needValidate(controller, method string) bool {
|
|
||||||
// 在里面
|
|
||||||
if v, ok := commonUrl[controller]; ok {
|
|
||||||
// 在commonUrl里
|
|
||||||
if _, ok2 := v[method]; ok2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
// controller不在这里的, 肯定要验证
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这里得到token, 若不是login, logout等公用操作, 必须验证是否已登录
|
|
||||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
|
||||||
// 得到token /api/user/info?userId=xxx&token=xxxxx
|
|
||||||
token := c.Params.Values.Get("token")
|
|
||||||
noToken := false
|
|
||||||
if token == "" {
|
|
||||||
// 若无, 则取sessionId
|
|
||||||
token = c.Session.Id()
|
|
||||||
noToken = true
|
|
||||||
}
|
|
||||||
c.Session["_token"] = token
|
|
||||||
|
|
||||||
// 全部变成首字大写
|
|
||||||
var controller = strings.Title(c.Name)
|
|
||||||
var method = strings.Title(c.MethodName)
|
|
||||||
|
|
||||||
// 验证是否已登录
|
|
||||||
// 通过sessionService判断该token下是否有userId, 并返回userId
|
|
||||||
userId := sessionService.GetUserId(token)
|
|
||||||
if noToken && userId == "" {
|
|
||||||
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
|
|
||||||
// 客户端
|
|
||||||
userId, _ = c.Session["UserId"];
|
|
||||||
}
|
|
||||||
c.Session["_userId"] = userId
|
|
||||||
|
|
||||||
// 是否需要验证?
|
|
||||||
if !needValidate(controller, method) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if userId != "" {
|
|
||||||
return nil // 已登录
|
|
||||||
}
|
|
||||||
|
|
||||||
// 没有登录, 返回错误的信息, 需要登录
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "NOTLOGIN"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// interceptors
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiFile{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNote{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiTag{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNotebook{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最外层init.go调用
|
|
||||||
// 获取service, 单例
|
|
||||||
func InitService() {
|
|
||||||
notebookService = service.NotebookS
|
|
||||||
noteService = service.NoteS
|
|
||||||
noteContentHistoryService = service.NoteContentHistoryS
|
|
||||||
trashService = service.TrashS
|
|
||||||
shareService = service.ShareS
|
|
||||||
userService = service.UserS
|
|
||||||
tagService = service.TagS
|
|
||||||
blogService = service.BlogS
|
|
||||||
tokenService = service.TokenS
|
|
||||||
noteImageService = service.NoteImageS
|
|
||||||
fileService = service.FileS
|
|
||||||
albumService = service.AlbumS
|
|
||||||
attachService = service.AttachS
|
|
||||||
pwdService = service.PwdS
|
|
||||||
suggestionService = service.SuggestionS
|
|
||||||
authService = service.AuthS
|
|
||||||
configService = service.ConfigS
|
|
||||||
emailService = service.EmailS
|
|
||||||
sessionService = service.SessionS
|
|
||||||
}
|
|
||||||
@@ -48,7 +48,8 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
|||||||
"FindPasswordUpdate": true,
|
"FindPasswordUpdate": true,
|
||||||
"Suggestion": true,
|
"Suggestion": true,
|
||||||
},
|
},
|
||||||
"Note": map[string]bool{"ToPdf": true},
|
"Note": map[string]bool{"ToImage": true},
|
||||||
|
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
|
||||||
"Blog": map[string]bool{"Index": true,
|
"Blog": map[string]bool{"Index": true,
|
||||||
"View": true,
|
"View": true,
|
||||||
"AboutMe": true,
|
"AboutMe": true,
|
||||||
@@ -68,7 +69,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
|||||||
},
|
},
|
||||||
"Oauth": map[string]bool{"GithubCallback": true},
|
"Oauth": map[string]bool{"GithubCallback": true},
|
||||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
"Attach": map[string]bool{"Download": true/*, "DownloadAll": true*/},
|
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||||
}
|
}
|
||||||
|
|
||||||
func needValidate(controller, method string) bool {
|
func needValidate(controller, method string) bool {
|
||||||
@@ -146,7 +147,6 @@ func init() {
|
|||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Album{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
var ext string
|
var ext string
|
||||||
_, ext = SplitFilename(filename)
|
_, ext = SplitFilename(filename)
|
||||||
if ext != ".zip" {
|
if ext != ".zip" {
|
||||||
re.Msg = "Please upload zip file"
|
re.Msg = "请上传zip文件"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
|
|
||||||
// > 10M?
|
// > 10M?
|
||||||
if len(data) > 10*1024*1024 {
|
if len(data) > 10*1024*1024 {
|
||||||
re.Msg = "File is big than 10M"
|
re.Msg = "文件大于10M"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-36
@@ -6,7 +6,6 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"gopkg.in/mgo.v2"
|
"gopkg.in/mgo.v2"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init mgo and the common DAO
|
// Init mgo and the common DAO
|
||||||
@@ -29,7 +28,7 @@ var Groups *mgo.Collection
|
|||||||
var GroupUsers *mgo.Collection
|
var GroupUsers *mgo.Collection
|
||||||
|
|
||||||
var Tags *mgo.Collection
|
var Tags *mgo.Collection
|
||||||
var NoteTags *mgo.Collection
|
//var TagNotes *mgo.Collection
|
||||||
var TagCounts *mgo.Collection
|
var TagCounts *mgo.Collection
|
||||||
|
|
||||||
var UserBlogs *mgo.Collection
|
var UserBlogs *mgo.Collection
|
||||||
@@ -63,26 +62,10 @@ func Init(url, dbname string) {
|
|||||||
config := revel.Config
|
config := revel.Config
|
||||||
if url == "" {
|
if url == "" {
|
||||||
url, ok = config.String("db.url")
|
url, ok = config.String("db.url")
|
||||||
if !ok {
|
|
||||||
url, ok = config.String("db.urlEnv")
|
|
||||||
if ok {
|
|
||||||
Log("get db conf from urlEnv: " + url)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log("get db conf from db.url: " + url)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
// get dbname from urlEnv
|
|
||||||
urls := strings.Split(url, "/")
|
|
||||||
dbname = urls[len(urls)-1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if dbname == "" {
|
if dbname == "" {
|
||||||
dbname, _ = config.String("db.dbname")
|
dbname, _ = config.String("db.dbname")
|
||||||
}
|
}
|
||||||
|
|
||||||
// get db config from host, port, username, password
|
|
||||||
if !ok {
|
if !ok {
|
||||||
host, _ := revel.Config.String("db.host")
|
host, _ := revel.Config.String("db.host")
|
||||||
port, _ := revel.Config.String("db.port")
|
port, _ := revel.Config.String("db.port")
|
||||||
@@ -133,7 +116,7 @@ func Init(url, dbname string) {
|
|||||||
|
|
||||||
// tag
|
// tag
|
||||||
Tags = Session.DB(dbname).C("tags")
|
Tags = Session.DB(dbname).C("tags")
|
||||||
NoteTags = Session.DB(dbname).C("note_tags")
|
// TagNotes = Session.DB(dbname).C("tag_notes")
|
||||||
TagCounts = Session.DB(dbname).C("tag_count")
|
TagCounts = Session.DB(dbname).C("tag_count")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
@@ -355,20 +338,3 @@ func Err(err error) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查mognodb是否lost connection
|
|
||||||
// 每个请求之前都要检查!!
|
|
||||||
func CheckMongoSessionLost() {
|
|
||||||
// fmt.Println("检查CheckMongoSessionLostErr")
|
|
||||||
err := Session.Ping()
|
|
||||||
if err != nil {
|
|
||||||
Log("Lost connection to db!")
|
|
||||||
Session.Refresh()
|
|
||||||
err = Session.Ping()
|
|
||||||
if err == nil {
|
|
||||||
Log("Reconnect to db successful.")
|
|
||||||
} else {
|
|
||||||
Log("重连失败!!!! 警告")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-4
@@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
// convert revel msg to js msg
|
// convert revel msg to js msg
|
||||||
|
|
||||||
var msgBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/messages/"
|
var msgBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/messages/"
|
||||||
var targetBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/js/i18n/"
|
var targetBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/public/js/i18n/"
|
||||||
func parse(filename string) {
|
func parse(filename string) {
|
||||||
file, err := os.Open(msgBasePath + filename)
|
file, err := os.Open(msgBasePath + filename)
|
||||||
reader := bufio.NewReader(file)
|
reader := bufio.NewReader(file)
|
||||||
@@ -84,8 +84,6 @@ function getMsg(key, data) {
|
|||||||
func main() {
|
func main() {
|
||||||
parse("msg.en")
|
parse("msg.en")
|
||||||
parse("msg.zh")
|
parse("msg.zh")
|
||||||
parse("msg.fr")
|
|
||||||
parse("blog.zh")
|
parse("blog.zh")
|
||||||
parse("blog.en")
|
parse("blog.en")
|
||||||
parse("blog.fr")
|
|
||||||
}
|
}
|
||||||
-119
@@ -1,119 +0,0 @@
|
|||||||
package info
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
//---------
|
|
||||||
// 数据结构
|
|
||||||
//---------
|
|
||||||
type NoteFile struct {
|
|
||||||
FileId string // 服务器端Id
|
|
||||||
LocalFileId string // 客户端Id
|
|
||||||
Type string // images/png, doc, xls, 根据fileName确定
|
|
||||||
Title string
|
|
||||||
HasBody bool // 传过来的值是否要更新内容
|
|
||||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
|
||||||
}
|
|
||||||
type ApiNote struct {
|
|
||||||
NoteId string
|
|
||||||
NotebookId string
|
|
||||||
UserId string
|
|
||||||
Title string
|
|
||||||
Desc string
|
|
||||||
// ImgSrc string
|
|
||||||
Tags []string
|
|
||||||
Abstract string
|
|
||||||
Content string
|
|
||||||
IsMarkdown bool
|
|
||||||
// FromUserId string // 为共享而新建
|
|
||||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
|
||||||
IsTrash bool
|
|
||||||
IsDeleted bool
|
|
||||||
Usn int
|
|
||||||
Files []NoteFile
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
PublicTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 内容
|
|
||||||
type ApiNoteContent struct {
|
|
||||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
|
||||||
|
|
||||||
Content string `Content`
|
|
||||||
|
|
||||||
// CreatedTime time.Time `CreatedTime`
|
|
||||||
// UpdatedTime time.Time `UpdatedTime`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换
|
|
||||||
func NoteToApiNote(note Note, files []NoteFile) ApiNote {
|
|
||||||
apiNote := ApiNote{}
|
|
||||||
return apiNote
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// 用户信息
|
|
||||||
//----------
|
|
||||||
|
|
||||||
type ApiUser struct {
|
|
||||||
UserId string
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Verified bool
|
|
||||||
Logo string
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// Notebook
|
|
||||||
//----------
|
|
||||||
type ApiNotebook struct {
|
|
||||||
NotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
|
||||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
|
||||||
Seq int `Seq` // 排序
|
|
||||||
Title string `Title` // 标题
|
|
||||||
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
|
||||||
CreatedTime time.Time `CreatedTime,omitempty`
|
|
||||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
IsDeleted bool `IsDeleted`
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------
|
|
||||||
// api 返回
|
|
||||||
//---------
|
|
||||||
|
|
||||||
// 一般返回
|
|
||||||
type ApiRe struct {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewApiRe() ApiRe {
|
|
||||||
return ApiRe{Ok: false}
|
|
||||||
}
|
|
||||||
|
|
||||||
// auth
|
|
||||||
type AuthOk struct {
|
|
||||||
Ok bool
|
|
||||||
Token string
|
|
||||||
UserId bson.ObjectId
|
|
||||||
Email string
|
|
||||||
Username string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 供notebook, note, tag更新的返回数据用
|
|
||||||
type ReUpdate struct {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
func NewReUpdate() ReUpdate {
|
|
||||||
return ReUpdate{Ok: false}
|
|
||||||
}
|
|
||||||
@@ -47,11 +47,3 @@ type Archive struct {
|
|||||||
MonthAchives []ArchiveMonth
|
MonthAchives []ArchiveMonth
|
||||||
Posts []*Post
|
Posts []*Post
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cate struct {
|
|
||||||
CateId string
|
|
||||||
ParentCateId string
|
|
||||||
Title string
|
|
||||||
UrlTitle string
|
|
||||||
Children []*Cate
|
|
||||||
}
|
|
||||||
@@ -41,10 +41,7 @@ type Note struct {
|
|||||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
SharePass int `SharePass` //分享笔记的密码
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
|
|
||||||
IsDeleted bool `IsDeleted` // 删除位
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ type Notebook struct {
|
|||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||||
CreatedTime time.Time `CreatedTime,omitempty`
|
CreatedTime time.Time `CreatedTime,omitempty`
|
||||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
UpdatedTime time.Time `UpdatedTime,omitempty`
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
IsDeleted bool `IsDeleted`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 仅仅是为了返回前台
|
// 仅仅是为了返回前台
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ type Session struct {
|
|||||||
|
|
||||||
LoginTimes int `LoginTimes` // 登录错误时间
|
LoginTimes int `LoginTimes` // 登录错误时间
|
||||||
Captcha string `Captcha` // 验证码
|
Captcha string `Captcha` // 验证码
|
||||||
|
Token string `Token` //attach token
|
||||||
UserId string `UserId` // API时有值UserId
|
TokenTime time.Time `TokenTime` //token生成时间
|
||||||
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ package info
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 这里主要是为了统计每个tag的note数目
|
// 这里主要是为了统计每个tag的note数目
|
||||||
@@ -22,18 +21,6 @@ type Tag struct {
|
|||||||
Tags []string `Tags`
|
Tags []string `Tags`
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2 版标签
|
|
||||||
type NoteTag struct {
|
|
||||||
TagId bson.ObjectId `bson:"_id"`
|
|
||||||
UserId bson.ObjectId `UserId` // 谁的
|
|
||||||
Tag string `Tag` // UserId, Tag是唯一索引
|
|
||||||
Usn int `Usn` // Update Sequence Number
|
|
||||||
Count int `Count` // 笔记数
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
|
||||||
IsDeleted bool `IsDeleted` // 删除位
|
|
||||||
}
|
|
||||||
|
|
||||||
type TagCount struct {
|
type TagCount struct {
|
||||||
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
UserId bson.ObjectId `UserId` // 谁的
|
UserId bson.ObjectId `UserId` // 谁的
|
||||||
@@ -41,7 +28,6 @@ type TagCount struct {
|
|||||||
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||||
Count int `Count` // 统计数量
|
Count int `Count` // 统计数量
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
type TagsCounts []TagCount
|
type TagsCounts []TagCount
|
||||||
func (this TagsCounts) Len() int {
|
func (this TagsCounts) Len() int {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type Theme struct {
|
|||||||
Version string `Version`
|
Version string `Version`
|
||||||
Author string `Author`
|
Author string `Author`
|
||||||
AuthorUrl string `AuthorUrl`
|
AuthorUrl string `AuthorUrl`
|
||||||
Path string `Path` // 文件夹路径, public/upload/54d7620d99c37b030600002c/themes/54d867c799c37b533e000001
|
Path string `Path` // 文件夹路径
|
||||||
Info map[string]interface{} `Info` // 所有信息
|
Info map[string]interface{} `Info` // 所有信息
|
||||||
IsActive bool `IsActive` // 是否在用
|
IsActive bool `IsActive` // 是否在用
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ type User struct {
|
|||||||
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
|
||||||
Usn int `Usn` // UpdateSequenceNum , 全局的
|
|
||||||
FullSyncBefore time.Time `bson:"FullSyncBefore"` // 需要全量同步的时间, 如果 > 客户端的LastSyncTime, 则需要全量更新
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserAccount struct {
|
type UserAccount struct {
|
||||||
@@ -70,13 +66,6 @@ type UserAccount struct {
|
|||||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
}
|
}
|
||||||
|
|
||||||
// note主页需要
|
|
||||||
type UserAndBlogUrl struct {
|
|
||||||
User
|
|
||||||
BlogUrl string `BlogUrl`
|
|
||||||
PostUrl string `PostUrl`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用户与博客信息结合, 公开
|
// 用户与博客信息结合, 公开
|
||||||
type UserAndBlog struct {
|
type UserAndBlog struct {
|
||||||
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
|||||||
+9
-58
@@ -6,10 +6,11 @@ import (
|
|||||||
"github.com/leanote/leanote/app/service"
|
"github.com/leanote/leanote/app/service"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
"github.com/leanote/leanote/app/controllers/api"
|
|
||||||
"github.com/leanote/leanote/app/controllers/admin"
|
"github.com/leanote/leanote/app/controllers/admin"
|
||||||
"github.com/leanote/leanote/app/controllers/member"
|
"github.com/leanote/leanote/app/controllers/member"
|
||||||
_ "github.com/leanote/leanote/app/lea/binder"
|
_ "github.com/leanote/leanote/app/lea/binder"
|
||||||
|
"github.com/leanote/leanote/app/lea/session"
|
||||||
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
"github.com/leanote/leanote/app/lea/route"
|
"github.com/leanote/leanote/app/lea/route"
|
||||||
"reflect"
|
"reflect"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -31,11 +32,11 @@ func init() {
|
|||||||
// AuthFilter, // Invoke the action.
|
// AuthFilter, // Invoke the action.
|
||||||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
||||||
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
||||||
revel.SessionFilter, // Restore and write the session cookie.
|
// revel.SessionFilter, // Restore and write the session cookie.
|
||||||
|
|
||||||
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
|
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
|
||||||
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
||||||
// session.SessionFilter, // leanote session
|
session.SessionFilter, // leanote session
|
||||||
// session.MSessionFilter, // leanote memcache session
|
// session.MSessionFilter, // leanote memcache session
|
||||||
|
|
||||||
revel.FlashFilter, // Restore and write the flash cookie.
|
revel.FlashFilter, // Restore and write the flash cookie.
|
||||||
@@ -49,18 +50,6 @@ func init() {
|
|||||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||||
return template.HTML(str)
|
return template.HTML(str)
|
||||||
}
|
}
|
||||||
revel.TemplateFuncs["trim"] = func(str string) string {
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
|
|
||||||
str = strings.Trim(str, "\n")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
|
|
||||||
// 以下两个空格不一样
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
revel.TemplateFuncs["add"] = func(i int) string {
|
revel.TemplateFuncs["add"] = func(i int) string {
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
return fmt.Sprintf("%v", i)
|
return fmt.Sprintf("%v", i)
|
||||||
@@ -155,43 +144,8 @@ func init() {
|
|||||||
return template.HTML(tagStr)
|
return template.HTML(tagStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
revel.TemplateFuncs["blogTagsForExport"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
|
|
||||||
if tags == nil || len(tags) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
tagStr := ""
|
|
||||||
lenTags := len(tags)
|
|
||||||
|
|
||||||
for i, tag := range tags {
|
|
||||||
str := tag
|
|
||||||
var classes = "label"
|
|
||||||
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
|
|
||||||
classes += " label-" + tag
|
|
||||||
} else {
|
|
||||||
classes += " label-default"
|
|
||||||
}
|
|
||||||
|
|
||||||
classes += " label-post"
|
|
||||||
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>";
|
|
||||||
if i != lenTags - 1 {
|
|
||||||
tagStr += " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return template.HTML(tagStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不用revel的msg
|
|
||||||
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
|
|
||||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
|
||||||
str := revel.Message(locale, key)
|
|
||||||
if strings.HasPrefix(str, "???") {
|
|
||||||
str = key
|
|
||||||
}
|
|
||||||
return template.HTML(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lea++
|
// lea++
|
||||||
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, typeStr string) template.HTML {
|
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
|
||||||
if tags == nil || len(tags) == 0 {
|
if tags == nil || len(tags) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -200,12 +154,10 @@ func init() {
|
|||||||
lenTags := len(tags)
|
lenTags := len(tags)
|
||||||
|
|
||||||
tagPostUrl := "http://lea.leanote.com/"
|
tagPostUrl := "http://lea.leanote.com/"
|
||||||
if typeStr == "recommend" {
|
if isRecommend {
|
||||||
tagPostUrl += "?tag=";
|
tagPostUrl += "?tag=";
|
||||||
} else if typeStr == "latest" {
|
|
||||||
tagPostUrl += "latest?tag=";
|
|
||||||
} else {
|
} else {
|
||||||
tagPostUrl += "subscription?tag=";
|
tagPostUrl += "latest?tag=";
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tag := range tags {
|
for i, tag := range tags {
|
||||||
@@ -414,13 +366,12 @@ func init() {
|
|||||||
// email配置
|
// email配置
|
||||||
InitEmail()
|
InitEmail()
|
||||||
InitVd()
|
InitVd()
|
||||||
// memcache.InitMemcache() // session服务
|
memcache.InitMemcache() // session服务
|
||||||
// 其它service
|
// 其它service
|
||||||
service.InitService()
|
service.InitService()
|
||||||
controllers.InitService()
|
controllers.InitService()
|
||||||
admin.InitService()
|
admin.InitService()
|
||||||
member.InitService()
|
member.InitService()
|
||||||
service.ConfigS.InitGlobalConfigs()
|
service.ConfigS.InitGlobalConfigs()
|
||||||
api.InitService()
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
@@ -56,14 +56,6 @@ func ClearDir(dir string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func MkdirAll(dir string) bool {
|
|
||||||
err := os.MkdirAll(dir, 0777)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// list dir's all file, return filenames
|
// list dir's all file, return filenames
|
||||||
func ListDir(dir string) []string {
|
func ListDir(dir string) []string {
|
||||||
f, err := os.Open(dir)
|
f, err := os.Open(dir)
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package lea
|
|
||||||
|
|
||||||
// 对比密码是否一致
|
|
||||||
// 因为之前密码是用md5加密的, 所以通过密码长度来判断
|
|
||||||
// rawPwd 原始, 用户输入的密码
|
|
||||||
func ComparePwd(rawPwd, dbPwd string) bool {
|
|
||||||
if len(dbPwd) == 32 {
|
|
||||||
return Md5(rawPwd) == dbPwd
|
|
||||||
}
|
|
||||||
|
|
||||||
hex := []byte(dbPwd)
|
|
||||||
return CompareHash(hex, rawPwd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加密
|
|
||||||
func GenPwd(rawPwd string) string {
|
|
||||||
digest, err := GenerateHash(rawPwd)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string(digest)
|
|
||||||
}
|
|
||||||
+20
-135
@@ -10,9 +10,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
|
||||||
"bytes"
|
|
||||||
math_rand "math/rand"
|
math_rand "math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,22 +22,6 @@ func Md5(s string) string {
|
|||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3位数的转换, 为了用bson.id -> 3位数
|
|
||||||
func Digest3(str string) string {
|
|
||||||
var b rune = 0
|
|
||||||
for _, k := range str {
|
|
||||||
b += k
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d", b % 1000)
|
|
||||||
}
|
|
||||||
func Digest2(str string) string {
|
|
||||||
var b rune = 0
|
|
||||||
for _, k := range str {
|
|
||||||
b += k
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d", b % 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guid
|
// Guid
|
||||||
func NewGuid() string {
|
func NewGuid() string {
|
||||||
b := make([]byte, 48)
|
b := make([]byte, 48)
|
||||||
@@ -141,49 +122,39 @@ func ReplaceAll(oldStr, pattern, newStr string) string {
|
|||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取纯文本
|
func SubStringHTML(param string, length int, end string) string {
|
||||||
func SubStringHTMLToRaw(param string, length int) string {
|
// 先取出<pre></pre>占位..
|
||||||
if param == "" {
|
|
||||||
return param
|
result := ""
|
||||||
}
|
|
||||||
|
// 1
|
||||||
n := 0
|
n := 0
|
||||||
var temp rune // 中文问题, 用rune来解决
|
var temp rune // 中文问题, 用rune来解决
|
||||||
|
isCode := false //是不是HTML代码
|
||||||
|
isHTML := false //是不是HTML特殊字符,如
|
||||||
rStr := []rune(param)
|
rStr := []rune(param)
|
||||||
lenStr := len(rStr)
|
for i := 0; i < len(rStr); i++ {
|
||||||
isCode := false
|
|
||||||
|
|
||||||
resultRune := make([]rune, length)
|
|
||||||
// s := ""
|
|
||||||
for i := 0; i < lenStr; i++ {
|
|
||||||
temp = rStr[i]
|
temp = rStr[i]
|
||||||
if temp == '<' {
|
if temp == '<' {
|
||||||
isCode = true
|
isCode = true
|
||||||
continue
|
} else if temp == '&' {
|
||||||
} else if temp == '>' {
|
isHTML = true
|
||||||
|
} else if temp == '>' && isCode {
|
||||||
|
n = n - 1
|
||||||
isCode = false
|
isCode = false
|
||||||
resultRune[n] = ' ';
|
} else if temp == ';' && isHTML {
|
||||||
|
isHTML = false
|
||||||
n++
|
|
||||||
if n >= length {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
continue
|
if !isCode && !isHTML {
|
||||||
|
n = n + 1
|
||||||
}
|
}
|
||||||
if !isCode {
|
result += string(temp)
|
||||||
resultRune[n] = temp;
|
|
||||||
// s += string(temp)
|
|
||||||
n++
|
|
||||||
if n >= length {
|
if n >= length {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
result += end
|
||||||
result := string(resultRune[0:n])
|
|
||||||
return strings.Trim(result, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自带方法补全html
|
|
||||||
func fixHtml(result string) string {
|
|
||||||
// 取出所有标签
|
// 取出所有标签
|
||||||
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
|
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
|
||||||
|
|
||||||
@@ -225,72 +196,6 @@ func fixHtml(result string) string {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取摘要, HTML
|
|
||||||
func SubStringHTML(param string, length int, end string) string {
|
|
||||||
if param == "" {
|
|
||||||
return param
|
|
||||||
}
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
rStr := []rune(param)
|
|
||||||
lenStr := len(rStr)
|
|
||||||
|
|
||||||
if lenStr <= length {
|
|
||||||
result = param
|
|
||||||
} else {
|
|
||||||
// 1
|
|
||||||
n := 0
|
|
||||||
var temp rune // 中文问题, 用rune来解决
|
|
||||||
isCode := false //是不是HTML代码
|
|
||||||
isHTML := false //是不是HTML特殊字符,如
|
|
||||||
var i = 0;
|
|
||||||
for ; i < lenStr; i++ {
|
|
||||||
temp = rStr[i]
|
|
||||||
if temp == '<' {
|
|
||||||
isCode = true
|
|
||||||
} else if temp == '&' {
|
|
||||||
isHTML = true
|
|
||||||
} else if temp == '>' && isCode {
|
|
||||||
// n = n - 1
|
|
||||||
isCode = false
|
|
||||||
} else if temp == ';' && isHTML {
|
|
||||||
isHTML = false
|
|
||||||
}
|
|
||||||
if !isCode && !isHTML {
|
|
||||||
n = n + 1
|
|
||||||
}
|
|
||||||
// 每一次都相加, 速度非常慢!, 重新分配内存, 7倍的差距
|
|
||||||
// result += string(temp)
|
|
||||||
if n >= length {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = string(rStr[0:i])
|
|
||||||
|
|
||||||
if end != "" {
|
|
||||||
result += end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用goquery来取出html, 为了补全html
|
|
||||||
htmlReader := bytes.NewBufferString(result)
|
|
||||||
dom, err1 := goquery.NewDocumentFromReader(htmlReader)
|
|
||||||
if err1 == nil {
|
|
||||||
html, _ := dom.Html()
|
|
||||||
html = strings.Replace(html, "<html><head></head><body>", "", 1)
|
|
||||||
html = strings.Replace(html, "</body></html>", "", 1)
|
|
||||||
|
|
||||||
// TODO 把style="float: left"去掉
|
|
||||||
return html
|
|
||||||
|
|
||||||
// 如果有错误, 则使用自己的方法补全, 有风险
|
|
||||||
} else {
|
|
||||||
return fixHtml(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否是合格的密码
|
// 是否是合格的密码
|
||||||
func IsGoodPwd(pwd string) (bool, string) {
|
func IsGoodPwd(pwd string) (bool, string) {
|
||||||
if pwd == "" {
|
if pwd == "" {
|
||||||
@@ -307,7 +212,7 @@ func IsEmail(email string) bool {
|
|||||||
if email == "" {
|
if email == "" {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.|\-]?)*[_a-z\-A-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-zA-Z0-9\-]+\.[0-9a-zA-Z]{2,6}$`, email)
|
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[0-9a-zA-Z]{2,3}$`, email)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,23 +279,3 @@ func InArray(arr []string, str string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将名称的特殊字符去掉
|
|
||||||
func FixFilename(filename string) string {
|
|
||||||
if filename != "" {
|
|
||||||
// 把特殊字段给替换掉
|
|
||||||
// str := `life "%&()+,/:;<>=?@\|`
|
|
||||||
// . == \\.
|
|
||||||
// $ === \\$
|
|
||||||
reg, _ := regexp.Compile("\\.|/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
|
|
||||||
filename = reg.ReplaceAllString(filename, "-")
|
|
||||||
filename = strings.Trim(filename, "-") // 左右单独的-去掉
|
|
||||||
// 把空格替换成-
|
|
||||||
// filename = strings.Replace(filename, " ", "-", -1)
|
|
||||||
for strings.Index(filename, "--") >= 0 { // 防止出现连续的--
|
|
||||||
filename = strings.Replace(filename, "--", "-", -1)
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
// "github.com/leanote/leanote/app/controllers/api"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -55,34 +54,15 @@ func nextKey(key string) string {
|
|||||||
return key[:fieldLen]
|
return key[:fieldLen]
|
||||||
}
|
}
|
||||||
var leanoteStructBinder = revel.Binder{
|
var leanoteStructBinder = revel.Binder{
|
||||||
// name == "noteOrContent"
|
|
||||||
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
||||||
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取
|
result := reflect.New(typ).Elem()
|
||||||
fieldValues := make(map[string]reflect.Value)
|
fieldValues := make(map[string]reflect.Value)
|
||||||
// fmt.Println(name)
|
for key, _ := range params.Values {
|
||||||
// fmt.Println(typ) // api.NoteFiles
|
|
||||||
// name = files[0], files[1], noteContent
|
|
||||||
// fmt.Println(params.Values)
|
|
||||||
/*
|
|
||||||
map[Title:[test1] METHOD:[POST] NotebookId:[54c4f51705fcd14031000002]
|
|
||||||
files[1][FileId]:[]
|
|
||||||
controller:[note]
|
|
||||||
files[1][LocalFileId]:[54c7ae27d98d0329dd000000] files[1][HasBody]:[true] files[0][FileId]:[] files[0][LocalFileId]:[54c7ae855e94ea2dba000000] action:[addNote] Content:[<p>lifedddddd</p><p><img src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" alt="" data-mce-src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" style="display: block; margin-left: auto; margin-right: auto;"></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae27d98d0329dd000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImg?fileId=54c7ae27d98d0329dd000000"></p><p><br></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" style="display: block; margin-left: auto; margin-right: auto;"></p><p><br></p><p><br></p>] IsBlog:[false] token:[user1]
|
|
||||||
files[0][HasBody]:[true]]
|
|
||||||
*/
|
|
||||||
nameIsSlice := strings.Contains(name, "[")
|
|
||||||
// fmt.Println(params.Values["files[1]"])
|
|
||||||
// fmt.Println(params.Values["Title"])
|
|
||||||
for key, _ := range params.Values {// Title, Content, Files
|
|
||||||
// 这里, 如果没有点, 默认就是a.
|
// 这里, 如果没有点, 默认就是a.
|
||||||
// life
|
// life
|
||||||
// fmt.Println("key:" + key); // files[0][LocalFileId]
|
|
||||||
// fmt.Println("name:" + name); // files[0][LocalFileId]
|
|
||||||
var suffix string
|
var suffix string
|
||||||
var noPrefix = false
|
var noPrefix = false
|
||||||
if nameIsSlice && strings.HasPrefix(key, name) {
|
if !strings.HasPrefix(key, name + ".") {
|
||||||
suffix = key[len(name)+1:len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
|
|
||||||
} else if !strings.HasPrefix(key, name + ".") {
|
|
||||||
noPrefix = true
|
noPrefix = true
|
||||||
suffix = key
|
suffix = key
|
||||||
// continue
|
// continue
|
||||||
@@ -91,18 +71,13 @@ files[0][HasBody]:[true]]
|
|||||||
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
||||||
suffix = key[len(name)+1:]
|
suffix = key[len(name)+1:]
|
||||||
}
|
}
|
||||||
// fmt.Println(suffix);
|
|
||||||
|
|
||||||
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
||||||
// fmt.Println(fieldName);
|
|
||||||
fieldLen := len(fieldName)
|
fieldLen := len(fieldName)
|
||||||
|
|
||||||
if _, ok := fieldValues[fieldName]; !ok {
|
if _, ok := fieldValues[fieldName]; !ok {
|
||||||
// Time to bind this field. Get it and make sure we can set it.
|
// Time to bind this field. Get it and make sure we can set it.
|
||||||
fieldName = strings.Title(fieldName) // 传过来title, 但struct是Title
|
|
||||||
// fmt.Println("xx: " + fieldName)
|
|
||||||
fieldValue := result.FieldByName(fieldName)
|
fieldValue := result.FieldByName(fieldName)
|
||||||
// fmt.Println(fieldValue)
|
|
||||||
if !fieldValue.IsValid() {
|
if !fieldValue.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -112,16 +87,8 @@ files[0][HasBody]:[true]]
|
|||||||
var boundVal reflect.Value
|
var boundVal reflect.Value
|
||||||
// 没有name前缀
|
// 没有name前缀
|
||||||
if(noPrefix) {
|
if(noPrefix) {
|
||||||
// life
|
|
||||||
// fmt.Println("<<")
|
|
||||||
// fmt.Println(strings.Title(key[:fieldLen]));
|
|
||||||
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
||||||
} else {
|
} else {
|
||||||
// fmt.Println("final")
|
|
||||||
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
|
|
||||||
if nameIsSlice {
|
|
||||||
fieldLen += 1
|
|
||||||
}
|
|
||||||
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
|
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
|
||||||
}
|
}
|
||||||
fieldValue.Set(boundVal)
|
fieldValue.Set(boundVal)
|
||||||
@@ -149,8 +116,5 @@ func init() {
|
|||||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.UserAccount{})] = leanoteStructBinder
|
|
||||||
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
|
|
||||||
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
|
|
||||||
}
|
}
|
||||||
@@ -179,6 +179,8 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
|
|
||||||
// 将该basePath下的所有文件提出
|
// 将该basePath下的所有文件提出
|
||||||
files := ListDir(basePath)
|
files := ListDir(basePath)
|
||||||
|
Log(basePath)
|
||||||
|
LogJ(files);
|
||||||
for _, t := range files {
|
for _, t := range files {
|
||||||
if !strings.Contains(t, ".html") {
|
if !strings.Contains(t, ".html") {
|
||||||
continue;
|
continue;
|
||||||
@@ -213,8 +215,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
//
|
// 错误显示
|
||||||
|
|
||||||
|
|
||||||
type ErrorResult struct {
|
type ErrorResult struct {
|
||||||
RenderArgs map[string]interface{}
|
RenderArgs map[string]interface{}
|
||||||
@@ -289,12 +290,13 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
|||||||
r.RenderArgs["Router"] = revel.MainRouter
|
r.RenderArgs["Router"] = revel.MainRouter
|
||||||
|
|
||||||
// 不是preview就不要显示错误了
|
// 不是preview就不要显示错误了
|
||||||
if r.IsPreview {
|
LogJ(revelError)
|
||||||
|
// if r.IsPreview {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
out := io.Writer(resp.Out)
|
out := io.Writer(resp.Out)
|
||||||
// out = ioutil.Discard
|
// out = ioutil.Discard
|
||||||
err = tmpl.Execute(&b, r.RenderArgs)
|
err = tmpl.Execute(&b, r.RenderArgs)
|
||||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
b.WriteTo(out)
|
b.WriteTo(out)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// contains two cryptographic functions for both storing and comparing passwords.
|
|
||||||
package lea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateHash generates bcrypt hash from plaintext password
|
|
||||||
func GenerateHash(password string) ([]byte, error) {
|
|
||||||
hex := []byte(password)
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword(hex, 10)
|
|
||||||
if err != nil {
|
|
||||||
return hashedPassword, err
|
|
||||||
}
|
|
||||||
return hashedPassword, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompareHash compares bcrypt password with a plaintext one. Returns true if passwords match
|
|
||||||
// and false if they do not.
|
|
||||||
func CompareHash(digest []byte, password string) bool {
|
|
||||||
hex := []byte(password)
|
|
||||||
if err := bcrypt.CompareHashAndPassword(digest, hex); err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package memcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/robfig/gomemcache/memcache"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client *memcache.Client
|
||||||
|
|
||||||
|
// onAppStart后调用
|
||||||
|
func InitMemcache() {
|
||||||
|
client = memcache.New("localhost:11211")
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// map
|
||||||
|
|
||||||
|
func SetMap(key string, value map[string]string, expiration int32) {
|
||||||
|
// 把value转成byte
|
||||||
|
bytes, _ := json.Marshal(value)
|
||||||
|
if expiration == -1 {
|
||||||
|
expiration = 30 * 24 * 60 * 60 // 30天
|
||||||
|
}
|
||||||
|
client.Set(&memcache.Item{Key: key, Value: bytes, Expiration: expiration})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMap(key string) map[string]string {
|
||||||
|
item, err := client.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := map[string]string{}
|
||||||
|
json.Unmarshal(item.Value, &m)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// string
|
||||||
|
func GetString(key string) string {
|
||||||
|
item, err := client.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(item.Value)
|
||||||
|
}
|
||||||
|
func SetString(key string, value string, expiration int32) {
|
||||||
|
if expiration == -1 {
|
||||||
|
expiration = 30 * 24 * 60 * 60 // 30天
|
||||||
|
}
|
||||||
|
client.Set(&memcache.Item{Key: key, Value: []byte(value), Expiration: expiration})
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
// int, 是通过转成string来存的
|
||||||
|
|
||||||
|
func GetInt(key string) int {
|
||||||
|
str := GetString(key)
|
||||||
|
i, _ := strconv.Atoi(str)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
func SetInt(key string, value int, expiration int32) {
|
||||||
|
str := strconv.Itoa(value)
|
||||||
|
SetString(key, str, expiration)
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package route
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/db"
|
// "github.com/leanote/leanote/app/service"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -42,10 +42,6 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if route.ControllerName != "Static" {
|
if route.ControllerName != "Static" {
|
||||||
|
|
||||||
// 检查mongodb 是否lost
|
|
||||||
db.CheckMongoSessionLost()
|
|
||||||
|
|
||||||
// api设置
|
// api设置
|
||||||
// leanote.com/api/user/get => ApiUser::Get
|
// leanote.com/api/user/get => ApiUser::Get
|
||||||
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 使用filter
|
||||||
|
// 很巧妙就使用了memcache来处理session
|
||||||
|
// revel的session(cookie)只存sessionId, 其它信息存在memcache中
|
||||||
|
|
||||||
|
func MSessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
|
||||||
|
// 从memcache中得到cache, 赋给session
|
||||||
|
cache := revel.Session(memcache.GetMap(sessionId))
|
||||||
|
|
||||||
|
Log("memcache")
|
||||||
|
LogJ(cache)
|
||||||
|
if cache == nil {
|
||||||
|
cache = revel.Session{}
|
||||||
|
cache.Id()
|
||||||
|
}
|
||||||
|
c.Session = cache
|
||||||
|
|
||||||
|
// Make session vars available in templates as {{.session.xyz}}
|
||||||
|
c.RenderArgs["session"] = c.Session
|
||||||
|
|
||||||
|
fc[0](c, fc[1:])
|
||||||
|
|
||||||
|
// 再把session保存之
|
||||||
|
LogJ(c.Session)
|
||||||
|
memcache.SetMap(sessionId, c.Session, -1)
|
||||||
|
|
||||||
|
// 只留下sessionId
|
||||||
|
c.Session = revel.Session{revel.SESSION_ID_KEY: sessionId}
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主要修改revel的cookie, 设置Domain
|
||||||
|
// 为了使sub domain共享cookie
|
||||||
|
// cookie.domain = leanote.com
|
||||||
|
|
||||||
|
// A signed cookie (and thus limited to 4kb in size).
|
||||||
|
// Restriction: Keys may not have a colon in them.
|
||||||
|
type Session map[string]string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SESSION_ID_KEY = "_ID"
|
||||||
|
TIMESTAMP_KEY = "_TS"
|
||||||
|
)
|
||||||
|
|
||||||
|
// expireAfterDuration is the time to live, in seconds, of a session cookie.
|
||||||
|
// It may be specified in config as "session.expires". Values greater than 0
|
||||||
|
// set a persistent cookie with a time to live as specified, and the value 0
|
||||||
|
// sets a session cookie.
|
||||||
|
var expireAfterDuration time.Duration
|
||||||
|
var cookieDomain = "" // life
|
||||||
|
func init() {
|
||||||
|
// Set expireAfterDuration, default to 30 days if no value in config
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
var err error
|
||||||
|
if expiresString, ok := revel.Config.String("session.expires"); !ok {
|
||||||
|
expireAfterDuration = 30 * 24 * time.Hour
|
||||||
|
} else if expiresString == "session" {
|
||||||
|
expireAfterDuration = 0
|
||||||
|
} else if expireAfterDuration, err = time.ParseDuration(expiresString); err != nil {
|
||||||
|
panic(fmt.Errorf("session.expires invalid: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
cookieDomain, _ = revel.Config.String("cookie.domain")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
||||||
|
// session.
|
||||||
|
func (s Session) Id() string {
|
||||||
|
|
||||||
|
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
||||||
|
return sessionIdStr
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(buffer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s[SESSION_ID_KEY] = hex.EncodeToString(buffer)
|
||||||
|
return s[SESSION_ID_KEY]
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExpiration return a time.Time with the session's expiration date.
|
||||||
|
// If previous session has set to "session", remain it
|
||||||
|
func (s Session) getExpiration() time.Time {
|
||||||
|
if expireAfterDuration == 0 || s[TIMESTAMP_KEY] == "session" {
|
||||||
|
// Expire after closing browser
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
return time.Now().Add(expireAfterDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cookie returns an http.Cookie containing the signed session.
|
||||||
|
func (s Session) cookie() *http.Cookie {
|
||||||
|
var sessionValue string
|
||||||
|
ts := s.getExpiration()
|
||||||
|
s[TIMESTAMP_KEY] = getSessionExpirationCookie(ts)
|
||||||
|
for key, value := range s {
|
||||||
|
if strings.ContainsAny(key, ":\x00") {
|
||||||
|
panic("Session keys may not have colons or null bytes")
|
||||||
|
}
|
||||||
|
if strings.Contains(value, "\x00") {
|
||||||
|
panic("Session values may not have null bytes")
|
||||||
|
}
|
||||||
|
sessionValue += "\x00" + key + ":" + value + "\x00"
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionData := url.QueryEscape(sessionValue)
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: revel.CookiePrefix + "_SESSION",
|
||||||
|
Value: revel.Sign(sessionData) + "-" + sessionData,
|
||||||
|
Path: "/",
|
||||||
|
HttpOnly: revel.CookieHttpOnly,
|
||||||
|
Secure: revel.CookieSecure,
|
||||||
|
Expires: ts.UTC(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cookieDomain != "" {
|
||||||
|
cookie.Domain = cookieDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionTimeoutExpiredOrMissing returns a boolean of whether the session
|
||||||
|
// cookie is either not present or present but beyond its time to live; i.e.,
|
||||||
|
// whether there is not a valid session.
|
||||||
|
func sessionTimeoutExpiredOrMissing(session Session) bool {
|
||||||
|
if exp, present := session[TIMESTAMP_KEY]; !present {
|
||||||
|
return true
|
||||||
|
} else if exp == "session" {
|
||||||
|
return false
|
||||||
|
} else if expInt, _ := strconv.Atoi(exp); int64(expInt) < time.Now().Unix() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSessionFromCookie returns a Session struct pulled from the signed
|
||||||
|
// session cookie.
|
||||||
|
func getSessionFromCookie(cookie *http.Cookie) Session {
|
||||||
|
session := make(Session)
|
||||||
|
|
||||||
|
// Separate the data from the signature.
|
||||||
|
hyphen := strings.Index(cookie.Value, "-")
|
||||||
|
if hyphen == -1 || hyphen >= len(cookie.Value)-1 {
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
|
||||||
|
|
||||||
|
// Verify the signature.
|
||||||
|
if !revel.Verify(data, sig) {
|
||||||
|
revel.INFO.Println("Session cookie signature failed")
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
revel.ParseKeyValueCookie(data, func(key, val string) {
|
||||||
|
session[key] = val
|
||||||
|
})
|
||||||
|
|
||||||
|
if sessionTimeoutExpiredOrMissing(session) {
|
||||||
|
session = make(Session)
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionFilter is a Revel Filter that retrieves and sets the session cookie.
|
||||||
|
// Within Revel, it is available as a Session attribute on Controller instances.
|
||||||
|
// The name of the Session cookie is set as CookiePrefix + "_SESSION".
|
||||||
|
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
session := restoreSession(c.Request.Request)
|
||||||
|
// c.Session, 重新生成一个revel.Session给controller!!!
|
||||||
|
// Log("sessoin--------")
|
||||||
|
// LogJ(session)
|
||||||
|
|
||||||
|
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
||||||
|
c.Session = revelSession
|
||||||
|
// 生成sessionId
|
||||||
|
c.Session.Id()
|
||||||
|
sessionWasEmpty := len(c.Session) == 0
|
||||||
|
|
||||||
|
// Make session vars available in templates as {{.session.xyz}}
|
||||||
|
c.RenderArgs["session"] = c.Session
|
||||||
|
|
||||||
|
fc[0](c, fc[1:])
|
||||||
|
|
||||||
|
// Store the signed session if it could have changed.
|
||||||
|
if len(c.Session) > 0 || !sessionWasEmpty {
|
||||||
|
// 转换成lea.Session
|
||||||
|
session = Session(c.Session)
|
||||||
|
c.SetCookie(session.cookie())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreSession returns either the current session, retrieved from the
|
||||||
|
// session cookie, or a new session.
|
||||||
|
func restoreSession(req *http.Request) Session {
|
||||||
|
cookie, err := req.Cookie(revel.CookiePrefix + "_SESSION")
|
||||||
|
if err != nil {
|
||||||
|
return make(Session)
|
||||||
|
} else {
|
||||||
|
return getSessionFromCookie(cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSessionExpirationCookie retrieves the cookie's time to live as a
|
||||||
|
// string of either the number of seconds, for a persistent cookie, or
|
||||||
|
// "session".
|
||||||
|
func getSessionExpirationCookie(t time.Time) string {
|
||||||
|
if t.IsZero() {
|
||||||
|
return "session"
|
||||||
|
}
|
||||||
|
return strconv.FormatInt(t.Unix(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNoExpiration sets session to expire when browser session ends
|
||||||
|
func (s Session) SetNoExpiration() {
|
||||||
|
s[TIMESTAMP_KEY] = "session"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultExpiration sets session to expire after default duration
|
||||||
|
func (s Session) SetDefaultExpiration() {
|
||||||
|
delete(s, TIMESTAMP_KEY)
|
||||||
|
}
|
||||||
+20
-16
@@ -6,7 +6,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
// "time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -33,7 +32,7 @@ import (
|
|||||||
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
||||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
"js/object_id"}
|
||||||
|
|
||||||
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
||||||
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
||||||
@@ -92,6 +91,7 @@ func dev() {
|
|||||||
"notebook.js": "notebook-min.js",
|
"notebook.js": "notebook-min.js",
|
||||||
"share.js": "share-min.js",
|
"share.js": "share-min.js",
|
||||||
"tag.js": "tag-min.js",
|
"tag.js": "tag-min.js",
|
||||||
|
"main.js": "main-min.js",
|
||||||
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||||
"editor/editor.js": "editor/editor-min.js",
|
"editor/editor.js": "editor/editor-min.js",
|
||||||
@@ -107,13 +107,6 @@ func dev() {
|
|||||||
for key, value := range m {
|
for key, value := range m {
|
||||||
content = strings.Replace(content, key, value, -1)
|
content = strings.Replace(content, key, value, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// var time = time.Now().Unix() % 1000
|
|
||||||
|
|
||||||
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
|
|
||||||
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
|
|
||||||
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
|
|
||||||
|
|
||||||
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
|
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,10 +114,8 @@ func dev() {
|
|||||||
func tinymce() {
|
func tinymce() {
|
||||||
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
|
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
|
||||||
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
||||||
cmd := exec.Command("/bin/sh", "-c", "grunt minify");
|
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
|
||||||
cmd.Dir = base + "/tinymce_4.1.9"
|
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||||
|
|
||||||
fmt.Println("正在build tinymce");
|
|
||||||
|
|
||||||
// 必须要先删除
|
// 必须要先删除
|
||||||
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
|
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
|
||||||
@@ -132,19 +123,32 @@ func tinymce() {
|
|||||||
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
|
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
|
||||||
c, _ := cmd2.CombinedOutput()
|
c, _ := cmd2.CombinedOutput()
|
||||||
fmt.Println(string(c))
|
fmt.Println(string(c))
|
||||||
|
|
||||||
c, _ = cmd.CombinedOutput()
|
c, _ = cmd.CombinedOutput()
|
||||||
fmt.Println(string(c))
|
fmt.Println(string(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 压缩tinymce
|
// 压缩tinymce
|
||||||
// tinymce()
|
tinymce()
|
||||||
|
|
||||||
dev();
|
dev();
|
||||||
|
|
||||||
// 其它零散的需要压缩的js
|
// 其它零散的需要压缩的js
|
||||||
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
otherJss := []string{"tinymce/tinymce", "js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
||||||
|
"mdeditor/editor/scrollLink",
|
||||||
|
"mdeditor/editor/editor",
|
||||||
|
"mdeditor/editor/jquery.waitforimages",
|
||||||
|
"mdeditor/editor/pagedown/local/Markdown.local.zh",
|
||||||
|
"mdeditor/editor/pagedown/local/Markdown.local.en",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Editor",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Sanitizer",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Converter",
|
||||||
|
"mdeditor/editor/Markdown.Extra",
|
||||||
|
"mdeditor/editor/underscore",
|
||||||
|
"mdeditor/editor/mathJax",
|
||||||
|
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||||
|
"js/app/editor_drop_paste",
|
||||||
|
"js/app/attachment_upload",
|
||||||
"js/jquery.ztree.all-3.5",
|
"js/jquery.ztree.all-3.5",
|
||||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,29 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/db"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttachService struct {
|
type AttachService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add attach
|
// add attach
|
||||||
// api调用时, 添加attach之前是没有note的
|
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
|
||||||
// fromApi表示是api添加的, updateNote传过来的, 此时不要incNote's usn, 因为updateNote会inc的
|
|
||||||
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
|
|
||||||
attach.CreatedTime = time.Now()
|
attach.CreatedTime = time.Now()
|
||||||
ok = db.Insert(db.Attachs, attach)
|
ok = db.Insert(db.Attachs, attach)
|
||||||
|
|
||||||
note := noteService.GetNoteById(attach.NoteId.Hex())
|
|
||||||
|
|
||||||
// api调用时, 添加attach之前是没有note的
|
|
||||||
var userId string
|
|
||||||
if note.NoteId != "" {
|
|
||||||
userId = note.UserId.Hex()
|
|
||||||
} else {
|
|
||||||
userId = attach.UploadUserId.Hex()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
// 更新笔记的attachs num
|
// 更新笔记的attachs num
|
||||||
this.updateNoteAttachNum(attach.NoteId, 1)
|
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fromApi {
|
|
||||||
// 增长note's usn
|
|
||||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,45 +46,22 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
|
|||||||
// list attachs
|
// list attachs
|
||||||
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||||
attachs := []info.Attach{}
|
attachs := []info.Attach{}
|
||||||
|
|
||||||
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
||||||
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||||
return attachs
|
return attachs
|
||||||
}
|
}
|
||||||
|
|
||||||
// 笔记是否是自己的
|
|
||||||
note := noteService.GetNoteByIdAndUserId(noteId, userId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return attachs
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 这里, 优化权限控制
|
|
||||||
|
|
||||||
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
||||||
|
|
||||||
return attachs
|
return attachs
|
||||||
}
|
}
|
||||||
|
|
||||||
// api调用, 通过noteIds得到note's attachs, 通过noteId归类返回
|
|
||||||
func (this *AttachService) getAttachsByNoteIds(noteIds []bson.ObjectId) map[string][]info.Attach {
|
|
||||||
attachs := []info.Attach{}
|
|
||||||
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.M{"$in": noteIds}}, &attachs)
|
|
||||||
noteAttchs := make(map[string][]info.Attach)
|
|
||||||
for _, attach := range attachs {
|
|
||||||
noteId := attach.NoteId.Hex()
|
|
||||||
if itAttachs, ok := noteAttchs[noteId]; ok {
|
|
||||||
noteAttchs[noteId] = append(itAttachs, attach)
|
|
||||||
} else {
|
|
||||||
noteAttchs[noteId] = []info.Attach{attach}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noteAttchs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
||||||
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Delete note to delete attas firstly
|
// Delete note to delete attas firstly
|
||||||
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
@@ -134,11 +94,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
|||||||
attach.Path = strings.TrimLeft(attach.Path, "/")
|
attach.Path = strings.TrimLeft(attach.Path, "/")
|
||||||
err := os.Remove(revel.BasePath + "/" + attach.Path)
|
err := os.Remove(revel.BasePath + "/" + attach.Path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size)
|
return true, "delete file error"
|
||||||
// 修改note Usn
|
|
||||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
|
||||||
|
|
||||||
return true, "delete file success"
|
|
||||||
}
|
}
|
||||||
return false, "delete file error"
|
return false, "delete file error"
|
||||||
}
|
}
|
||||||
@@ -150,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
|||||||
// 获取文件路径
|
// 获取文件路径
|
||||||
// 要判断是否具有权限
|
// 要判断是否具有权限
|
||||||
// userId是否具有attach的访问权限
|
// userId是否具有attach的访问权限
|
||||||
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
|
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
|
||||||
if attachId == "" {
|
if attachId == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -181,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//userId为空则是分享笔记的附件
|
||||||
|
if userId == "" && sessionId != "" {
|
||||||
|
if token != "" {
|
||||||
|
realToken := sessionService.GetToken(sessionId)
|
||||||
|
if token == realToken {
|
||||||
|
Log("attach token is equal!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attach = info.Attach{}
|
attach = info.Attach{}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -213,35 +180,8 @@ func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
|
|||||||
attach.Name = newFilename
|
attach.Name = newFilename
|
||||||
attach.Path = filePath
|
attach.Path = filePath
|
||||||
|
|
||||||
this.AddAttach(attach, false)
|
this.AddAttach(attach)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只留下files的数据, 其它的都删除
|
|
||||||
func (this *AttachService) UpdateOrDeleteAttachApi(noteId, userId string, files []info.NoteFile) bool {
|
|
||||||
// 现在数据库内的
|
|
||||||
attachs := this.ListAttachs(noteId, userId)
|
|
||||||
|
|
||||||
nowAttachs := map[string]bool{}
|
|
||||||
if files != nil {
|
|
||||||
for _, file := range files {
|
|
||||||
if file.IsAttach && file.FileId != "" {
|
|
||||||
nowAttachs[file.FileId] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, attach := range attachs {
|
|
||||||
fileId := attach.AttachId.Hex()
|
|
||||||
if !nowAttachs[fileId] {
|
|
||||||
// 需要删除的
|
|
||||||
// TODO 权限验证去掉
|
|
||||||
this.DeleteAttach(fileId, userId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
}
|
|
||||||
+21
-31
@@ -5,28 +5,23 @@ import (
|
|||||||
// "github.com/leanote/leanote/app/db"
|
// "github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// "github.com/revel/revel"
|
// "github.com/revel/revel"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 登录与权限 Login & Register
|
// 登录与权限
|
||||||
|
|
||||||
type AuthService struct {
|
type AuthService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用bcrypt认证或者Md5认证
|
// pwd已md5了
|
||||||
// Use bcrypt (Md5 depreciated)
|
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||||
func (this *AuthService) Login(emailOrUsername, pwd string) (info.User, error) {
|
|
||||||
emailOrUsername = strings.Trim(emailOrUsername, " ")
|
emailOrUsername = strings.Trim(emailOrUsername, " ")
|
||||||
// pwd = strings.Trim(pwd, " ")
|
// pwd = strings.Trim(pwd, " ")
|
||||||
userInfo := userService.GetUserInfoByName(emailOrUsername)
|
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||||
if userInfo.UserId == "" || !ComparePwd(pwd, userInfo.Pwd) {
|
return userInfo
|
||||||
return userInfo, errors.New("wrong username or password")
|
|
||||||
}
|
|
||||||
return userInfo, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
@@ -45,21 +40,17 @@ func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string)
|
|||||||
if userService.IsExistsUser(email) {
|
if userService.IsExistsUser(email) {
|
||||||
return false, "userHasBeenRegistered-" + email
|
return false, "userHasBeenRegistered-" + email
|
||||||
}
|
}
|
||||||
passwd := GenPwd(pwd)
|
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||||
if passwd == "" {
|
|
||||||
return false, "GenerateHash error"
|
|
||||||
}
|
|
||||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: passwd}
|
|
||||||
if fromUserId != "" && IsObjectId(fromUserId) {
|
if fromUserId != "" && IsObjectId(fromUserId) {
|
||||||
user.FromUserId = bson.ObjectIdHex(fromUserId)
|
user.FromUserId = bson.ObjectIdHex(fromUserId)
|
||||||
}
|
}
|
||||||
|
LogJ(user)
|
||||||
return this.register(user)
|
return this.register(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *AuthService) register(user info.User) (bool, string) {
|
func (this *AuthService) register(user info.User) (bool, string) {
|
||||||
if userService.AddUser(user) {
|
if userService.AddUser(user) {
|
||||||
// 添加笔记本, 生活, 学习, 工作
|
// 添加笔记本, 生活, 学习, 工作
|
||||||
userId := user.UserId.Hex()
|
|
||||||
notebook := info.Notebook{
|
notebook := info.Notebook{
|
||||||
Seq: -1,
|
Seq: -1,
|
||||||
UserId: user.UserId}
|
UserId: user.UserId}
|
||||||
@@ -68,12 +59,14 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
notebook.Title = title
|
notebook.Title = title
|
||||||
notebook.NotebookId = objectId
|
notebook.NotebookId = objectId
|
||||||
notebook.UserId = user.UserId
|
notebook.UserId = user.UserId
|
||||||
notebookService.AddNotebook(notebook)
|
notebookService.AddNotebook(notebook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
email := user.Email
|
||||||
|
|
||||||
// 添加leanote -> 该用户的共享
|
// 添加leanote -> 该用户的共享
|
||||||
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
||||||
if registerSharedUserId != "" {
|
if(registerSharedUserId != "") {
|
||||||
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
|
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
|
||||||
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
|
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
|
||||||
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
|
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
|
||||||
@@ -81,23 +74,20 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
// 添加共享笔记本
|
// 添加共享笔记本
|
||||||
for _, notebook := range registerSharedNotebooks {
|
for _, notebook := range registerSharedNotebooks {
|
||||||
perm, _ := strconv.Atoi(notebook["perm"])
|
perm, _ := strconv.Atoi(notebook["perm"])
|
||||||
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId)
|
shareService.AddShareNotebook(notebook["notebookId"], perm, registerSharedUserId, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加共享笔记
|
// 添加共享笔记
|
||||||
for _, note := range registerSharedNotes {
|
for _, note := range registerSharedNotes {
|
||||||
perm, _ := strconv.Atoi(note["perm"])
|
perm, _ := strconv.Atoi(note["perm"])
|
||||||
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId)
|
shareService.AddShareNote(note["noteId"], perm, registerSharedUserId, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制笔记
|
// 复制笔记
|
||||||
for _, noteId := range registerCopyNoteIds {
|
for _, noteId := range registerCopyNoteIds {
|
||||||
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex())
|
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
||||||
// Log(noteId)
|
noteUpdate := bson.M{"IsBlog": true}
|
||||||
// Log("Copy")
|
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
||||||
// LogJ(note)
|
|
||||||
noteUpdate := bson.M{"IsBlog": false} // 不要是博客
|
|
||||||
noteService.UpdateNote(user.UserId.Hex(), note.NoteId.Hex(), noteUpdate, -1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +95,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
// 添加一条userBlog
|
// 添加一条userBlog
|
||||||
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
||||||
Title: user.Username + " 's Blog",
|
Title: user.Username + " 's Blog",
|
||||||
SubTitle: "Love Leanote!",
|
SubTitle: "love leanote!",
|
||||||
AboutMe: "Hello, I am (^_^)",
|
AboutMe: "Hello, I am (^_^)",
|
||||||
CanComment: true,
|
CanComment: true,
|
||||||
})
|
})
|
||||||
@@ -123,7 +113,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
|
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
|
||||||
username = thirdType + "-" + thirdUsername
|
username = thirdType + "-" + thirdUsername
|
||||||
i := 1
|
i := 1
|
||||||
for {
|
for ;; {
|
||||||
if !userService.IsExistsUserByUsername(username) {
|
if !userService.IsExistsUserByUsername(username) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,7 @@ func (this *BlogService) GetBlogByIdAndUrlTitle(userId string, noteIdOrUrlTitle
|
|||||||
return this.GetBlog(noteIdOrUrlTitle)
|
return this.GetBlog(noteIdOrUrlTitle)
|
||||||
}
|
}
|
||||||
note := info.Note{}
|
note := info.Note{}
|
||||||
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle),
|
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle), "IsBlog": true, "IsTrash": false}, ¬e)
|
||||||
"IsBlog": true,
|
|
||||||
"IsTrash": false, "IsDeleted": false}, ¬e)
|
|
||||||
return this.GetBlogItem(note)
|
return this.GetBlogItem(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +56,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
|||||||
}
|
}
|
||||||
func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
||||||
if note.NoteId == "" || !note.IsBlog {
|
if note.NoteId == "" || !note.IsBlog {
|
||||||
return info.BlogItem{}
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
@@ -71,14 +69,9 @@ func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户共享的notebooks
|
// 得到用户共享的notebooks
|
||||||
// 3/19 博客不是deleted
|
|
||||||
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
||||||
notebooks := []info.Notebook{}
|
notebooks := []info.Notebook{}
|
||||||
orQ := []bson.M{
|
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}, ¬ebooks)
|
||||||
bson.M{"IsDeleted": false},
|
|
||||||
bson.M{"IsDeleted": bson.M{"$exists": false}},
|
|
||||||
}
|
|
||||||
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "$or": orQ}, ¬ebooks)
|
|
||||||
return notebooks
|
return notebooks
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +126,7 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
|||||||
func (this *BlogService) GetBlogTags(userId string) []info.TagCount {
|
func (this *BlogService) GetBlogTags(userId string) []info.TagCount {
|
||||||
// 得到所有博客
|
// 得到所有博客
|
||||||
tagCounts := []info.TagCount{}
|
tagCounts := []info.TagCount{}
|
||||||
// tag不能为空
|
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "Tag": bson.M{"$ne": ""}}
|
|
||||||
db.TagCounts.Find(query).Sort("-Count").All(&tagCounts)
|
db.TagCounts.Find(query).Sort("-Count").All(&tagCounts)
|
||||||
return tagCounts
|
return tagCounts
|
||||||
}
|
}
|
||||||
@@ -145,7 +137,7 @@ func (this *BlogService) ReCountBlogTags(userId string) bool {
|
|||||||
// 得到所有博客
|
// 得到所有博客
|
||||||
notes := []info.Note{}
|
notes := []info.Note{}
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsDeleted": false, "IsBlog": true}
|
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true}
|
||||||
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es)
|
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es)
|
||||||
|
|
||||||
db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true})
|
db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true})
|
||||||
@@ -187,7 +179,7 @@ Posts: []
|
|||||||
*/
|
*/
|
||||||
func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) []info.Archive {
|
func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) []info.Archive {
|
||||||
// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true);
|
// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true);
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false, "IsDeleted": false}
|
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false}
|
||||||
if notebookId != "" {
|
if notebookId != "" {
|
||||||
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||||
}
|
}
|
||||||
@@ -295,7 +287,6 @@ func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumb
|
|||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"IsDeleted": false,
|
|
||||||
"IsBlog": true,
|
"IsBlog": true,
|
||||||
"Tags": bson.M{"$all": tags}}
|
"Tags": bson.M{"$all": tags}}
|
||||||
|
|
||||||
@@ -397,12 +388,10 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
|
|||||||
sortFieldR2 = sorterField
|
sortFieldR2 = sorterField
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1
|
|
||||||
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
|
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
|
||||||
note := info.Note{}
|
note := info.Note{}
|
||||||
query := bson.M{"UserId": userIdO,
|
query := bson.M{"UserId": userIdO,
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"IsDeleted": false,
|
|
||||||
"IsBlog": true,
|
"IsBlog": true,
|
||||||
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
|
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
|
||||||
sorterField: sortFieldT1,
|
sorterField: sortFieldT1,
|
||||||
@@ -436,7 +425,7 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
|
|||||||
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
|
||||||
|
|
||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"IsTrash": false, "IsDeleted": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
|
query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
query["Tags"] = bson.M{"$in": []string{tag}}
|
query["Tags"] = bson.M{"$in": []string{tag}}
|
||||||
}
|
}
|
||||||
@@ -502,9 +491,6 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
|
|||||||
content = noteContent.Abstract
|
content = noteContent.Abstract
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if len(note.Tags) == 1 && note.Tags[0] == "" {
|
|
||||||
note.Tags = nil
|
|
||||||
}
|
|
||||||
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
|
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
|
||||||
}
|
}
|
||||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||||
@@ -1108,7 +1094,6 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool
|
|||||||
|
|
||||||
// 得到用户的博客url
|
// 得到用户的博客url
|
||||||
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
||||||
if userBlog != nil {
|
|
||||||
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||||
return configService.GetUserUrl(userBlog.Domain)
|
return configService.GetUserUrl(userBlog.Domain)
|
||||||
} else if userBlog.SubDomain != "" {
|
} else if userBlog.SubDomain != "" {
|
||||||
@@ -1117,7 +1102,6 @@ func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string
|
|||||||
if username == "" {
|
if username == "" {
|
||||||
username = userBlog.UserId.Hex()
|
username = userBlog.UserId.Hex()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return configService.GetBlogUrl() + "/" + username
|
return configService.GetBlogUrl() + "/" + username
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,10 +1190,6 @@ func (this *BlogService) FixBlog(blog info.BlogItem) info.Post {
|
|||||||
LikeNum: blog.LikeNum,
|
LikeNum: blog.LikeNum,
|
||||||
IsMarkdown: blog.IsMarkdown,
|
IsMarkdown: blog.IsMarkdown,
|
||||||
}
|
}
|
||||||
if blog2.Tags != nil && len(blog2.Tags) > 0 && blog2.Tags[0] != "" {
|
|
||||||
} else {
|
|
||||||
blog2.Tags = nil
|
|
||||||
}
|
|
||||||
return blog2
|
return blog2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
|
|||||||
username, _ := revel.Config.String("db.username")
|
username, _ := revel.Config.String("db.username")
|
||||||
password, _ := revel.Config.String("db.password")
|
password, _ := revel.Config.String("db.password")
|
||||||
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
binPath = binPath + " -h " + host + " -d " + dbname + " --port " + port
|
binPath = binPath + " -h " + host + " -d " + dbname + " -port " + port
|
||||||
if username != "" {
|
if username != "" {
|
||||||
binPath += " -u " + username + " -p " + password
|
binPath += " -u " + username + " -p " + password
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
|||||||
username, _ := revel.Config.String("db.username")
|
username, _ := revel.Config.String("db.username")
|
||||||
password, _ := revel.Config.String("db.password")
|
password, _ := revel.Config.String("db.password")
|
||||||
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
binPath = binPath + " --drop -h " + host + " -d " + dbname + " --port " + port
|
binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
|
||||||
if username != "" {
|
if username != "" {
|
||||||
binPath += " -u " + username + " -p " + password
|
binPath += " -u " + username + " -p " + password
|
||||||
}
|
}
|
||||||
@@ -372,7 +372,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
|||||||
return false, path + " Is Not Exists"
|
return false, path + " Is Not Exists"
|
||||||
}
|
}
|
||||||
|
|
||||||
binPath += " " + path
|
binPath += " --directoryperdb " + path
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", binPath)
|
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||||
Log(binPath);
|
Log(binPath);
|
||||||
@@ -455,15 +455,12 @@ var port string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
/*
|
|
||||||
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
|
|
||||||
port = strconv.Itoa(revel.HttpPort)
|
port = strconv.Itoa(revel.HttpPort)
|
||||||
if port != "80" {
|
if port != "80" {
|
||||||
port = ":" + port
|
port = ":" + port
|
||||||
} else {
|
} else {
|
||||||
port = "";
|
port = "";
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
||||||
if strings.HasPrefix(siteUrl, "http://") {
|
if strings.HasPrefix(siteUrl, "http://") {
|
||||||
@@ -472,17 +469,6 @@ func init() {
|
|||||||
defaultDomain = siteUrl[len("https://"):]
|
defaultDomain = siteUrl[len("https://"):]
|
||||||
schema = "https://"
|
schema = "https://"
|
||||||
}
|
}
|
||||||
|
|
||||||
// port localhost:9000
|
|
||||||
ports := strings.Split(defaultDomain, ":")
|
|
||||||
if len(ports) == 2 {
|
|
||||||
port = ports[1]
|
|
||||||
}
|
|
||||||
if port == "80" {
|
|
||||||
port = ""
|
|
||||||
} else {
|
|
||||||
port = ":" + port
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,5 +580,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ConfigService) GetVersion() string {
|
func (this *ConfigService) GetVersion() string {
|
||||||
return "1.3.1"
|
return "1.0-beta2"
|
||||||
}
|
}
|
||||||
+28
-61
@@ -1,18 +1,15 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"github.com/leanote/leanote/app/db"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"io/ioutil"
|
"time"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
// "fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||||
@@ -119,57 +116,11 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
|||||||
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *FileService) GetFileBase64(userId, fileId string) (str string, mine string) {
|
|
||||||
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
fmt.Println(err) // 这里的err其实就是panic传入的内容,55
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
path := this.GetFile(userId, fileId)
|
|
||||||
|
|
||||||
if path == "" {
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
|
|
||||||
path = revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
|
||||||
|
|
||||||
ff, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
|
|
||||||
e64 := base64.StdEncoding
|
|
||||||
maxEncLen := e64.EncodedLen(len(ff))
|
|
||||||
encBuf := make([]byte, maxEncLen)
|
|
||||||
|
|
||||||
e64.Encode(encBuf, ff)
|
|
||||||
|
|
||||||
mime := http.DetectContentType(ff)
|
|
||||||
|
|
||||||
str = string(encBuf)
|
|
||||||
return str, mime
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到图片base64, 图片要在之前添加data:image/png;base64,
|
|
||||||
func (this *FileService) GetImageBase64(userId, fileId string) string {
|
|
||||||
|
|
||||||
str, mime := this.GetFileBase64(userId, fileId)
|
|
||||||
if str == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
switch mime {
|
|
||||||
case "image/gif", "image/jpeg", "image/pjpeg", "image/png", "image/tiff":
|
|
||||||
return fmt.Sprintf("data:%s;base64,%s", mime, str)
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return "data:image/png;base64," + str
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取文件路径
|
// 获取文件路径
|
||||||
// 要判断是否具有权限
|
// 要判断是否具有权限
|
||||||
// userId是否具有fileId的访问权限
|
// userId是否具有fileId的访问权限
|
||||||
func (this *FileService) GetFile(userId, fileId string) string {
|
|
||||||
|
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
|
||||||
if fileId == "" {
|
if fileId == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -182,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. 判断权限
|
// 1. 判断权限
|
||||||
|
//未登录用户,判断token
|
||||||
|
noteIds := noteImageService.GetNoteIds(fileId)
|
||||||
// 是否是我的文件
|
// 是否是我的文件
|
||||||
if userId != "" && file.UserId.Hex() == userId {
|
if userId != "" && file.UserId.Hex() == userId {
|
||||||
return path
|
return path
|
||||||
@@ -192,13 +144,30 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
// 这些笔记是否有public的, 若有则ok
|
// 这些笔记是否有public的, 若有则ok
|
||||||
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||||
|
|
||||||
noteIds := noteImageService.GetNoteIds(fileId)
|
|
||||||
if noteIds != nil && len(noteIds) > 0 {
|
if noteIds != nil && len(noteIds) > 0 {
|
||||||
// 这些笔记是否有public的
|
// 这些笔记是否有public的
|
||||||
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//分享给未注册用户
|
||||||
|
if userId == "" && sessionId != "" {
|
||||||
|
if token != "" {
|
||||||
|
realToken := sessionService.GetToken(sessionId)
|
||||||
|
if token == realToken {
|
||||||
|
Log("image token is equal!")
|
||||||
|
return path
|
||||||
|
} else {
|
||||||
|
Log("image token is different!")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
note := noteService.GetNoteById(noteId.Hex())
|
note := noteService.GetNoteById(noteId.Hex())
|
||||||
@@ -206,6 +175,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// 若有共享给我的笔记?
|
// 若有共享给我的笔记?
|
||||||
// 对该笔记可读?
|
// 对该笔记可读?
|
||||||
@@ -242,6 +212,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 复制图片
|
// 复制图片
|
||||||
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
||||||
// 是否已经复制过了
|
// 是否已经复制过了
|
||||||
@@ -294,9 +265,5 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
|
|||||||
|
|
||||||
// 是否是我的文件
|
// 是否是我的文件
|
||||||
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
||||||
// 如果有问题会panic
|
|
||||||
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
||||||
}
|
}
|
||||||
@@ -32,21 +32,11 @@ func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg stri
|
|||||||
return false, "groupHasUsers"
|
return false, "groupHasUsers"
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if !this.isMyGroup(userId, groupId) {
|
|
||||||
return false, "notMyGroup"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除分组后, 需要删除所有用户分享到该组的笔记本, 笔记
|
|
||||||
|
|
||||||
shareService.DeleteAllShareNotebookGroup(groupId);
|
|
||||||
shareService.DeleteAllShareNoteGroup(groupId);
|
|
||||||
|
|
||||||
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
|
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
|
||||||
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
||||||
|
|
||||||
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改group标题
|
// 修改group标题
|
||||||
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
||||||
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
||||||
@@ -54,14 +44,9 @@ func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bo
|
|||||||
|
|
||||||
// 得到用户的所有分组(包括下的所有用户)
|
// 得到用户的所有分组(包括下的所有用户)
|
||||||
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||||
/*
|
// 得到分组s
|
||||||
// 得到我的分组
|
|
||||||
groups := []info.Group{}
|
groups := []info.Group{}
|
||||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
*/
|
|
||||||
// 我的分组, 及我所属的分组
|
|
||||||
groups := this.GetGroupsContainOf(userId);
|
|
||||||
|
|
||||||
// 得到其下的用户
|
// 得到其下的用户
|
||||||
for i, group := range groups {
|
for i, group := range groups {
|
||||||
group.Users = this.GetUsers(group.GroupId.Hex())
|
group.Users = this.GetUsers(group.GroupId.Hex())
|
||||||
@@ -76,55 +61,6 @@ func (this *GroupService) GetGroups(userId string) ([]info.Group) {
|
|||||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
return groups
|
return groups
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到我的和我所属组的ids
|
|
||||||
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
|
||||||
// 所属组
|
|
||||||
groupIds := this.GetBelongToGroupIds(userId)
|
|
||||||
|
|
||||||
m := map[bson.ObjectId]bool{}
|
|
||||||
for _, groupId := range groupIds {
|
|
||||||
m[groupId] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 我的组
|
|
||||||
myGroups := this.GetGroups(userId)
|
|
||||||
|
|
||||||
for _, group := range myGroups {
|
|
||||||
if !m[group.GroupId] {
|
|
||||||
groupIds = append(groupIds, group.GroupId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupIds
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取包含此用户的组对象数组
|
|
||||||
// 获取该用户所属组, 和我的组
|
|
||||||
func (this *GroupService) GetGroupsContainOf(userId string) []info.Group {
|
|
||||||
// 我的组
|
|
||||||
myGroups := this.GetGroups(userId)
|
|
||||||
myGroupMap := map[bson.ObjectId]bool{}
|
|
||||||
|
|
||||||
for _, group := range myGroups {
|
|
||||||
myGroupMap[group.GroupId] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所属组
|
|
||||||
groupIds := this.GetBelongToGroupIds(userId)
|
|
||||||
|
|
||||||
groups := []info.Group{}
|
|
||||||
db.ListByQ(db.Groups, bson.M{"_id": bson.M{"$in": groupIds}}, &groups)
|
|
||||||
|
|
||||||
for _, group := range groups {
|
|
||||||
if !myGroupMap[group.GroupId] {
|
|
||||||
myGroups = append(myGroups, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return myGroups
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到分组, shareService用
|
// 得到分组, shareService用
|
||||||
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||||
// 得到分组s
|
// 得到分组s
|
||||||
@@ -167,25 +103,10 @@ func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
|||||||
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
||||||
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断组中是否包含指定用户
|
|
||||||
func (this *GroupService) IsExistsGroupUser(userId, groupId string) (ok bool) {
|
|
||||||
// 如果我拥有这个组, 那也行
|
|
||||||
if this.isMyGroup(userId, groupId) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return db.Has(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId), "GroupId": bson.ObjectIdHex(groupId)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为group添加用户
|
// 为group添加用户
|
||||||
// 用户是否已存在?
|
// 用户是否已存在?
|
||||||
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
// groupId是否是ownUserId的?
|
// groupId是否是ownUserId的?
|
||||||
/*
|
|
||||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
|
||||||
return false, "forbidden"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if !this.isMyGroup(ownUserId, groupId) {
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
return false, "forbidden"
|
return false, "forbidden"
|
||||||
}
|
}
|
||||||
@@ -202,22 +123,11 @@ func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, m
|
|||||||
CreatedTime: time.Now(),
|
CreatedTime: time.Now(),
|
||||||
}), ""
|
}), ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除用户
|
// 删除用户
|
||||||
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
// groupId是否是ownUserId的?
|
// groupId是否是ownUserId的?
|
||||||
/*
|
|
||||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
|
||||||
return false, "forbidden"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if !this.isMyGroup(ownUserId, groupId) {
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
return false, "forbidden"
|
return false, "forbidden"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除该用户分享到本组的笔记本, 笔记
|
|
||||||
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId);
|
|
||||||
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId);
|
|
||||||
|
|
||||||
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,6 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 这个web可以用, 但api会传来, 不用用了
|
|
||||||
// 解析内容中的图片, 建立图片与note的关系
|
// 解析内容中的图片, 建立图片与note的关系
|
||||||
// <img src="/file/outputImage?fileId=12323232" />
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
// 图片必须是我的, 不然不添加
|
// 图片必须是我的, 不然不添加
|
||||||
@@ -39,8 +38,7 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
|||||||
if imgSrc != "" {
|
if imgSrc != "" {
|
||||||
content = "<img src=\"" + imgSrc + "\" >" + content
|
content = "<img src=\"" + imgSrc + "\" >" + content
|
||||||
}
|
}
|
||||||
// life 添加getImage
|
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||||
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
|
|
||||||
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
||||||
|
|
||||||
// 删除旧的
|
// 删除旧的
|
||||||
@@ -52,8 +50,8 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
|||||||
hasAdded := make(map[string]bool)
|
hasAdded := make(map[string]bool)
|
||||||
if find != nil && len(find) > 0 {
|
if find != nil && len(find) > 0 {
|
||||||
for _, each := range find {
|
for _, each := range find {
|
||||||
if each != nil && len(each) == 3 {
|
if each != nil && len(each) == 2 {
|
||||||
fileId = each[2] // 现在有两个子表达式了
|
fileId = each[1]
|
||||||
// 之前没能添加过的
|
// 之前没能添加过的
|
||||||
if _, ok := hasAdded[fileId]; !ok {
|
if _, ok := hasAdded[fileId]; !ok {
|
||||||
Log(fileId)
|
Log(fileId)
|
||||||
@@ -73,13 +71,17 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
|||||||
|
|
||||||
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
|
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
|
||||||
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
|
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
|
||||||
/* 弃用之
|
|
||||||
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
|
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
|
||||||
noteImages := []info.NoteImage{}
|
noteImages := []info.NoteImage{}
|
||||||
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, ¬eImages)
|
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, ¬eImages)
|
||||||
|
|
||||||
if len(noteImages) == 0 {
|
if len(noteImages) == 0 {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
|
// 把fileId=1232替换成新的
|
||||||
|
replaceMap := map[string]string{}
|
||||||
for _, noteImage := range noteImages {
|
for _, noteImage := range noteImages {
|
||||||
imageId := noteImage.ImageId.Hex()
|
imageId := noteImage.ImageId.Hex()
|
||||||
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
|
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
|
||||||
@@ -87,88 +89,19 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
|
|||||||
replaceMap[imageId] = newImageId
|
replaceMap[imageId] = newImageId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// 因为很多图片上传就会删除, 所以直接从内容中查看图片id进行复制
|
if len(replaceMap) > 0 {
|
||||||
|
// 替换之
|
||||||
// <img src="/file/outputImage?fileId=12323232" />
|
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||||
// 把fileId=1232替换成新的
|
|
||||||
replaceMap := map[string]string{}
|
|
||||||
|
|
||||||
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
|
|
||||||
content = reg.ReplaceAllStringFunc(content, func(each string) string {
|
content = reg.ReplaceAllStringFunc(content, func(each string) string {
|
||||||
// each=outputImage?fileId=541bd2f599c37b4f3r000003
|
// each=outputImage?fileId=541bd2f599c37b4f3r000003
|
||||||
// each = getImage?fileId=541bd2f599c37b4f3r000003
|
|
||||||
|
|
||||||
fileId := each[len(each)-24:] // 得到后24位, 也即id
|
fileId := each[len(each)-24:] // 得到后24位, 也即id
|
||||||
|
if replaceFileId, ok := replaceMap[fileId]; ok {
|
||||||
if _, ok := replaceMap[fileId]; !ok {
|
|
||||||
if bson.IsObjectIdHex(fileId) {
|
|
||||||
ok2, newImageId := fileService.CopyImage(fromUserId, fileId, toUserId)
|
|
||||||
if ok2 {
|
|
||||||
replaceMap[fileId] = newImageId
|
|
||||||
} else {
|
|
||||||
replaceMap[fileId] = ""
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
replaceMap[fileId] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceFileId := replaceMap[fileId]
|
|
||||||
if replaceFileId != "" {
|
|
||||||
if each[0] == 'o' {
|
|
||||||
return "outputImage?fileId=" + replaceFileId
|
return "outputImage?fileId=" + replaceFileId
|
||||||
}
|
}
|
||||||
return "getImage?fileId=" + replaceFileId
|
|
||||||
}
|
|
||||||
return each
|
return each
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[string][]info.File {
|
|
||||||
noteNoteImages := []info.NoteImage{}
|
|
||||||
db.ListByQ(db.NoteImages, bson.M{"NoteId": bson.M{"$in": noteIds}}, ¬eNoteImages)
|
|
||||||
|
|
||||||
// 得到imageId, 再去files表查所有的Files
|
|
||||||
imageIds := []bson.ObjectId{}
|
|
||||||
|
|
||||||
// 图片1 => N notes
|
|
||||||
imageIdNotes := map[string][]string{} // imageId => [noteId1, noteId2, ...]
|
|
||||||
for _, noteImage := range noteNoteImages {
|
|
||||||
imageId := noteImage.ImageId
|
|
||||||
imageIds = append(imageIds, imageId)
|
|
||||||
|
|
||||||
imageIdHex := imageId.Hex()
|
|
||||||
noteId := noteImage.NoteId.Hex()
|
|
||||||
if notes, ok := imageIdNotes[imageIdHex]; ok {
|
|
||||||
imageIdNotes[imageIdHex] = append(notes, noteId)
|
|
||||||
} else {
|
|
||||||
imageIdNotes[imageIdHex] = []string{noteId}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到所有files
|
|
||||||
files := []info.File{}
|
|
||||||
db.ListByQ(db.Files, bson.M{"_id": bson.M{"$in": imageIds}}, &files)
|
|
||||||
|
|
||||||
// 建立note->file关联
|
|
||||||
noteImages := make(map[string][]info.File)
|
|
||||||
for _, file := range files {
|
|
||||||
fileIdHex := file.FileId.Hex() // == imageId
|
|
||||||
// 这个fileIdHex有哪些notes呢?
|
|
||||||
if notes, ok := imageIdNotes[fileIdHex]; ok {
|
|
||||||
for _, noteId := range notes {
|
|
||||||
if files, ok2 := noteImages[noteId]; ok2 {
|
|
||||||
noteImages[noteId] = append(files, file)
|
|
||||||
} else {
|
|
||||||
noteImages[noteId] = []info.File{file}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noteImages
|
|
||||||
}
|
|
||||||
+42
-337
@@ -17,30 +17,28 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
|||||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//通过附件id得到note
|
||||||
|
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
|
||||||
|
attach := info.Attach{}
|
||||||
|
db.Get(db.Attachs, attachId, &attach)
|
||||||
|
note = info.Note{}
|
||||||
|
noteId := attach.NoteId
|
||||||
|
db.Get(db.Notes, noteId.Hex(), ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// fileService调用
|
// fileService调用
|
||||||
// 不能是已经删除了的, life bug, 客户端删除后, 竟然还能在web上打开
|
|
||||||
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||||
note = info.Note{}
|
note = info.Note{}
|
||||||
if noteId == "" {
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
return
|
|
||||||
}
|
|
||||||
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsDeleted": false}, ¬e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (this *NoteService) GetNoteByIdAndUserId(noteId, userId string) (note info.Note) {
|
|
||||||
note = info.Note{}
|
|
||||||
if noteId == "" || userId == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "IsDeleted": false}, ¬e)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 得到blog, blogService用
|
// 得到blog, blogService用
|
||||||
// 不要传userId, 因为是公开的
|
// 不要传userId, 因为是公开的
|
||||||
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
||||||
note = info.Note{}
|
note = info.Note{}
|
||||||
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId),
|
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsBlog": true, "IsTrash": false}, ¬e)
|
||||||
"IsBlog": true, "IsTrash": false, "IsDeleted": false}, ¬e)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 通过id, userId得到noteContent
|
// 通过id, userId得到noteContent
|
||||||
@@ -57,115 +55,14 @@ func (this *NoteService) GetNoteAndContent(noteId, userId string) (noteAndConten
|
|||||||
return info.NoteAndContent{note, noteContent}
|
return info.NoteAndContent{note, noteContent}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取同步的笔记
|
|
||||||
// > afterUsn的笔记
|
|
||||||
func (this *NoteService) GetSyncNotes(userId string, afterUsn, maxEntry int) []info.ApiNote {
|
|
||||||
notes := []info.Note{}
|
|
||||||
q := db.Notes.Find(bson.M{
|
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"Usn": bson.M{"$gt": afterUsn},
|
|
||||||
});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬es)
|
|
||||||
|
|
||||||
return this.ToApiNotes(notes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// note与apiNote的转换
|
|
||||||
func (this *NoteService) ToApiNotes(notes []info.Note) []info.ApiNote {
|
|
||||||
// 2, 得到所有图片, 附件信息
|
|
||||||
// 查images表, attachs表
|
|
||||||
if len(notes) > 0 {
|
|
||||||
noteIds := make([]bson.ObjectId, len(notes));
|
|
||||||
for i, note := range notes {
|
|
||||||
noteIds[i] = note.NoteId
|
|
||||||
}
|
|
||||||
noteFilesMap := this.getFiles(noteIds)
|
|
||||||
// 生成info.ApiNote
|
|
||||||
apiNotes := make([]info.ApiNote, len(notes))
|
|
||||||
for i, note := range notes {
|
|
||||||
noteId := note.NoteId.Hex()
|
|
||||||
apiNotes[i] = this.ToApiNote(¬e, noteFilesMap[noteId])
|
|
||||||
}
|
|
||||||
return apiNotes
|
|
||||||
}
|
|
||||||
// 返回空的
|
|
||||||
return []info.ApiNote{}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// note与apiNote的转换
|
|
||||||
func (this *NoteService) ToApiNote(note *info.Note, files []info.NoteFile) info.ApiNote {
|
|
||||||
apiNote := info.ApiNote{
|
|
||||||
NoteId: note.NoteId.Hex(),
|
|
||||||
NotebookId: note.NotebookId.Hex(),
|
|
||||||
UserId : note.UserId.Hex(),
|
|
||||||
Title : note.Title,
|
|
||||||
Tags : note.Tags,
|
|
||||||
IsMarkdown : note.IsMarkdown,
|
|
||||||
IsBlog : note.IsBlog,
|
|
||||||
IsTrash : note.IsTrash,
|
|
||||||
IsDeleted : note.IsDeleted,
|
|
||||||
Usn : note.Usn,
|
|
||||||
CreatedTime : note.CreatedTime,
|
|
||||||
UpdatedTime : note.UpdatedTime,
|
|
||||||
PublicTime : note.PublicTime,
|
|
||||||
Files: files,
|
|
||||||
}
|
|
||||||
return apiNote
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDirtyNotes, 把note的图片, 附件信息都发送给客户端
|
|
||||||
// 客户端保存到本地, 再获取图片, 附件
|
|
||||||
|
|
||||||
// 得到所有图片, 附件信息
|
|
||||||
// 查images表, attachs表
|
|
||||||
// [待测]
|
|
||||||
func (this *NoteService) getFiles(noteIds []bson.ObjectId) map[string][]info.NoteFile {
|
|
||||||
noteImages := noteImageService.getImagesByNoteIds(noteIds);
|
|
||||||
noteAttachs := attachService.getAttachsByNoteIds(noteIds)
|
|
||||||
|
|
||||||
noteFilesMap := map[string][]info.NoteFile{}
|
|
||||||
|
|
||||||
for _, noteId := range noteIds {
|
|
||||||
noteIdHex := noteId.Hex()
|
|
||||||
noteFiles := []info.NoteFile{}
|
|
||||||
// images
|
|
||||||
if images, ok := noteImages[noteIdHex]; ok {
|
|
||||||
for _, image := range images {
|
|
||||||
noteFiles = append(noteFiles, info.NoteFile{
|
|
||||||
FileId: image.FileId.Hex(),
|
|
||||||
Type: image.Type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach
|
|
||||||
if attachs, ok := noteAttachs[noteIdHex]; ok {
|
|
||||||
for _, attach := range attachs {
|
|
||||||
noteFiles = append(noteFiles, info.NoteFile{
|
|
||||||
FileId: attach.AttachId.Hex(),
|
|
||||||
Type: attach.Type,
|
|
||||||
Title: attach.Title,
|
|
||||||
IsAttach: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noteFilesMap[noteIdHex] = noteFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
return noteFilesMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列出note, 排序规则, 还有分页
|
// 列出note, 排序规则, 还有分页
|
||||||
// CreatedTime, UpdatedTime, title 来排序
|
// CreatedTime, UpdatedTime, title 来排序
|
||||||
func (this *NoteService) ListNotes(userId, notebookId string,
|
func (this *NoteService) ListNotes(userId, notebookId string,
|
||||||
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
|
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
|
||||||
notes = []info.Note{}
|
notes = []info.Note{}
|
||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash, "IsDeleted": false}
|
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
query["IsBlog"] = true
|
query["IsBlog"] = true
|
||||||
}
|
}
|
||||||
@@ -235,7 +132,7 @@ func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (note
|
|||||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||||
// [ok]
|
// [ok]
|
||||||
|
|
||||||
func (this *NoteService) AddNote(note info.Note, fromApi bool) info.Note {
|
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId();
|
noteId := bson.NewObjectId();
|
||||||
note.NoteId = noteId;
|
note.NoteId = noteId;
|
||||||
@@ -245,18 +142,14 @@ func (this *NoteService) AddNote(note info.Note, fromApi bool) info.Note {
|
|||||||
note.IsTrash = false
|
note.IsTrash = false
|
||||||
note.UpdatedUserId = note.UserId
|
note.UpdatedUserId = note.UserId
|
||||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||||
note.Usn = userService.IncrUsn(note.UserId.Hex())
|
|
||||||
|
|
||||||
notebookId := note.NotebookId.Hex()
|
|
||||||
|
|
||||||
// api会传IsBlog, web不会传
|
|
||||||
if !fromApi {
|
|
||||||
// 设为blog
|
// 设为blog
|
||||||
|
notebookId := note.NotebookId.Hex()
|
||||||
note.IsBlog = notebookService.IsBlog(notebookId)
|
note.IsBlog = notebookService.IsBlog(notebookId)
|
||||||
}
|
|
||||||
// if note.IsBlog {
|
if note.IsBlog {
|
||||||
note.PublicTime = note.UpdatedTime
|
note.PublicTime = note.UpdatedTime
|
||||||
// }
|
}
|
||||||
|
|
||||||
db.Insert(db.Notes, note)
|
db.Insert(db.Notes, note)
|
||||||
|
|
||||||
@@ -274,7 +167,7 @@ func (this *NoteService) AddSharedNote(note info.Note, myUserId bson.ObjectId) i
|
|||||||
// 判断我是否有权限添加
|
// 判断我是否有权限添加
|
||||||
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
|
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
|
||||||
note.CreatedUserId = myUserId // 是我给共享我的人创建的
|
note.CreatedUserId = myUserId // 是我给共享我的人创建的
|
||||||
return this.AddNote(note, false)
|
return this.AddNote(note)
|
||||||
}
|
}
|
||||||
return info.Note{}
|
return info.Note{}
|
||||||
}
|
}
|
||||||
@@ -294,49 +187,6 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
|||||||
return noteContent;
|
return noteContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// API, abstract, desc需要这里获取
|
|
||||||
// 不需要
|
|
||||||
/*
|
|
||||||
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
|
||||||
if(note.NoteId.Hex() == "") {
|
|
||||||
noteId := bson.NewObjectId();
|
|
||||||
note.NoteId = noteId;
|
|
||||||
}
|
|
||||||
note.CreatedTime = time.Now()
|
|
||||||
note.UpdatedTime = note.CreatedTime
|
|
||||||
note.IsTrash = false
|
|
||||||
note.UpdatedUserId = note.UserId
|
|
||||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
|
||||||
note.Usn = userService.IncrUsn(note.UserId.Hex())
|
|
||||||
|
|
||||||
// desc这里获取
|
|
||||||
desc := SubStringHTMLToRaw(noteContent.Content, 50)
|
|
||||||
note.Desc = desc;
|
|
||||||
|
|
||||||
// 设为blog
|
|
||||||
notebookId := note.NotebookId.Hex()
|
|
||||||
note.IsBlog = notebookService.IsBlog(notebookId)
|
|
||||||
|
|
||||||
if note.IsBlog {
|
|
||||||
note.PublicTime = note.UpdatedTime
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Insert(db.Notes, note)
|
|
||||||
|
|
||||||
// tag1, 不需要了
|
|
||||||
// tagService.AddTags(note.UserId.Hex(), note.Tags)
|
|
||||||
|
|
||||||
// recount notebooks' notes number
|
|
||||||
notebookService.ReCountNotebookNumberNotes(notebookId)
|
|
||||||
|
|
||||||
// 这里, 添加到内容中
|
|
||||||
abstract := SubStringHTML(noteContent.Content, 200, "")
|
|
||||||
noteContent.Abstract = abstract
|
|
||||||
this.AddNoteContent(noteContent)
|
|
||||||
|
|
||||||
return note
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// 添加笔记和内容
|
// 添加笔记和内容
|
||||||
// 这里使用 info.NoteAndContent 接收?
|
// 这里使用 info.NoteAndContent 接收?
|
||||||
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
||||||
@@ -359,24 +209,7 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note
|
|||||||
if note.UserId != myUserId {
|
if note.UserId != myUserId {
|
||||||
note = this.AddSharedNote(note, myUserId)
|
note = this.AddSharedNote(note, myUserId)
|
||||||
} else {
|
} else {
|
||||||
note = this.AddNote(note, false)
|
note = this.AddNote(note)
|
||||||
}
|
|
||||||
if note.NoteId != "" {
|
|
||||||
this.AddNoteContent(noteContent)
|
|
||||||
}
|
|
||||||
return note
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
|
||||||
if(note.NoteId.Hex() == "") {
|
|
||||||
noteId := bson.NewObjectId()
|
|
||||||
note.NoteId = noteId
|
|
||||||
}
|
|
||||||
noteContent.NoteId = note.NoteId
|
|
||||||
if note.UserId != myUserId {
|
|
||||||
note = this.AddSharedNote(note, myUserId)
|
|
||||||
} else {
|
|
||||||
note = this.AddNote(note, true)
|
|
||||||
}
|
}
|
||||||
if note.NoteId != "" {
|
if note.NoteId != "" {
|
||||||
this.AddNoteContent(noteContent)
|
this.AddNoteContent(noteContent)
|
||||||
@@ -385,30 +218,19 @@ func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.N
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记
|
// 修改笔记
|
||||||
// 这里没有判断usn
|
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||||
func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bson.M, usn int) (bool, string, int) {
|
|
||||||
// 是否存在
|
|
||||||
note := this.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
userId := note.UserId.Hex()
|
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH2")
|
Log("NO AUTH2")
|
||||||
return false, "noAuth", 0
|
return false
|
||||||
} else {
|
} else {
|
||||||
Log("HAS AUTH -----------")
|
Log("HAS AUTH -----------")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if usn > 0 && note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否已自定义
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
if note.IsBlog && note.HasSelfDefined {
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
delete(needUpdate, "ImgSrc")
|
delete(needUpdate, "ImgSrc")
|
||||||
delete(needUpdate, "Desc")
|
delete(needUpdate, "Desc")
|
||||||
@@ -416,11 +238,8 @@ func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bso
|
|||||||
|
|
||||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
afterUsn := userService.IncrUsn(userId);
|
|
||||||
needUpdate["Usn"] = afterUsn
|
|
||||||
|
|
||||||
// 添加tag2
|
// 添加tag2
|
||||||
// TODO 这个tag去掉, 添加tag另外添加, 不要这个
|
|
||||||
if tags, ok := needUpdate["Tags"]; ok {
|
if tags, ok := needUpdate["Tags"]; ok {
|
||||||
tagService.AddTagsI(userId, tags)
|
tagService.AddTagsI(userId, tags)
|
||||||
}
|
}
|
||||||
@@ -428,60 +247,10 @@ func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bso
|
|||||||
// 是否修改了isBlog
|
// 是否修改了isBlog
|
||||||
// 也要修改noteContents的IsBlog
|
// 也要修改noteContents的IsBlog
|
||||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||||
isBlog2 := isBlog.(bool)
|
|
||||||
if note.IsBlog != isBlog2 {
|
|
||||||
this.UpdateNoteContentIsBlog(noteId, userId, isBlog2);
|
|
||||||
|
|
||||||
// 重新发布成博客
|
|
||||||
if !note.IsBlog {
|
|
||||||
needUpdate["PublicTime"] = needUpdate["UpdatedTime"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
|
|
||||||
if !ok {
|
|
||||||
return ok, "", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新获取之
|
|
||||||
note = this.GetNoteById(noteId)
|
|
||||||
|
|
||||||
hasRecount := false
|
|
||||||
|
|
||||||
// 如果修改了notebookId, 则更新notebookId'count
|
|
||||||
// 两方的notebook也要修改
|
|
||||||
notebookIdI := needUpdate["NotebookId"]
|
|
||||||
if notebookIdI != nil {
|
|
||||||
notebookId := notebookIdI.(bson.ObjectId)
|
|
||||||
if notebookId != "" {
|
|
||||||
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
|
|
||||||
hasRecount = true
|
|
||||||
notebookService.ReCountNotebookNumberNotes(notebookId.Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不要多次更新, isTrash = false, = true都要重新统计
|
|
||||||
if !hasRecount {
|
|
||||||
if _, ok := needUpdate["IsTrash"]; ok {
|
|
||||||
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, "", afterUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当设置/取消了笔记为博客
|
|
||||||
func (this *NoteService) UpdateNoteContentIsBlog(noteId, userId string, isBlog bool) {
|
|
||||||
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog})
|
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 附件修改, 增加noteIncr
|
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
|
||||||
func (this *NoteService) IncrNoteUsn(noteId, userId string) int {
|
|
||||||
afterUsn := userService.IncrUsn(userId)
|
|
||||||
db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
|
||||||
bson.M{"UpdatedTime": time.Now(), "Usn": afterUsn})
|
|
||||||
return afterUsn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
|
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
|
||||||
@@ -496,50 +265,31 @@ func (this *NoteService) UpdateNoteTitle(userId, updatedUserId, noteId, title st
|
|||||||
}
|
}
|
||||||
|
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
||||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now(), "Usn": userService.IncrUsn(userId)})
|
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记本内容
|
// 修改笔记本内容
|
||||||
// [ok] TODO perm未测
|
// [ok] TODO perm未测
|
||||||
// hasBeforeUpdateNote 之前是否更新过note其它信息, 如果有更新, usn不用更新
|
func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, content, abstract string) bool {
|
||||||
// TODO abstract这里生成
|
|
||||||
func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstract string, hasBeforeUpdateNote bool, usn int) (bool, string, int) {
|
|
||||||
// 是否已自定义
|
|
||||||
note := this.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
userId := note.UserId.Hex()
|
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH")
|
Log("NO AUTH")
|
||||||
return false, "noAuth", 0
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstract重置
|
|
||||||
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||||
"Content": content,
|
"Content": content,
|
||||||
"Abstract": abstract,
|
"Abstract": abstract,
|
||||||
"UpdatedTime": time.Now()}
|
"UpdatedTime": time.Now()}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
if note.IsBlog && note.HasSelfDefined {
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
delete(data, "Abstract")
|
delete(data, "Abstract")
|
||||||
}
|
}
|
||||||
|
|
||||||
// usn, 修改笔记不可能单独修改内容
|
|
||||||
afterUsn := 0
|
|
||||||
// 如果之前没有修改note其它信息, 那么usn++
|
|
||||||
if !hasBeforeUpdateNote {
|
|
||||||
// 需要验证
|
|
||||||
if usn >= 0 && note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
afterUsn = userService.IncrUsn(userId)
|
|
||||||
db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Usn", usn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
||||||
// 这里, 添加历史记录
|
// 这里, 添加历史记录
|
||||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||||
@@ -550,9 +300,9 @@ func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstr
|
|||||||
// 更新笔记图片
|
// 更新笔记图片
|
||||||
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
||||||
|
|
||||||
return true, "", afterUsn
|
return true
|
||||||
}
|
}
|
||||||
return false, "", 0
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ?????
|
// ?????
|
||||||
@@ -566,7 +316,7 @@ func (this *NoteService) updateNoteImages(noteId string, content string) bool {
|
|||||||
// 更新tags
|
// 更新tags
|
||||||
// [ok] [del]
|
// [ok] [del]
|
||||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{"Tags": tags, "Usn": userService.IncrUsn(userId)})
|
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
||||||
@@ -584,13 +334,9 @@ func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool
|
|||||||
} else {
|
} else {
|
||||||
noteUpdate["HasSelfDefined"] = false
|
noteUpdate["HasSelfDefined"] = false
|
||||||
}
|
}
|
||||||
noteUpdate["Usn"] = userService.IncrUsn(userId)
|
|
||||||
|
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
||||||
// 重新计算tags
|
// 重新计算tags
|
||||||
go (func() {
|
go (func() {
|
||||||
this.UpdateNoteContentIsBlog(noteId, userId, isBlog);
|
|
||||||
|
|
||||||
blogService.ReCountBlogTags(userId)
|
blogService.ReCountBlogTags(userId)
|
||||||
})()
|
})()
|
||||||
return ok
|
return ok
|
||||||
@@ -607,9 +353,7 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
|||||||
|
|
||||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsTrash": false,
|
bson.M{"$set": bson.M{"IsTrash": false,
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId),
|
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||||
"Usn": userService.IncrUsn(userId),
|
|
||||||
}})
|
|
||||||
|
|
||||||
if re {
|
if re {
|
||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
@@ -631,14 +375,13 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
|||||||
// 如果自己的blog状态是true, 不用改变,
|
// 如果自己的blog状态是true, 不用改变,
|
||||||
// 否则, 如果notebookId的blog是true, 则改为true之
|
// 否则, 如果notebookId的blog是true, 则改为true之
|
||||||
// 返回blog状态
|
// 返回blog状态
|
||||||
// move, copy时用
|
|
||||||
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
|
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
|
||||||
if this.IsBlog(noteId) {
|
if this.IsBlog(noteId) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if notebookService.IsBlog(notebookId) {
|
if notebookService.IsBlog(notebookId) {
|
||||||
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsBlog": true, "PublicTime": time.Now()}}) // life
|
bson.M{"$set": bson.M{"IsBlog": true}})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -664,7 +407,7 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
|||||||
note.NotebookId = bson.ObjectIdHex(notebookId)
|
note.NotebookId = bson.ObjectIdHex(notebookId)
|
||||||
|
|
||||||
noteContent.NoteId = note.NoteId
|
noteContent.NoteId = note.NoteId
|
||||||
note = this.AddNoteAndContent(note, noteContent, note.UserId);
|
this.AddNoteAndContent(note, noteContent, note.UserId);
|
||||||
|
|
||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
|
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
|
||||||
@@ -683,9 +426,10 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
|||||||
// 复制别人的共享笔记给我
|
// 复制别人的共享笔记给我
|
||||||
// 将别人可用的图片转为我的图片, 复制图片
|
// 将别人可用的图片转为我的图片, 复制图片
|
||||||
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
|
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
|
||||||
|
// Log(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId))
|
||||||
// 判断是否共享了给我
|
// 判断是否共享了给我
|
||||||
// Log(notebookService.IsMyNotebook(notebookId, myUserId))
|
if notebookService.IsMyNotebook(notebookId, myUserId) &&
|
||||||
if notebookService.IsMyNotebook(notebookId, myUserId) && shareService.HasReadPerm(fromUserId, myUserId, noteId) {
|
(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId)) {
|
||||||
note := this.GetNote(noteId, fromUserId)
|
note := this.GetNote(noteId, fromUserId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
return info.Note{}
|
return info.Note{}
|
||||||
@@ -752,7 +496,6 @@ func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int
|
|||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"IsDeleted": false, // 不能搜索已删除了的
|
|
||||||
"$or": orQ,
|
"$or": orQ,
|
||||||
}
|
}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
@@ -835,58 +578,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
// 统计
|
// 统计
|
||||||
func (this *NoteService) CountNote(userId string) int {
|
func (this *NoteService) CountNote(userId string) int {
|
||||||
q := bson.M{"IsTrash": false, "IsDeleted": false}
|
q := bson.M{"IsTrash": false}
|
||||||
if userId != "" {
|
if userId != "" {
|
||||||
q["UserId"] = bson.ObjectIdHex(userId)
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
}
|
}
|
||||||
return db.Count(db.Notes, q)
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
func (this *NoteService) CountBlog(userId string) int {
|
func (this *NoteService) CountBlog(userId string) int {
|
||||||
q := bson.M{"IsBlog": true, "IsTrash": false, "IsDeleted": false}
|
q := bson.M{"IsBlog": true, "IsTrash": false}
|
||||||
if userId != "" {
|
if userId != "" {
|
||||||
q["UserId"] = bson.ObjectIdHex(userId)
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
}
|
}
|
||||||
return db.Count(db.Notes, q)
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过标签来查询
|
|
||||||
func (this *NoteService) CountNoteByTag(userId string, tag string) int {
|
|
||||||
if tag == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
|
||||||
// "IsTrash": false,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Tags": bson.M{"$in": []string{tag}}}
|
|
||||||
return db.Count(db.Notes, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除tag
|
|
||||||
// 返回所有note的Usn
|
|
||||||
func (this *NoteService) UpdateNoteToDeleteTag(userId string, targetTag string) map[string]int {
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"Tags": bson.M{"$in": []string{targetTag}}}
|
|
||||||
notes := []info.Note{}
|
|
||||||
db.ListByQ(db.Notes, query, ¬es)
|
|
||||||
ret := map[string]int{}
|
|
||||||
for _, note := range notes {
|
|
||||||
tags := note.Tags
|
|
||||||
if tags == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for i, tag := range tags {
|
|
||||||
if tag == targetTag {
|
|
||||||
tags = tags
|
|
||||||
tags = append(tags[:i], tags[i+1:]...)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
usn := userService.IncrUsn(userId)
|
|
||||||
db.UpdateByQMap(db.Notes, bson.M{"_id": note.NoteId}, bson.M{"Usn": usn, "Tags": tags})
|
|
||||||
ret[note.NoteId.Hex()] = usn
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,6 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
|
||||||
// "html"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 笔记本
|
// 笔记本
|
||||||
@@ -42,9 +40,7 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
|
|||||||
for _, each := range userNotebooks {
|
for _, each := range userNotebooks {
|
||||||
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
|
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
|
||||||
newNotebooks.NotebookId = each.NotebookId
|
newNotebooks.NotebookId = each.NotebookId
|
||||||
newNotebooks.Title = each.Title;
|
newNotebooks.Title = each.Title
|
||||||
// newNotebooks.Title = html.EscapeString(each.Title)
|
|
||||||
newNotebooks.Title = strings.Replace(strings.Replace(each.Title, "<script>", "", -1), "</script", "", -1)
|
|
||||||
newNotebooks.Seq = each.Seq
|
newNotebooks.Seq = each.Seq
|
||||||
newNotebooks.UserId = each.UserId
|
newNotebooks.UserId = each.UserId
|
||||||
newNotebooks.ParentNotebookId = each.ParentNotebookId
|
newNotebooks.ParentNotebookId = each.ParentNotebookId
|
||||||
@@ -115,24 +111,12 @@ func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOr
|
|||||||
return notebook
|
return notebook
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步的方法
|
|
||||||
func (this *NotebookService) GeSyncNotebooks(userId string, afterUsn, maxEntry int) ([]info.Notebook) {
|
|
||||||
notebooks := []info.Notebook{}
|
|
||||||
q := db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬ebooks)
|
|
||||||
return notebooks
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户下所有的notebook
|
// 得到用户下所有的notebook
|
||||||
// 排序好之后返回
|
// 排序好之后返回
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
|
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
|
||||||
userNotebooks := []info.Notebook{}
|
userNotebooks := []info.Notebook{}
|
||||||
orQ := []bson.M{
|
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId)}).All(&userNotebooks)
|
||||||
bson.M{"IsDeleted": false},
|
|
||||||
bson.M{"IsDeleted": bson.M{"$exists": false}},
|
|
||||||
}
|
|
||||||
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "$or": orQ}).All(&userNotebooks)
|
|
||||||
|
|
||||||
if len(userNotebooks) == 0 {
|
if len(userNotebooks) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -157,46 +141,14 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
|||||||
|
|
||||||
// 添加
|
// 添加
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Notebook) {
|
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||||
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||||
notebook.Usn = userService.IncrUsn(notebook.UserId.Hex())
|
|
||||||
now := time.Now()
|
|
||||||
notebook.CreatedTime = now
|
|
||||||
notebook.UpdatedTime = now
|
|
||||||
err := db.Notebooks.Insert(notebook)
|
err := db.Notebooks.Insert(notebook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, notebook
|
panic(err)
|
||||||
}
|
|
||||||
return true, notebook
|
|
||||||
}
|
|
||||||
// 更新笔记, api
|
|
||||||
func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parentNotebookId string, seq, usn int) (bool, string, info.Notebook) {
|
|
||||||
if notebookId == "" {
|
|
||||||
return false, "notebookIdNotExists", info.Notebook{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先判断usn是否和数据库的一样, 如果不一样, 则冲突, 不保存
|
|
||||||
notebook := this.GetNotebookById(notebookId)
|
|
||||||
// 不存在
|
|
||||||
if notebook.NotebookId == "" {
|
|
||||||
return false, "notExists", notebook
|
|
||||||
} else if notebook.Usn != usn {
|
|
||||||
return false, "conflict", notebook
|
|
||||||
}
|
|
||||||
notebook.Usn = userService.IncrUsn(userId);
|
|
||||||
notebook.Title = title;
|
|
||||||
|
|
||||||
updates := bson.M{"Title": title, "Usn": notebook.Usn, "Seq": seq, "UpdatedTime": time.Now()};
|
|
||||||
if(parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId)) {
|
|
||||||
updates["ParentNotebookId"] = bson.ObjectIdHex(parentNotebookId);
|
|
||||||
} else {
|
} else {
|
||||||
updates["ParentNotebookId"] = "";
|
|
||||||
}
|
}
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates);
|
return true
|
||||||
if ok {
|
|
||||||
return ok, "", this.GetNotebookById(notebookId)
|
|
||||||
}
|
|
||||||
return false, "", notebook
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否是blog
|
// 判断是否是blog
|
||||||
@@ -222,22 +174,19 @@ func (this *NotebookService) UpdateNotebook(notebook info.Notebook) bool {
|
|||||||
// 更新笔记本标题
|
// 更新笔记本标题
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
|
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
|
||||||
usn := userService.IncrUsn(userId)
|
return db.UpdateByIdAndUserIdField(db.Notebooks, notebookId, userId, "Title", title)
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Title": title, "Usn": usn})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新notebook
|
// 更新notebook
|
||||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
needUpdate["Usn"] = userService.IncrUsn(userId)
|
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToBlog or Not
|
// ToBlog or Not
|
||||||
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
||||||
updates := bson.M{"IsBlog": isBlog, "Usn": userService.IncrUsn(userId)}
|
|
||||||
// 笔记本
|
// 笔记本
|
||||||
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
|
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"IsBlog": isBlog})
|
||||||
|
|
||||||
// 更新笔记
|
// 更新笔记
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
@@ -248,8 +197,6 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
|
|||||||
} else {
|
} else {
|
||||||
data["HasSelfDefined"] = false
|
data["HasSelfDefined"] = false
|
||||||
}
|
}
|
||||||
// usn
|
|
||||||
data["Usn"] = userService.IncrUsn(userId)
|
|
||||||
db.UpdateByQMap(db.Notes, q, data)
|
db.UpdateByQMap(db.Notes, q, data)
|
||||||
|
|
||||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||||
@@ -275,19 +222,12 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
|
|||||||
// 查看是否有子notebook
|
// 查看是否有子notebook
|
||||||
// 先查看该notebookId下是否有notes, 没有则删除
|
// 先查看该notebookId下是否有notes, 没有则删除
|
||||||
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
||||||
if db.Count(db.Notebooks, bson.M{
|
if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
|
||||||
"ParentNotebookId": bson.ObjectIdHex(notebookId),
|
"UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"IsDeleted": false,
|
|
||||||
}) == 0 { // 无
|
|
||||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false}) == 0 { // 不包含trash
|
||||||
"IsDeleted": false}) == 0 { // 不包含trash
|
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||||
// 不是真删除 1/20, 为了同步笔记本
|
|
||||||
ok := db.UpdateByQMap(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, bson.M{"IsDeleted": true, "Usn": userService.IncrUsn(userId)})
|
|
||||||
return ok, ""
|
|
||||||
// return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
|
||||||
}
|
}
|
||||||
return false, "笔记本下有笔记"
|
return false, "笔记本下有笔记"
|
||||||
} else {
|
} else {
|
||||||
@@ -295,18 +235,6 @@ func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API调用, 删除笔记本, 不作笔记控制
|
|
||||||
func (this *NotebookService) DeleteNotebookForce(userId, notebookId string, usn int) (bool, string) {
|
|
||||||
notebook := this.GetNotebookById(notebookId)
|
|
||||||
// 不存在
|
|
||||||
if notebook.NotebookId == "" {
|
|
||||||
return false, "notExists"
|
|
||||||
} else if notebook.Usn != usn {
|
|
||||||
return false, "conflict"
|
|
||||||
}
|
|
||||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
// 传入 notebookId => Seq
|
// 传入 notebookId => Seq
|
||||||
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
|
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
|
||||||
@@ -317,7 +245,7 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
|||||||
}
|
}
|
||||||
|
|
||||||
for notebookId, seq := range notebookId2Seqs {
|
for notebookId, seq := range notebookId2Seqs {
|
||||||
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) {
|
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), bson.ObjectIdHex(userId), "Seq", seq) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,14 +253,15 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序和设置父
|
|
||||||
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
ok := false
|
ok := false
|
||||||
// 如果没parentNotebookId, 则parentNotebookId设空
|
// 如果没parentNotebookId, 则parentNotebookId设空
|
||||||
if(parentNotebookId == "") {
|
if(parentNotebookId == "") {
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)});
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", "");
|
||||||
} else {
|
} else {
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": bson.ObjectIdHex(parentNotebookId), "Usn": userService.IncrUsn(userId)});
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", bson.ObjectIdHex(parentNotebookId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -341,7 +270,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
|
|||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
for seq, notebookId := range siblings {
|
for seq, notebookId := range siblings {
|
||||||
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) {
|
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), userIdO, "Seq", seq) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,7 +283,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
|
|||||||
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
|
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
|
||||||
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
|
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
|
||||||
notebookIdO := bson.ObjectIdHex(notebookId)
|
notebookIdO := bson.ObjectIdHex(notebookId)
|
||||||
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false, "IsDeleted": false})
|
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false})
|
||||||
Log(count)
|
Log(count)
|
||||||
Log(notebookId)
|
Log(notebookId)
|
||||||
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
|
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
|
||||||
|
|||||||
@@ -45,13 +45,9 @@ func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) {
|
|||||||
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenPwd); !ok {
|
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenPwd); !ok {
|
||||||
return ok, msg
|
return ok, msg
|
||||||
}
|
}
|
||||||
digest, err := GenerateHash(pwd)
|
|
||||||
if err != nil {
|
|
||||||
return false,"GenerateHash error"
|
|
||||||
}
|
|
||||||
passwd := string(digest)
|
|
||||||
// 修改密码之
|
// 修改密码之
|
||||||
ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", passwd)
|
ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", Md5(pwd))
|
||||||
|
|
||||||
// 删除token
|
// 删除token
|
||||||
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
|
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
|
|||||||
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||||
bson.M{key: value, "UpdatedTime": time.Now()})
|
bson.M{key: value, "UpdatedTime": time.Now()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
|
||||||
|
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||||
|
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 注销时清空session
|
// 注销时清空session
|
||||||
func (this *SessionService) Clear(sessionId string) bool {
|
func (this *SessionService) Clear(sessionId string) bool {
|
||||||
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
|
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
|
||||||
@@ -70,19 +77,18 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------
|
|
||||||
// API
|
// 附件token
|
||||||
func (this *SessionService) GetUserId(sessionId string) string {
|
func (this *SessionService) GetToken(sessionId string) string {
|
||||||
session := this.Get(sessionId)
|
session := this.Get(sessionId)
|
||||||
// 更新updateTime, 避免过期
|
return session.Token
|
||||||
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
|
||||||
bson.M{"UpdatedTime": time.Now()})
|
|
||||||
return session.UserId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录成功后设置userId
|
func (this *SessionService) SetToken(sessionId, token string) bool {
|
||||||
func (this *SessionService) SetUserId(sessionId, userId string) bool {
|
|
||||||
this.Get(sessionId)
|
this.Get(sessionId)
|
||||||
ok := this.Update(sessionId, "UserId", userId)
|
Log(sessionId)
|
||||||
|
Log(token)
|
||||||
|
ok := this.UpdateToken(sessionId, "Token", token)
|
||||||
|
Log(ok)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
+65
-55
@@ -7,6 +7,9 @@ import (
|
|||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"sort"
|
"sort"
|
||||||
|
"math/rand"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 共享Notebook, Note服务
|
// 共享Notebook, Note服务
|
||||||
@@ -33,9 +36,8 @@ type ShareService struct {
|
|||||||
|
|
||||||
// 谁共享给了我的Query
|
// 谁共享给了我的Query
|
||||||
func (this *ShareService) getOrQ(userId string) bson.M {
|
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||||
// 得到我和和我参与的组织
|
// 得到我参与的组织
|
||||||
groupIds := groupService.GetMineAndBelongToGroupIds(userId)
|
groupIds := groupService.GetBelongToGroupIds(userId)
|
||||||
|
|
||||||
q := bson.M{}
|
q := bson.M{}
|
||||||
if len(groupIds) > 0 {
|
if len(groupIds) > 0 {
|
||||||
orQ := []bson.M{
|
orQ := []bson.M{
|
||||||
@@ -52,8 +54,6 @@ func (this *ShareService) getOrQ(userId string) bson.M {
|
|||||||
|
|
||||||
// 得到共享给我的笔记本和用户(谁共享给了我)
|
// 得到共享给我的笔记本和用户(谁共享给了我)
|
||||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||||
myUserId := userId
|
|
||||||
|
|
||||||
// 得到共享给我的用户s信息
|
// 得到共享给我的用户s信息
|
||||||
// 得到我参与的组织
|
// 得到我参与的组织
|
||||||
q := this.getOrQ(userId)
|
q := this.getOrQ(userId)
|
||||||
@@ -67,15 +67,7 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
|
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
|
||||||
|
|
||||||
userIds := append(userIds1, userIds2...)
|
userIds := append(userIds1, userIds2...)
|
||||||
|
|
||||||
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||||
// 不要我的id
|
|
||||||
for i, userInfo := range userInfos {
|
|
||||||
if userInfo.UserId.Hex() == myUserId {
|
|
||||||
userInfos = append(userInfos[:i], userInfos[i+1:]...)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// 得到他们共享给我的notebooks
|
// 得到他们共享给我的notebooks
|
||||||
@@ -113,11 +105,6 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
// 先建立userId => []
|
// 先建立userId => []
|
||||||
for _, eachSub := range subShareNotebooks {
|
for _, eachSub := range subShareNotebooks {
|
||||||
userId := eachSub.Notebook.UserId
|
userId := eachSub.Notebook.UserId
|
||||||
// 我自己的, 算了
|
|
||||||
if userId.Hex() == myUserId {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := shareNotebooksByUsersMap[userId]; ok {
|
if _, ok := shareNotebooksByUsersMap[userId]; ok {
|
||||||
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
|
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
|
||||||
} else {
|
} else {
|
||||||
@@ -310,11 +297,7 @@ func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId,
|
|||||||
if toUserId == "" {
|
if toUserId == "" {
|
||||||
return false, "无该用户", ""
|
return false, "无该用户", ""
|
||||||
}
|
}
|
||||||
return this.AddShareNotebookToUserId(notebookId, perm, userId, toUserId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 第三方注册时没有email
|
|
||||||
func (this *ShareService) AddShareNotebookToUserId(notebookId string, perm int, userId, toUserId string) (bool, string, string) {
|
|
||||||
// 添加一条记录说明两者存在关系
|
// 添加一条记录说明两者存在关系
|
||||||
this.AddHasShareNote(userId, toUserId);
|
this.AddHasShareNote(userId, toUserId);
|
||||||
|
|
||||||
@@ -347,11 +330,7 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
|||||||
if toUserId == "" {
|
if toUserId == "" {
|
||||||
return false, "无该用户", ""
|
return false, "无该用户", ""
|
||||||
}
|
}
|
||||||
return this.AddShareNoteToUserId(noteId, perm, userId, toUserId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 第三方测试没有userId
|
|
||||||
func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId, toUserId string) (bool, string, string) {
|
|
||||||
// 添加一条记录说明两者存在关系
|
// 添加一条记录说明两者存在关系
|
||||||
this.AddHasShareNote(userId, toUserId);
|
this.AddHasShareNote(userId, toUserId);
|
||||||
|
|
||||||
@@ -361,12 +340,14 @@ func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId,
|
|||||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||||
UserId: bson.ObjectIdHex(userId),
|
UserId: bson.ObjectIdHex(userId),
|
||||||
ToUserId: bson.ObjectIdHex(toUserId),
|
ToUserId: bson.ObjectIdHex(toUserId),
|
||||||
Perm: perm,
|
Perm: perm,
|
||||||
CreatedTime: time.Now(),
|
CreatedTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,7 +671,8 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
|||||||
|
|
||||||
// 得到笔记分享给的groups
|
// 得到笔记分享给的groups
|
||||||
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
||||||
groups := groupService.GetGroupsContainOf(userId)
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
// 得到有分享的分组
|
// 得到有分享的分组
|
||||||
shares := []info.ShareNote{}
|
shares := []info.ShareNote{}
|
||||||
@@ -717,7 +699,9 @@ func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.Share
|
|||||||
|
|
||||||
// 共享笔记给分组
|
// 共享笔记给分组
|
||||||
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
||||||
if !groupService.IsExistsGroupUser(userId, groupId) {
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +729,8 @@ func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) b
|
|||||||
|
|
||||||
// 得到笔记本分享给的groups
|
// 得到笔记本分享给的groups
|
||||||
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
||||||
groups := groupService.GetGroupsContainOf(userId)
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
// 得到有分享的分组
|
// 得到有分享的分组
|
||||||
shares := []info.ShareNotebook{}
|
shares := []info.ShareNotebook{}
|
||||||
@@ -772,7 +757,9 @@ func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []in
|
|||||||
}
|
}
|
||||||
// 共享笔记给分组
|
// 共享笔记给分组
|
||||||
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
||||||
if !groupService.IsExistsGroupUser(userId, groupId) {
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,35 +783,58 @@ func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId s
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
|
||||||
// 删除组时, 删除所有的
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
func (this *ShareService) DeleteAllShareNotebookGroup(groupId string) bool {
|
func (this *ShareService) GenSharePass(noteId string) (int, bool) {
|
||||||
return db.Delete(db.ShareNotebooks, bson.M{
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
pass := 1000 + r.Intn(9000)
|
||||||
});
|
|
||||||
}
|
ok := db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$set": bson.M{"SharePass": pass}})
|
||||||
func (this *ShareService) DeleteAllShareNoteGroup(groupId string) bool {
|
return pass, ok
|
||||||
return db.Delete(db.ShareNotes, bson.M{
|
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
func (this *ShareService) QuerySharePass(noteId string) int {
|
||||||
// 删除组内用户时, 删除其分享的
|
note := &info.Note{}
|
||||||
//--------------------
|
db.Get(db.Notes, noteId, note)
|
||||||
|
|
||||||
func (this *ShareService) DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId string) bool {
|
return note.SharePass
|
||||||
return db.Delete(db.ShareNotebooks, bson.M{
|
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *ShareService) DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId string) bool {
|
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
|
||||||
return db.Delete(db.ShareNotes, bson.M{
|
note = info.Note{}
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
if note.SharePass == sharePass {
|
||||||
});
|
note = noteService.GetNoteById(noteId)
|
||||||
|
noteContent = noteService.GetNoteContent(noteId, note.UserId.Hex())
|
||||||
|
flag = true
|
||||||
|
} else {
|
||||||
|
note = info.Note{}
|
||||||
|
noteContent = info.NoteContent{}
|
||||||
|
flag = false
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//把笔记中含有attachID的url后加上token,返回笔记中含有的attachids
|
||||||
|
func (this *ShareService) AppendToken4URL(token, content string) (c string, attachIds map[string]bool) {
|
||||||
|
re := regexp.MustCompile(`href=\"(.*?attachId.*?)\".*?data-mce-href=\"(.*?attachId.*?)\"`)
|
||||||
|
re2 := regexp.MustCompile(`\"(.*?attachId.*?)\"`)
|
||||||
|
|
||||||
|
attachIds = map[string]bool{}
|
||||||
|
s := re.ReplaceAllStringFunc(content, func(m string) string {
|
||||||
|
idx := strings.Index(m, "attachId=") + len("attachId=")
|
||||||
|
var ss []byte = []byte(m)
|
||||||
|
attachId := string(ss[idx: idx + 24])
|
||||||
|
attachIds[attachId] = true
|
||||||
|
return re2.ReplaceAllString(m, `"${1}&token=` + token + `"`)
|
||||||
|
})
|
||||||
|
|
||||||
|
re3 := regexp.MustCompile(`<img\s+src=\"(.*?fileId.*?)\".*?data-mce-src=\"(.*?fileId.*?)\"`)
|
||||||
|
re4 := regexp.MustCompile(`\"(.*?fileId.*?)\"`)
|
||||||
|
|
||||||
|
c = re3.ReplaceAllStringFunc(s, func(m string) string {
|
||||||
|
return re4.ReplaceAllString(m, `"${1}&token=` + token + `"`)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+2
-100
@@ -3,9 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -14,14 +14,12 @@ import (
|
|||||||
type TagService struct {
|
type TagService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (this *TagService) GetTags(userId string) []string {
|
func (this *TagService) GetTags(userId string) []string {
|
||||||
tag := info.Tag{}
|
tag := info.Tag{}
|
||||||
db.Get(db.Tags, userId, &tag)
|
db.Get(db.Tags, userId, &tag)
|
||||||
LogJ(tag)
|
LogJ(tag)
|
||||||
return tag.Tags
|
return tag.Tags
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
|
func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
|
||||||
if ts, ok2 := tags.([]string); ok2 {
|
if ts, ok2 := tags.([]string); ok2 {
|
||||||
@@ -39,99 +37,3 @@ func (this *TagService) AddTags(userId string, tags []string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------
|
|
||||||
// v2
|
|
||||||
// 第二版标签, 单独一张表, 每一个tag一条记录
|
|
||||||
|
|
||||||
// 添加或更新标签, 先查下是否存在, 不存在则添加, 存在则更新
|
|
||||||
// 都要统计下tag的note数
|
|
||||||
// 什么时候调用? 笔记添加Tag, 删除Tag时
|
|
||||||
// 删除note时, 都可以调用
|
|
||||||
// 万能
|
|
||||||
func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
|
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
db.GetByQ(db.NoteTags, bson.M{"UserId": userIdO, "Tag": tag}, ¬eTag)
|
|
||||||
|
|
||||||
// 存在, 则更新之
|
|
||||||
if noteTag.TagId != "" {
|
|
||||||
// 统计note数
|
|
||||||
count := noteService.CountNoteByTag(userId, tag)
|
|
||||||
noteTag.Count = count
|
|
||||||
noteTag.UpdatedTime = time.Now()
|
|
||||||
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
|
|
||||||
db.UpdateByIdAndUserId(db.NoteTags, noteTag.TagId.Hex(), userId, noteTag)
|
|
||||||
return noteTag
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不存在, 则创建之
|
|
||||||
noteTag.TagId = bson.NewObjectId()
|
|
||||||
noteTag.Count = 1
|
|
||||||
noteTag.Tag = tag
|
|
||||||
noteTag.UserId = bson.ObjectIdHex(userId)
|
|
||||||
noteTag.CreatedTime = time.Now()
|
|
||||||
noteTag.UpdatedTime = noteTag.CreatedTime
|
|
||||||
noteTag.Usn = userService.IncrUsn(userId)
|
|
||||||
noteTag.IsDeleted = false
|
|
||||||
db.Insert(db.NoteTags, noteTag)
|
|
||||||
|
|
||||||
return noteTag
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到标签, 按更新时间来排序
|
|
||||||
func (this *TagService) GetTags(userId string) []info.NoteTag {
|
|
||||||
tags := []info.NoteTag{}
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsDeleted": false}
|
|
||||||
q := db.NoteTags.Find(query);
|
|
||||||
sortFieldR := "-UpdatedTime"
|
|
||||||
q.Sort(sortFieldR).All(&tags)
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
// 也删除所有的笔记含该标签的
|
|
||||||
// 返回noteId => usn
|
|
||||||
func (this *TagService) DeleteTag(userId string, tag string) map[string]int {
|
|
||||||
usn := userService.IncrUsn(userId)
|
|
||||||
if db.UpdateByQMap(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, bson.M{"Usn": usn, "IsDeleted": true}) {
|
|
||||||
return noteService.UpdateNoteToDeleteTag(userId, tag);
|
|
||||||
}
|
|
||||||
return map[string]int{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签, 供API调用
|
|
||||||
func (this *TagService) DeleteTagApi(userId string, tag string, usn int) (ok bool, msg string, toUsn int) {
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
db.GetByQ(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, ¬eTag)
|
|
||||||
|
|
||||||
if noteTag.TagId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
if noteTag.Usn > usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
toUsn = userService.IncrUsn(userId)
|
|
||||||
if db.UpdateByQMap(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, bson.M{"Usn": usn, "IsDeleted": true}) {
|
|
||||||
return true, "", toUsn
|
|
||||||
}
|
|
||||||
return false, "", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新统计标签的count
|
|
||||||
func (this *TagService) reCountTagCount(userId string, tags []string) {
|
|
||||||
if tags == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, tag := range tags {
|
|
||||||
this.AddOrUpdateTag(userId, tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同步用
|
|
||||||
func (this *TagService) GeSyncTags(userId string, afterUsn, maxEntry int) ([]info.NoteTag) {
|
|
||||||
noteTags := []info.NoteTag{}
|
|
||||||
q := db.NoteTags.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬eTags)
|
|
||||||
return noteTags
|
|
||||||
}
|
|
||||||
@@ -85,13 +85,13 @@ func (this *ThemeService) getDefaultTheme(style string) info.Theme {
|
|||||||
|
|
||||||
// 用户的主题路径设置
|
// 用户的主题路径设置
|
||||||
func (this *ThemeService) getUserThemeBasePath(userId string) string {
|
func (this *ThemeService) getUserThemeBasePath(userId string) string {
|
||||||
return revel.BasePath + "/public/upload/" + Digest3(userId) + "/" + userId + "/themes"
|
return revel.BasePath + "/public/upload/" + userId + "/themes"
|
||||||
}
|
}
|
||||||
func (this *ThemeService) getUserThemePath(userId, themeId string) string {
|
func (this *ThemeService) getUserThemePath(userId, themeId string) string {
|
||||||
return this.getUserThemeBasePath(userId) + "/" + themeId
|
return this.getUserThemeBasePath(userId) + "/" + themeId
|
||||||
}
|
}
|
||||||
func (this *ThemeService) getUserThemePath2(userId, themeId string) string {
|
func (this *ThemeService) getUserThemePath2(userId, themeId string) string {
|
||||||
return "public/upload/" + Digest3(userId) + "/" + userId + "/themes/" + themeId
|
return "public/upload/" + userId + "/themes/" + themeId
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新建主题
|
// 新建主题
|
||||||
@@ -412,18 +412,10 @@ func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string)
|
|||||||
themeIdO := bson.NewObjectId()
|
themeIdO := bson.NewObjectId()
|
||||||
themeId := themeIdO.Hex()
|
themeId := themeIdO.Hex()
|
||||||
targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId
|
targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId
|
||||||
|
|
||||||
err := os.MkdirAll(targetPath, 0755)
|
|
||||||
if err != nil {
|
|
||||||
msg = "error"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ok, msg = archive.Unzip(path, targetPath); !ok {
|
if ok, msg = archive.Unzip(path, targetPath); !ok {
|
||||||
DeleteFile(targetPath)
|
DeleteFile(targetPath)
|
||||||
Log("oh no")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主题验证
|
// 主题验证
|
||||||
if ok, msg = this.ValidateTheme(targetPath, "", ""); !ok {
|
if ok, msg = this.ValidateTheme(targetPath, "", ""); !ok {
|
||||||
DeleteFile(targetPath)
|
DeleteFile(targetPath)
|
||||||
|
|||||||
@@ -25,16 +25,10 @@ type TrashService struct {
|
|||||||
// 应该放在回收站里
|
// 应该放在回收站里
|
||||||
// 有trashService
|
// 有trashService
|
||||||
func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
||||||
note := noteService.GetNote(noteId, userId);
|
|
||||||
// 如果是垃圾, 则彻底删除
|
|
||||||
if (note.IsTrash) {
|
|
||||||
return this.DeleteTrash(noteId, userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 首先删除其共享
|
// 首先删除其共享
|
||||||
if shareService.DeleteShareNoteAll(noteId, userId) {
|
if shareService.DeleteShareNoteAll(noteId, userId) {
|
||||||
// 更新note isTrash = true
|
// 更新note isTrash = true
|
||||||
if db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true, "Usn": userService.IncrUsn(userId)}}) {
|
if db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}}) {
|
||||||
// recount notebooks' notes number
|
// recount notebooks' notes number
|
||||||
notebookIdO := noteService.GetNotebookId(noteId)
|
notebookIdO := noteService.GetNotebookId(noteId)
|
||||||
notebookId := notebookIdO.Hex()
|
notebookId := notebookIdO.Hex()
|
||||||
@@ -42,17 +36,15 @@ func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除别人共享给我的笔记
|
// 删除别人共享给我的笔记
|
||||||
// 先判断我是否有权限, 笔记是否是我创建的
|
// 先判断我是否有权限, 笔记是否是我创建的
|
||||||
func (this *TrashService) DeleteSharedNote(noteId, myUserId string) bool {
|
func (this *TrashService) DeleteSharedNote(noteId, userId, myUserId string) bool {
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNote(noteId, userId)
|
||||||
userId := note.UserId.Hex()
|
|
||||||
if shareService.HasUpdatePerm(userId, myUserId, noteId) && note.CreatedUserId.Hex() == myUserId {
|
if shareService.HasUpdatePerm(userId, myUserId, noteId) && note.CreatedUserId.Hex() == myUserId {
|
||||||
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true, "Usn": userService.IncrUsn(userId)}})
|
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}})
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -61,63 +53,23 @@ func (this *TrashService) DeleteSharedNote(noteId, myUserId string) bool {
|
|||||||
func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
||||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsTrash": false,
|
bson.M{"$set": bson.M{"IsTrash": false,
|
||||||
"Usn": userService.IncrUsn(userId),
|
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除trash
|
// 删除trash
|
||||||
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
||||||
note := noteService.GetNote(noteId, userId);
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// delete note's attachs
|
// delete note's attachs
|
||||||
ok := attachService.DeleteAllAttachs(noteId, userId)
|
ok := attachService.DeleteAllAttachs(noteId, userId)
|
||||||
|
|
||||||
// 设置删除位
|
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
|
||||||
bson.M{"IsDeleted": true,
|
|
||||||
"Usn": userService.IncrUsn(userId)})
|
|
||||||
// delete note
|
// delete note
|
||||||
// ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
||||||
|
|
||||||
// delete content
|
// delete content
|
||||||
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
||||||
|
|
||||||
// 重新统计tag's count
|
|
||||||
// TODO 这里会改变tag's Usn
|
|
||||||
tagService.reCountTagCount(userId, note.Tags)
|
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TrashService) DeleteTrashApi(noteId, userId string, usn int) (bool, string, int) {
|
|
||||||
note := noteService.GetNote(noteId, userId)
|
|
||||||
|
|
||||||
if note.NoteId == "" || note.IsDeleted {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete note's attachs
|
|
||||||
ok := attachService.DeleteAllAttachs(noteId, userId)
|
|
||||||
|
|
||||||
// 设置删除位
|
|
||||||
afterUsn := userService.IncrUsn(userId)
|
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
|
||||||
bson.M{"IsDeleted": true,
|
|
||||||
"Usn": afterUsn})
|
|
||||||
|
|
||||||
// delete content
|
|
||||||
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
|
||||||
|
|
||||||
return ok, "", afterUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列出note, 排序规则, 还有分页
|
// 列出note, 排序规则, 还有分页
|
||||||
// CreatedTime, UpdatedTime, title 来排序
|
// CreatedTime, UpdatedTime, title 来排序
|
||||||
func (this *TrashService) ListNotes(userId string,
|
func (this *TrashService) ListNotes(userId string,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func (this *UpgradeService) UpgradeBlog() bool {
|
|||||||
*/
|
*/
|
||||||
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
||||||
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
||||||
return false, "Leanote have been upgraded"
|
return false, "已升级"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. aboutMe -> page
|
// 1. aboutMe -> page
|
||||||
@@ -102,81 +102,3 @@ func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg stri
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usn设置
|
|
||||||
// 客户端 api
|
|
||||||
|
|
||||||
func (this *UpgradeService) moveTag() {
|
|
||||||
usnI := 1
|
|
||||||
tags := []info.Tag{}
|
|
||||||
db.ListByQ(db.Tags, bson.M{}, &tags)
|
|
||||||
for _, eachTag := range tags {
|
|
||||||
tagTitles := eachTag.Tags
|
|
||||||
now := time.Now()
|
|
||||||
if tagTitles != nil && len(tagTitles) > 0 {
|
|
||||||
for _, tagTitle := range tagTitles {
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
noteTag.TagId = bson.NewObjectId()
|
|
||||||
noteTag.Count = 1
|
|
||||||
noteTag.Tag = tagTitle
|
|
||||||
noteTag.UserId = eachTag.UserId
|
|
||||||
noteTag.CreatedTime = now
|
|
||||||
noteTag.UpdatedTime = now
|
|
||||||
noteTag.Usn = usnI
|
|
||||||
noteTag.IsDeleted = false
|
|
||||||
db.Insert(db.NoteTags, noteTag)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpgradeService) setNotebookUsn() {
|
|
||||||
usnI := 1
|
|
||||||
notebooks := []info.Notebook{}
|
|
||||||
db.ListByQWithFields(db.Notebooks, bson.M{}, []string{"UserId"}, ¬ebooks)
|
|
||||||
|
|
||||||
for _, notebook := range notebooks {
|
|
||||||
db.UpdateByQField(db.Notebooks, bson.M{"_id": notebook.NotebookId}, "Usn", usnI)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpgradeService) setNoteUsn() {
|
|
||||||
usnI := 1
|
|
||||||
notes := []info.Note{}
|
|
||||||
db.ListByQWithFields(db.Notes, bson.M{}, []string{"UserId"}, ¬es)
|
|
||||||
|
|
||||||
for _, note := range notes {
|
|
||||||
db.UpdateByQField(db.Notes, bson.M{"_id": note.NoteId}, "Usn", usnI)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 升级为Api, beta.4
|
|
||||||
func (this *UpgradeService) Api(userId string) (ok bool, msg string) {
|
|
||||||
if configService.GetGlobalStringConfig("UpgradeBetaToBeta4") != "" {
|
|
||||||
return false, "Leanote have been upgraded"
|
|
||||||
}
|
|
||||||
|
|
||||||
// user
|
|
||||||
db.UpdateByQField(db.Users, bson.M{}, "Usn", 200000)
|
|
||||||
|
|
||||||
// notebook
|
|
||||||
db.UpdateByQField(db.Notebooks, bson.M{}, "IsDeleted", false)
|
|
||||||
this.setNotebookUsn();
|
|
||||||
|
|
||||||
// note
|
|
||||||
// 1-N
|
|
||||||
db.UpdateByQField(db.Notes, bson.M{}, "IsDeleted", false)
|
|
||||||
this.setNoteUsn();
|
|
||||||
|
|
||||||
// tag
|
|
||||||
// 1-N
|
|
||||||
/// tag, 要重新插入, 将之前的Tag表迁移到NoteTag中
|
|
||||||
this.moveTag();
|
|
||||||
|
|
||||||
configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToBeta4", "1")
|
|
||||||
|
|
||||||
return true, ""
|
|
||||||
}
|
|
||||||
@@ -12,27 +12,6 @@ import (
|
|||||||
type UserService struct {
|
type UserService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自增Usn
|
|
||||||
// 每次notebook,note添加, 修改, 删除, 都要修改
|
|
||||||
func (this *UserService) IncrUsn(userId string) int {
|
|
||||||
user := info.User{}
|
|
||||||
query := bson.M{"_id": bson.ObjectIdHex(userId)}
|
|
||||||
db.GetByQWithFields(db.Users, query, []string{"Usn"}, &user)
|
|
||||||
usn := user.Usn
|
|
||||||
usn += 1
|
|
||||||
Log("inc Usn")
|
|
||||||
db.UpdateByQField(db.Users, query, "Usn", usn)
|
|
||||||
return usn
|
|
||||||
// return db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"ReadNum": 1}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UserService) GetUsn(userId string) int {
|
|
||||||
user := info.User{}
|
|
||||||
query := bson.M{"_id": bson.ObjectIdHex(userId)}
|
|
||||||
db.GetByQWithFields(db.Users, query, []string{"Usn"}, &user)
|
|
||||||
return user.Usn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加用户
|
// 添加用户
|
||||||
func (this *UserService) AddUser(user info.User) bool {
|
func (this *UserService) AddUser(user info.User) bool {
|
||||||
if user.UserId == "" {
|
if user.UserId == "" {
|
||||||
@@ -114,13 +93,6 @@ func (this *UserService) setUserLogo(user *info.User) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 仅得到用户
|
|
||||||
func (this *UserService) GetUser(userId string) info.User {
|
|
||||||
user := info.User{}
|
|
||||||
db.Get(db.Users, userId, &user)
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户信息 userId
|
// 得到用户信息 userId
|
||||||
func (this *UserService) GetUserInfo(userId string) info.User {
|
func (this *UserService) GetUserInfo(userId string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
@@ -133,8 +105,6 @@ func (this *UserService) GetUserInfo(userId string) info.User {
|
|||||||
func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
||||||
// Logo路径问题, 有些有http: 有些没有
|
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
// 得到用户信息 username
|
// 得到用户信息 username
|
||||||
@@ -142,15 +112,12 @@ func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
|||||||
user := info.User{}
|
user := info.User{}
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
||||||
// Logo路径问题, 有些有http: 有些没有
|
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UserService) GetUserInfoByThirdUserId(thirdUserId string) info.User {
|
func (this *UserService) GetUserInfoByThirdUserId(thirdUserId string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
db.GetByQ(db.Users, bson.M{"ThirdUserId": thirdUserId}, &user)
|
db.GetByQ(db.Users, bson.M{"ThirdUserId": thirdUserId}, &user)
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.User {
|
func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.User {
|
||||||
@@ -216,20 +183,6 @@ func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[st
|
|||||||
return userAndBlogMap
|
return userAndBlogMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户信息+博客主页
|
|
||||||
func (this *UserService) GetUserAndBlogUrl(userId string) info.UserAndBlogUrl {
|
|
||||||
user := this.GetUserInfo(userId)
|
|
||||||
userBlog := blogService.GetUserBlog(userId)
|
|
||||||
|
|
||||||
blogUrls := blogService.GetBlogUrls(&userBlog, &user)
|
|
||||||
|
|
||||||
return info.UserAndBlogUrl{
|
|
||||||
User: user,
|
|
||||||
BlogUrl: blogUrls.IndexUrl,
|
|
||||||
PostUrl: blogUrls.PostUrl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到userAndBlog公开信息
|
// 得到userAndBlog公开信息
|
||||||
func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog {
|
func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog {
|
||||||
user := this.GetUserInfo(userId)
|
user := this.GetUserInfo(userId)
|
||||||
@@ -267,17 +220,17 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
|||||||
return users2
|
return users2
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用email(username), 得到用户信息
|
// 使用email(username), pwd得到用户信息
|
||||||
func (this *UserService) GetUserInfoByName(emailOrUsername string) info.User {
|
func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.User {
|
||||||
emailOrUsername = strings.ToLower(emailOrUsername)
|
emailOrUsername = strings.ToLower(emailOrUsername)
|
||||||
|
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
if strings.Contains(emailOrUsername, "@") {
|
if strings.Contains(emailOrUsername, "@") {
|
||||||
db.GetByQ(db.Users, bson.M{"Email": emailOrUsername}, &user)
|
db.GetByQ(db.Users, bson.M{"Email": emailOrUsername, "Pwd": md5Pwd}, &user)
|
||||||
} else {
|
} else {
|
||||||
db.GetByQ(db.Users, bson.M{"Username": emailOrUsername}, &user)
|
db.GetByQ(db.Users, bson.M{"Username": emailOrUsername, "Pwd": md5Pwd}, &user)
|
||||||
}
|
}
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,16 +262,10 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
|||||||
// 已经登录了的用户修改密码
|
// 已经登录了的用户修改密码
|
||||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||||
userInfo := this.GetUserInfo(userId)
|
userInfo := this.GetUserInfo(userId)
|
||||||
if !ComparePwd(oldPwd, userInfo.Pwd) {
|
if userInfo.Pwd != Md5(oldPwd) {
|
||||||
return false, "oldPasswordError"
|
return false, "oldPasswordError"
|
||||||
}
|
}
|
||||||
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
passwd := GenPwd(pwd)
|
|
||||||
if passwd == "" {
|
|
||||||
return false, "GenerateHash error"
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", passwd)
|
|
||||||
return ok, ""
|
return ok, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,12 +274,7 @@ func (this *UserService) ResetPwd(adminUserId, userId, pwd string) (ok bool, msg
|
|||||||
if configService.GetAdminUserId() != adminUserId {
|
if configService.GetAdminUserId() != adminUserId {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ok = db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
passwd := GenPwd(pwd)
|
|
||||||
if passwd == "" {
|
|
||||||
return false, "GenerateHash error"
|
|
||||||
}
|
|
||||||
ok = db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", passwd)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,7 +332,7 @@ func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string)
|
|||||||
tokenInfo := info.Token{}
|
tokenInfo := info.Token{}
|
||||||
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenUpdateEmail); ok {
|
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenUpdateEmail); ok {
|
||||||
// 修改之后的邮箱
|
// 修改之后的邮箱
|
||||||
email = strings.ToLower(tokenInfo.Email)
|
email = tokenInfo.Email
|
||||||
// 先验证该email是否被注册了
|
// 先验证该email是否被注册了
|
||||||
if userService.IsExistsUser(email) {
|
if userService.IsExistsUser(email) {
|
||||||
ok = false
|
ok = false
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ func encodeValue(val string) string {
|
|||||||
v.Set("", val)
|
v.Set("", val)
|
||||||
return v.Encode()[1:]
|
return v.Encode()[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加笔记时通过title得到urlTitle
|
// 添加笔记时通过title得到urlTitle
|
||||||
func fixUrlTitle(urlTitle string) string {
|
func fixUrlTitle(urlTitle string) string {
|
||||||
if urlTitle != "" {
|
if urlTitle != "" {
|
||||||
@@ -120,15 +119,6 @@ func fixUrlTitle(urlTitle string) string {
|
|||||||
|
|
||||||
func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int) string {
|
func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int) string {
|
||||||
urlTitle2 := urlTitle
|
urlTitle2 := urlTitle
|
||||||
|
|
||||||
// 判断urlTitle是不是过长, 过长则截断, 300
|
|
||||||
// 不然生成index有问题
|
|
||||||
// it will not index a single field with more than 1024 bytes.
|
|
||||||
// If you're indexing a field that is 2.5MB, it's not really indexing it, it's being skipped.
|
|
||||||
if len(urlTitle2) > 320 {
|
|
||||||
urlTitle2 = urlTitle2[:300] // 为什么要少些, 因为怕无限循环, 因为把padding截了
|
|
||||||
}
|
|
||||||
|
|
||||||
if padding > 1 {
|
if padding > 1 {
|
||||||
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
||||||
}
|
}
|
||||||
@@ -149,7 +139,6 @@ func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int
|
|||||||
|
|
||||||
return urlTitle2
|
return urlTitle2
|
||||||
}
|
}
|
||||||
|
|
||||||
// types == note,notebook,single
|
// types == note,notebook,single
|
||||||
func GetUrTitle(userId string, title string, types string) string {
|
func GetUrTitle(userId string, title string, types string) string {
|
||||||
urlTitle := strings.Trim(title, " ")
|
urlTitle := strings.Trim(title, " ")
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/robfig/revel"
|
||||||
|
|
||||||
|
"github.com/leanote/leanote/app/service"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/lea/memcache"
|
||||||
|
// "github.com/leanote/leanote/app/lea/netutil"
|
||||||
|
"github.com/leanote/leanote/app/lea/html2image"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
// "gopkg.in/mgo.v2"
|
||||||
|
// "encoding/json"
|
||||||
|
// "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var userId = "5295d4c95b1dd58edb4a7f4f"
|
||||||
|
var userIdO = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
var userId3 = "52b43ae4cfeeae33ef073b2b"
|
||||||
|
var userId3O = bson.ObjectIdHex(userId3)
|
||||||
|
|
||||||
|
var toUserId = "52b4376bcfeeae33ef073b21"
|
||||||
|
var toUserIdO = bson.ObjectIdHex(toUserId)
|
||||||
|
|
||||||
|
var notebookId = "52b2d051ea3ba3d3fb35910c"
|
||||||
|
var notebookIdO = bson.ObjectIdHex(notebookId)
|
||||||
|
var notebookId2O = bson.ObjectIdHex("52b2d051ea3ba3d3fb35910b")
|
||||||
|
|
||||||
|
var noteId = "52b2dd34ea3ba3d3fb35910d"
|
||||||
|
var noteIdO = bson.ObjectIdHex(noteId)
|
||||||
|
|
||||||
|
func testNoteService() {
|
||||||
|
println("testNoteService")
|
||||||
|
noteService := &service.NoteService{}
|
||||||
|
note := noteService.GetBlogNote("535f9e6b19807a4c8d000000")
|
||||||
|
LogJ(note)
|
||||||
|
/*
|
||||||
|
_, notes := noteService.SearchNote("go", "52d3e8ac99c37b7f0d000001", 1, 30, "", false, true);
|
||||||
|
LogJ(notes)
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
noteService.AddNote(info.Note{UserId: userIdO,
|
||||||
|
NotebookId: notebookIdO,
|
||||||
|
Title: "life you", Tags: []string{"red", "yellow"}})
|
||||||
|
*/
|
||||||
|
|
||||||
|
noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||||
|
NoteId: bson.ObjectIdHex("52b4531dcfeeae33ef073b33"),
|
||||||
|
Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||||
|
|
||||||
|
// noteService.UpdateNoteContent(userId, userId, "52b2dd34ea3ba3d3fb35910d", "life2---------")
|
||||||
|
|
||||||
|
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||||
|
|
||||||
|
// println(bson.IsObjectIdHex(id))
|
||||||
|
|
||||||
|
// note := noteService.Get(id)
|
||||||
|
// fmt.Println(note)
|
||||||
|
|
||||||
|
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNotebookService() {
|
||||||
|
service := &service.NotebookService{}
|
||||||
|
Log(service.IsBlog("52ccb959bcbf21610d000001"))
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
notebooks := service.GetNotebooks(userId3)
|
||||||
|
LogJ(notebooks)
|
||||||
|
|
||||||
|
// b, _ := json.MarshalIndent(notebooks, "", " ")
|
||||||
|
// fmt.Println(string(b))
|
||||||
|
|
||||||
|
// service.UpdateNotebookTitle("52b2cf9eea3ba3d3fb359108", userId, "JS")
|
||||||
|
|
||||||
|
// service.SortNotebooks(userId, map[string]int{"52b2d051ea3ba3d3fb35910c": 4, "52b2d051ea3ba3d3fb35910b": 3})
|
||||||
|
|
||||||
|
/*
|
||||||
|
service.AddNotebook(info.Notebook{UserId: userId3O,
|
||||||
|
ParentNotebookId: bson.ObjectIdHex("52b43c1fcfeeae33ef073b2e"),
|
||||||
|
Title: "Mac-life",
|
||||||
|
Seq: 0})
|
||||||
|
*/
|
||||||
|
|
||||||
|
println("xxx")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testShareService() {
|
||||||
|
service := &service.ShareService{}
|
||||||
|
|
||||||
|
// service.AddShareNote("52bd127dbcbf216d0b000000", 1, "5295d4c95b1dd58edb4a7f4f", "c@a.com")
|
||||||
|
LogJ(service.ListNoteShareUserInfo("52cd11a1bcbf215680000000", "5295d4c95b1dd58edb4a7f4f"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
service.AddShareNotebook(info.ShareNotebook{UserId: userId3O, ToUserId: userIdO,
|
||||||
|
NotebookId: bson.ObjectIdHex("52b43c38cfeeae33ef073b30")})
|
||||||
|
*/
|
||||||
|
|
||||||
|
notebooks,_ := service.GetShareNotebooks(userId)
|
||||||
|
LogJ(notebooks)
|
||||||
|
|
||||||
|
// noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||||
|
// NoteId: bson.ObjectIdHex("52b2dd34ea3ba3d3fb35910d"), Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||||
|
|
||||||
|
|
||||||
|
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||||
|
|
||||||
|
// println(bson.IsObjectIdHex(id))
|
||||||
|
|
||||||
|
// note := noteService.Get(id)
|
||||||
|
// fmt.Println(note)
|
||||||
|
|
||||||
|
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAuthService() {
|
||||||
|
userService := &service.UserService{}
|
||||||
|
LogJ(userService.GetUserInfo("52d26b4e99c37b609a000001"))
|
||||||
|
// userService.AddUser(info.User{UserId: bson.ObjectIdHex("52d26b4e99c37b609a000001"), Email: "leanote@leanote.com", Pwd:"abc"})
|
||||||
|
return;
|
||||||
|
|
||||||
|
authService := &service.AuthService{}
|
||||||
|
authService.Register("f@a.com", "abc")
|
||||||
|
|
||||||
|
// fmt.Println(authService.LogonGetUserInfo("a@a.com", "abc"))
|
||||||
|
|
||||||
|
// noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||||
|
// NoteId: bson.ObjectIdHex("52b2dd34ea3ba3d3fb35910d"), Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||||
|
|
||||||
|
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||||
|
|
||||||
|
// println(bson.IsObjectIdHex(id))
|
||||||
|
|
||||||
|
// note := noteService.Get(id)
|
||||||
|
// fmt.Println(note)
|
||||||
|
|
||||||
|
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTagService() {
|
||||||
|
service := &service.TagService{}
|
||||||
|
// service.AddTags("5295d4c95b1dd58edb4a7f4f", []string{"life", "blue", "yellow"})
|
||||||
|
// service.AddTags("5295d4c95b1dd58edb4a7f4f", []string{"what", "can", "make"})
|
||||||
|
LogJ(service.GetTags("5295d4c95b1dd58edb4a7f4f"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHtml2Image() {
|
||||||
|
start := time.Now()
|
||||||
|
Log("start...")
|
||||||
|
// TestFillString()
|
||||||
|
|
||||||
|
|
||||||
|
html2image.ToImage("uid", "username", "noteId", "开发一款属于自己的编程语言,开发一款属于自己的编程语言听起来是不是很酷?", `
|
||||||
|
<div class="each-post">
|
||||||
|
<p>
|
||||||
|
一个合格的 Techspace 需要有足够专业的器材、场地和资源,你可以和你的团队在里面进行激光切割、快速贴片甚至加工木材等操作,在相对独立的空间内又能同周围的同道友人互相激发切磋。国内现有的 Techspace 没几家,不久前我去深圳特地拜访了当地的 Techspace,很喜欢那里的氛围,希望国内其他地方也能有更多这类空间供创客发挥。
|
||||||
|
假如你有一个比较成型的想法,想在硬件领域做点事情,核心团队也基本组好,硬件软件交互基本都有专人了。</p>
|
||||||
|
<p><a>这时候你的首要目标</a>,就是找个地方,按照你的计划,尽早做出一个可用的原型。Techspace可能是一个合适的地方。
|
||||||
|
一个合格的 Techspace 需要有足够专业的器材、场地和资源,你可以和你的团队在里面进行激光切割、快速贴片甚至加工木材等操作,在相对独立的空间内又能同周围的同道友人互相激发切磋。国内现有的 Techspace 没几家,不久前我去深圳特地拜访了当地的 Techspace,很喜欢那里的氛围,希望国内其他地方也能有更多这类空间供创客发挥。
|
||||||
|
深圳 Techspace 位于工业区,园区内有奥迪、BMW 等企业的厂房,在大门口我停下来问保安,M10 栋在哪里?保安答,去 Techspace?最里面靠右手那栋。惊叹于保安的机智,我也在想,莫非有许多朋友都慕名来到这巨大园区寻访 Techspace?
|
||||||
|
穿过一片工业区里的高楼和各种建筑材料
|
||||||
|
</p>
|
||||||
|
<!--
|
||||||
|
<pre class="">cd jpeg-9a/<br>./configure --enable-shared --enable-static
|
||||||
|
make<br>make --- install</pre>
|
||||||
|
<p>
|
||||||
|
life you can, !!@kk
|
||||||
|
</p>
|
||||||
|
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
`, "/Users/life/Desktop/a.png")
|
||||||
|
fmt.Printf("time cost %v\n", time.Now().Sub(start))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLea() {
|
||||||
|
names := ListDir("/Users/life/Documents/Go/package/src/leanote")
|
||||||
|
fmt.Println(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
revel.BasePath = "/Users/life/Documents/Go/package/src/leanote"
|
||||||
|
// testLea();
|
||||||
|
|
||||||
|
// a, b := SplitFilename("http://ab/c/a.gif#??")
|
||||||
|
// println(a)
|
||||||
|
// println(b)
|
||||||
|
|
||||||
|
// path, ok := netutil.WriteUrl("http://a.36krcnd.com/photo/2014/9bd1a07c0973d79ca05ad13c3c2e16b8.png!slider", "/tmp")
|
||||||
|
// println(path)
|
||||||
|
// testHtml2Image();
|
||||||
|
|
||||||
|
// println(IsObjectId("52d26b4e99c37b609a000001"))
|
||||||
|
|
||||||
|
// b := `请点击链接验证邮箱: <a href="">http://leanote.com/user/activeEmail?token=d8ca086cce5550a6227f9dc84dbac09d</a>. 48小时后过期.`
|
||||||
|
// SendEmail("lifephp@gmail.com", "leanote-验证邮箱", "验证邮", b)
|
||||||
|
|
||||||
|
//_, err := mgo.Dial("mongodb://leanote:nKFAkxKnWkEQy8Vv2LlM@115.28.133.226:27017/leanote")
|
||||||
|
|
||||||
|
// testNotebookService();
|
||||||
|
// testNoteService();
|
||||||
|
// testShareService()
|
||||||
|
// testAuthService()
|
||||||
|
|
||||||
|
// testTagService();
|
||||||
|
/*
|
||||||
|
filename := "你好59.26.png"
|
||||||
|
ext := SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||||
|
ext = strings.ToLower(ext)
|
||||||
|
print(ext)
|
||||||
|
52d26ab199c37b5f80000001
|
||||||
|
|
||||||
|
Log(bson.NewObjectId())
|
||||||
|
Log(bson.NewObjectId())
|
||||||
|
Log(bson.NewObjectId())
|
||||||
|
|
||||||
|
*/
|
||||||
|
// Log(TransferExt("/你好a/b/a.gif", ".jpg"))
|
||||||
|
// TransToGif("/Users/life/Desktop/a2.png", 0, false)
|
||||||
|
|
||||||
|
// Log(IsUsername("xx**x"))
|
||||||
|
|
||||||
|
/*
|
||||||
|
memcache.Set("xx", map[string]string{"A":"you"}, 0)
|
||||||
|
a := memcache.Get("xx")
|
||||||
|
Log(a)
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"github.com/leanote/leanote/app/db"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/leanote/leanote/app/service"
|
|
||||||
// "gopkg.in/mgo.v2"
|
|
||||||
// "fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
db.Init("mongodb://localhost:27017/leanote", "leanote")
|
|
||||||
service.InitService()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试登录
|
|
||||||
func TestAuth(t *testing.T) {
|
|
||||||
_, err := service.AuthS.Login("admin", "abc123")
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Admin User Auth Error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"github.com/leanote/leanote/app/db"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
// "github.com/leanote/leanote/app/service"
|
|
||||||
// "gopkg.in/mgo.v2"
|
|
||||||
// "fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDBConnect(t *testing.T) {
|
|
||||||
db.Init("mongodb://localhost:27017/leanote", "leanote")
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package tests
|
|
||||||
func a() {
|
|
||||||
}
|
|
||||||
@@ -11,3 +11,20 @@
|
|||||||
<script src="/public/admin/js/artDialog/jquery.artDialog.js?skin=default"></script>
|
<script src="/public/admin/js/artDialog/jquery.artDialog.js?skin=default"></script>
|
||||||
<script src="/public/js/common.js"></script>
|
<script src="/public/js/common.js"></script>
|
||||||
<script src="/public/admin/js/admin.js"></script>
|
<script src="/public/admin/js/admin.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var pathname = location.pathname; // admin/t
|
||||||
|
var search = location.search; // ?t=xxx, 如果有?page呢
|
||||||
|
var fullPath = pathname;
|
||||||
|
if(search.indexOf("?t=") >= 0) {
|
||||||
|
var fullPath = pathname + search; // /admin/t?t=xxx
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#nav > li").removeClass("active");
|
||||||
|
// 自己
|
||||||
|
var $thisLi = $('#nav a[href^="' + fullPath + '"]').parent();
|
||||||
|
$thisLi.addClass("active");
|
||||||
|
// 父也active
|
||||||
|
$thisLi.parent().parent().addClass('active');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
<li id="adminUserNav">
|
<li id="adminUserNav">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<i class="fa fa-users icon">
|
<i class="fa fa-users icon">
|
||||||
@@ -156,7 +157,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/t?t=setting/share_note">
|
<a href="/admin/t?t=setting/shareNote">
|
||||||
<span>
|
<span>
|
||||||
Register Share Note
|
Register Share Note
|
||||||
</span>
|
</span>
|
||||||
@@ -170,15 +171,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="/admin/t?t=setting/export_pdf">
|
|
||||||
<span>
|
|
||||||
Export PDF
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -237,14 +229,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="/admin/t?t=upgrade/beta2">
|
<a href="/admin/t?t=upgrade/beta2">
|
||||||
<span>
|
<span>
|
||||||
v1.0-beta to v1.0-beta.2
|
v1.0-beta to v1.0-beta2
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/admin/t?t=upgrade/beta3">
|
|
||||||
<span>
|
|
||||||
v1.0-beta.2/3 to v1.0-beta.4
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
{{template "admin/top.html" .}}
|
|
||||||
<div class="m-b-md"> <h3 class="m-b-none">Export PDF</h3></div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<form id="add_user_form">
|
|
||||||
<section class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Wkhtmltopdf Binary Path</label>
|
|
||||||
<input type="text" class="form-control" placeholder="/usr/local/bin/wkhtmltopdf" name="path" value="{{.str.exportPdfBinPath}}">
|
|
||||||
Leanote use <a target="_blank" href="http://wkhtmltopdf.org">wkhtmltopdf</a> to export pdf. You should install it on your server.
|
|
||||||
<br />
|
|
||||||
Please input the path that wkhtmltopdf installed, e.g. <code>/usr/local/bin/wkhtmltopdf</code>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="panel-footer text-right bg-light lter">
|
|
||||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
|
||||||
</footer>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{template "admin/footer.html" .}}
|
|
||||||
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
init_validator("#add_user_form");
|
|
||||||
|
|
||||||
$("#submit").click(function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
var t = this;
|
|
||||||
if($("#add_user_form").valid()) {
|
|
||||||
$(t).button('loading');
|
|
||||||
ajaxPost("/adminSetting/exportPdf", getFormJsonData("add_user_form"), function(ret){
|
|
||||||
$(t).button('reset')
|
|
||||||
if(!ret.Ok) {
|
|
||||||
art.alert(ret.Msg)
|
|
||||||
} else {
|
|
||||||
art.tips("Success");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{template "admin/end.html" .}}
|
|
||||||
File renamed without changes.
@@ -46,7 +46,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="hidden-xs">
|
<li class="hidden-xs">
|
||||||
<a href="/blog" class="dk" target="_blank">
|
<a href="/blog/admin" class="dk" target="_blank">
|
||||||
My Blog
|
My Blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{{template "admin/top.html" .}}
|
{{template "admin/top.html" .}}
|
||||||
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta to v1.0-beta.2</h3></div>
|
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta to v1.0-beta2</h3></div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<footer class="panel-footer text-right bg-light lter">
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade to v1.0-beta.2</button>
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade</button>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
@@ -31,7 +31,6 @@ $(function() {
|
|||||||
$("#submit").click(function(e){
|
$("#submit").click(function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var t = this;
|
var t = this;
|
||||||
art.confirm("Are you sure to upgrade to v1.0-beta.2", function() {
|
|
||||||
$(t).button('loading');
|
$(t).button('loading');
|
||||||
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
||||||
$(t).button('reset')
|
$(t).button('reset')
|
||||||
@@ -43,7 +42,6 @@ $("#submit").click(function(e){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{template "admin/end.html" .}}
|
{{template "admin/end.html" .}}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{{template "admin/top.html" .}}
|
|
||||||
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta.2/3 to v1.0-beta.4</h3></div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<form id="add_user_form">
|
|
||||||
<section class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
Current Version: <span class="label label-success">leanote v{{.version}}</span>
|
|
||||||
<ul>
|
|
||||||
<li>Api support (Enable Leanote Desktop App to connect server))</li>
|
|
||||||
<li>Update tags</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<footer class="panel-footer text-right bg-light lter">
|
|
||||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade to v1.0-beta.4</button>
|
|
||||||
</footer>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{template "admin/footer.html" .}}
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#submit").click(function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var t = this;
|
|
||||||
art.confirm("Are you sure to upgrade to v1.0-beta.4 ? Please don't try to upgrade twice.", function() {
|
|
||||||
$(t).button('loading');
|
|
||||||
ajaxPost("/adminUpgrade/UpgradeBeta3ToBeta4", {}, function(ret){
|
|
||||||
$(t).button('reset')
|
|
||||||
if(!ret.Ok) {
|
|
||||||
art.alert(ret.Msg)
|
|
||||||
} else {
|
|
||||||
art.tips("Success");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{template "admin/end.html" .}}
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<div id="boxFooter">
|
<div id="boxFooter">
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<div id="boxFooter">
|
<div id="boxFooter">
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>{{.title}}</title>
|
|
||||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
|
||||||
<link id="styleLink" href="/css/pdf.css" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
table th, table td {
|
|
||||||
padding: 6px 13px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
table th {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tr {
|
|
||||||
background-color: #fff;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
table tr:nth-child(2n) {
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
}
|
|
||||||
.mce-item-table, .mce-item-table td, .mce-item-table th, .mce-item-table caption {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-collapse: collapse;
|
|
||||||
padding: 6px 13px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="content">
|
|
||||||
<h1 class="title tex2jax_ignore">
|
|
||||||
{{if .blog.Title}}
|
|
||||||
{{.blog.Title}}
|
|
||||||
{{else}}
|
|
||||||
Untitled
|
|
||||||
{{end}}
|
|
||||||
</h1>
|
|
||||||
<div class="created-time">
|
|
||||||
<!--
|
|
||||||
{{ if .userBlog.Logo}}
|
|
||||||
<img src="{{.userBlog.Logo}}" id="logo">
|
|
||||||
{{else}}
|
|
||||||
<img src="{{$.siteUrl}}/images/blog/default_avatar.png" id="logo">
|
|
||||||
{{end}}
|
|
||||||
{{.userInfo.Username}}
|
|
||||||
-->
|
|
||||||
{{if .blog.Tags}}
|
|
||||||
<img src="{{$.siteUrl}}/images/blog/tag.png" id="tag">
|
|
||||||
{{blogTagsForExport $ .blog.Tags}}
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="desc">
|
|
||||||
{{if .blog.IsMarkdown }}
|
|
||||||
<div id="markdownContent" style="display: none">
|
|
||||||
<!-- 用textarea装html, 防止得到的值失真 -->
|
|
||||||
<textarea>
|
|
||||||
{{.content | raw}}
|
|
||||||
</textarea>
|
|
||||||
</div>
|
|
||||||
<div id="parsedContent">
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{.content | raw}}
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<div id="footer">
|
|
||||||
<p class="split"></p>
|
|
||||||
<a href="http://leanote.com"><img src="{{.siteUrl}}/images/logo/leanote_icon_blue.png" id="leanote_logo"/></a>
|
|
||||||
<p>
|
|
||||||
<a href="http://leanote.com">Leanote</a>
|
|
||||||
<br />
|
|
||||||
<a href="http://leanote.com/service">Upgrade Account</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script src="{{.siteUrl}}/js/jquery-1.9.0.min.js"></script>
|
|
||||||
|
|
||||||
<link href="{{.siteUrl}}/public/mdeditor/editor/google-code-prettify/prettify.css" type="text/css" rel="stylesheet">
|
|
||||||
<script src="{{.siteUrl}}/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function ok() {
|
|
||||||
setTimeout(function() {
|
|
||||||
window.status = 'done';
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{if not .blog.IsMarkdown }}
|
|
||||||
<script>
|
|
||||||
$("pre").addClass("prettyprint");
|
|
||||||
prettyPrint();
|
|
||||||
ok();
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .blog.IsMarkdown }}
|
|
||||||
<script src="/public/libs/md2html/md2html_for_export.js"></script>
|
|
||||||
<script>
|
|
||||||
var content = $.trim($("#markdownContent textarea").val());
|
|
||||||
md2Html(content, $("#parsedContent"), function(html) {
|
|
||||||
$("pre").addClass("prettyprint");
|
|
||||||
prettyPrint();
|
|
||||||
ok();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,18 @@
|
|||||||
<a href="http://weibo.com/leanotecom" target="_blank"><i class="fa fa-weibo"></i></a>
|
<a href="http://weibo.com/leanotecom" target="_blank"><i class="fa fa-weibo"></i></a>
|
||||||
<br />
|
<br />
|
||||||
leanote@leanote.com
|
leanote@leanote.com
|
||||||
<br />
|
<div id="beian">
|
||||||
Copyright © 2014-2015 <a href="https://leanote.com">Leanote</a>
|
<a href="http://www.miibeian.gov.cn" target="_blank">沪ICP备14006011号</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<i class="fa fa-globe fa-3x icon-muted"></i>
|
<i class="fa fa-globe fa-3x icon-muted"></i>
|
||||||
<h2>Join Us</h2>
|
<h2>Join Us</h2>
|
||||||
<a href="https://github.com/leanote/leanote">Github Leanote</a>
|
<a href="https://github.com/leanote/leanote">github leanote</a>
|
||||||
<br />
|
<br />
|
||||||
QQ Group: 158716820, 158716820
|
QQ Group: 158716820
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-leanote">Proudly powered by <a href="https://leanote.com">Leanote</a></div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
+18
-22
@@ -5,7 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="keywords" content="leanote,leanote.com">
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
<meta name="description" content="Leanote, {{msg $ "moto"}}">
|
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||||
<meta name="author" content="leanote">
|
<meta name="author" content="leanote">
|
||||||
<title>{{.title}}</title>
|
<title>{{.title}}</title>
|
||||||
|
|
||||||
@@ -37,33 +37,30 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
<div id="lang">
|
|
||||||
<a data-lang="en-us">English</a>
|
|
||||||
<a data-lang="fr-fr">Français</a>
|
|
||||||
<a data-lang="zh-cn">简体中文</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-left">
|
<ul class="nav navbar-nav navbar-left">
|
||||||
<li><a href="/index#" data-target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||||
|
<!--
|
||||||
|
<li><a href="/index#aboutLeanote" target="#aboutLeanote" class="smooth-scroll">{{msg . "aboutLeanote"}}</a> </li>
|
||||||
|
-->
|
||||||
|
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
||||||
|
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
||||||
<li style="position: relative; margin-right: 3px;">
|
<li style="position: relative; margin-right: 3px;">
|
||||||
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
||||||
|
<div class="red-circle" style=""></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><a id="leanoteBlog" href="http://lea.leanote.com" target="_blank" title="Lea++, leanote blog platform" class="">Lea++</a></li>
|
|
||||||
<li><a id="leanoteApp" href="http://app.leanote.com" target="_blank" title="Leanote App" class="">{{msg . "desktopApp"}}</a></li>
|
|
||||||
<li>
|
|
||||||
<a href="http://leanote.org#donate" target="_blank" class="">{{msg . "donate"}}</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><a href="http://leanote.org" target="_blank" title="leanote.org" class="">leanote.org</a></li>
|
|
||||||
|
|
||||||
{{if .userInfo.Email}}
|
|
||||||
<li id="loginBtns">
|
<li id="loginBtns">
|
||||||
|
{{if .userInfo.Email}}
|
||||||
{{msg . "hi"}}, {{.userInfo.Username}}
|
{{msg . "hi"}}, {{.userInfo.Username}}
|
||||||
<a href="{{$.noteUrl}}">{{msg . "myNote"}}</a>
|
<a href="{{$.noteUrl}}">{{msg . "myNote"}}</a>
|
||||||
<a href="/logout">{{msg . "logout"}}</a>
|
<a href="/logout">{{msg . "logout"}}</a>
|
||||||
</li>
|
{{else}}
|
||||||
|
<a href="/login">{{msg . "login"}}</a>
|
||||||
|
{{if .openRegister}}
|
||||||
|
<a href="/register" class="btn-register">{{msg . "register"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,11 +90,10 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul id="blogNav" class="pull-right">
|
<ul id="blogNav" class="pull-right">
|
||||||
<li><a href="#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||||
<li><a href="#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
||||||
<li><a href="#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
||||||
<li><a id="leanoteBlog" href="{{.leaUrl}}/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
|
<li><a id="leanoteBlog" href="{{.leaUrl}}/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
|
||||||
|
|
||||||
<li style="position: relative; margin-right: 3px;">
|
<li style="position: relative; margin-right: 3px;">
|
||||||
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
||||||
<div style="position: absolute;
|
<div style="position: absolute;
|
||||||
|
|||||||
+81
-37
@@ -1,22 +1,26 @@
|
|||||||
{{template "home/header.html" .}}
|
{{template "home/header.html" .}}
|
||||||
|
<style>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<section>
|
<section>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>Leanote, {{msg . "moto"}}</h2>
|
<h2>leanote, {{msg . "moto"}}</h2>
|
||||||
<p>{{msg . "moto3"}}</p>
|
<p>{{msg . "moto3"}}</p>
|
||||||
<p>{{msg . "moto2"}}</p>
|
<p>{{msg . "moto2"}}</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a class="btn btn-default btn-primary" href="/register">{{msg . "register"}}</a>
|
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||||
|
|
||||||
|
|
||||||
{{if not .userInfo.UserId}}
|
|
||||||
<a class="btn btn-default" href="/login">{{msg . "login"}}</a>
|
|
||||||
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||||
|
{{if .openRegister}}
|
||||||
|
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
|
||||||
|
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -25,23 +29,13 @@
|
|||||||
<div class="img-header">
|
<div class="img-header">
|
||||||
<img src="/images/home/mac-btns.png"/>
|
<img src="/images/home/mac-btns.png"/>
|
||||||
</div>
|
</div>
|
||||||
<div id="webSliderContainer">
|
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||||
<img class="web-slider" data-text="Default theme - markdown" src="/images/slider/v2/default_markdown.png"/>
|
|
||||||
<img class="web-slider hide-img" data-text="Default theme - rich editor" src="/images/slider/v2/simple_tinymce.png"/>
|
|
||||||
<img class="web-slider hide-img" data-text="Simple theme - markdown" src="/images/slider/v2/simple_markdown.png"/>
|
|
||||||
<img class="web-slider hide-img" data-text="Writting mode" src="/images/slider/v2/writting.png"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="slider-desc"><span id="webText">Default theme - markdown</span></div>
|
|
||||||
<div class="mobile">
|
<div class="mobile">
|
||||||
<div class="mobile-header">
|
<div class="mobile-header">
|
||||||
<img src="/images/home/mac-dot.png" />
|
<img src="/images/home/mac-dot.png" />
|
||||||
</div>
|
</div>
|
||||||
<div id="mobileSliderContainer">
|
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||||
<img class="mobile-slider" data-text="Mobile" src="/images/slider/v2/mobile_simple_list.png" />
|
|
||||||
<img class="mobile-slider hide-img" data-text="Mobile markdown" src="/images/slider/v2/mobile_markdown.png" />
|
|
||||||
</div>
|
|
||||||
<div class="slider-desc mobile-text"><span id="mobileText">Default theme - markdown</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -52,10 +46,6 @@
|
|||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<h3>{{msg . "knowledge"}}</h3>
|
<h3>{{msg . "knowledge"}}</h3>
|
||||||
<p>{{msg . "knowledgeInfo"}}</p>
|
<p>{{msg . "knowledgeInfo"}}</p>
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<h3>{{msg . "blog"}}</h3>
|
|
||||||
<p>{{msg . "blogInfo"}}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<h3>{{msg . "share"}}</h3>
|
<h3>{{msg . "share"}}</h3>
|
||||||
@@ -65,27 +55,81 @@
|
|||||||
<h3>{{msg . "cooperation"}}</h3>
|
<h3>{{msg . "cooperation"}}</h3>
|
||||||
<p>{{msg . "cooperationInfo"}}</p>
|
<p>{{msg . "cooperationInfo"}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "blog"}}</h3>
|
||||||
|
<p>{{msg . "blogInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container" id="download">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:300px; margin:auto; padding: 10px;">
|
||||||
|
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||||
|
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container" id="donate">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:500px; margin:auto; padding: 10px;">
|
||||||
|
<p>
|
||||||
|
您可以通过支付宝向leanote捐赠, 所捐赠的钱将用来leanote开发.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
支付宝账号: <b>pay@leanote.com</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
或使用支付宝扫以下二维码捐赠:
|
||||||
|
</p>
|
||||||
|
<p style="text-align: center">
|
||||||
|
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||||
|
border: 2px solid #eee;
|
||||||
|
border-radius: 10px;"/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
我们会定期将捐赠名单发布在 <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">捐赠列表</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
感谢您对leanote的支持!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
有任何疑问, 建议或需其它服务或支持, 欢迎联系 <code>leanote@leanote.com</code> 或加入官方QQ群: <code>158716820</code> 谢谢!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{template "home/footer.html"}}
|
{{template "home/footer.html"}}
|
||||||
|
|
||||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
<script src="/js/bootstrap.js"></script>
|
<script src="/js/bootstrap.js"></script>
|
||||||
<script>
|
|
||||||
var lang = '{{.locale}}';
|
|
||||||
</script>
|
|
||||||
<script src="/js/home/index.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var _hmt = _hmt || [];
|
$(function() {
|
||||||
(function() {
|
/*
|
||||||
var hm = document.createElement("script");
|
var u = navigator.userAgent;
|
||||||
hm.src = "//hm.baidu.com/hm.js?d0c988e37b452b3bf1220d45b30f2de2";
|
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||||
var s = document.getElementsByTagName("script")[0];
|
if(isMobile || $("body").width() < 600) {
|
||||||
s.parentNode.insertBefore(hm, s);
|
location.href = "/mobile/index";
|
||||||
})();
|
}
|
||||||
|
*/
|
||||||
|
// 平滑滚动
|
||||||
|
$(".smooth-scroll").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var t = $(this).attr("target");
|
||||||
|
var targetOffset = $(t).offset().top - 80;
|
||||||
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
{{template "home/header.html" .}}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<section>
|
||||||
|
<div class="header">
|
||||||
|
<h2>leanote, {{msg . "moto"}}</h2>
|
||||||
|
<p>{{msg . "moto3"}}</p>
|
||||||
|
<p>
|
||||||
|
Knowledge, Blog, Sharing, Cooperation... all in leanote
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||||
|
|
||||||
|
|
||||||
|
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||||
|
{{if .openRegister}}
|
||||||
|
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
|
||||||
|
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview" style="position: relative;">
|
||||||
|
<div>
|
||||||
|
<div class="img-header">
|
||||||
|
<img src="/images/home/mac-btns.png"/>
|
||||||
|
</div>
|
||||||
|
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||||
|
</div>
|
||||||
|
<div class="mobile">
|
||||||
|
<div class="mobile-header">
|
||||||
|
<img src="/images/home/mac-dot.png" />
|
||||||
|
</div>
|
||||||
|
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="container" id="aboutLeanote">
|
||||||
|
<h2>{{msg . "aboutLeanote"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "knowledge"}}</h3>
|
||||||
|
<p>{{msg . "knowledgeInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "share"}}</h3>
|
||||||
|
<p>{{msg . "shareInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "cooperation"}}</h3>
|
||||||
|
<p>{{msg . "cooperationInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "blog"}}</h3>
|
||||||
|
<p>{{msg . "blogInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="download">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:300px; margin:auto; padding: 10px;">
|
||||||
|
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||||
|
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="donate">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:500px; margin:auto; padding: 10px;">
|
||||||
|
<p>
|
||||||
|
You can use <a href="http://alipay.com">alipay</a> to donate us, The donated money will be used to develop leanote.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Alipay Account: <b>pay@leanote.com</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Or you can use alipay app to scan the code to donate us:
|
||||||
|
</p>
|
||||||
|
<p style="text-align: center">
|
||||||
|
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||||
|
border: 2px solid #eee;
|
||||||
|
border-radius: 10px; width: 200px;"/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The donation list will be published at <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">Donation List</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Thanks for your support!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
Any questions, suggestions or need more supports, you are welcomed to contact us via <code>leanote@leanote.com</code> or the QQ Group <code>158716820</code> Thanks!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "home/footer.html"}}
|
||||||
|
|
||||||
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
/*
|
||||||
|
var u = navigator.userAgent;
|
||||||
|
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||||
|
if(isMobile || $("body").width() < 600) {
|
||||||
|
location.href = "/mobile/index";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// 平滑滚动
|
||||||
|
$(".smooth-scroll").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var t = $(this).attr("target");
|
||||||
|
var targetOffset = $(t).offset().top - 80;
|
||||||
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
{{template "home/header.html" .}}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<section>
|
||||||
|
<div class="header">
|
||||||
|
<h2>leanote, {{msg . "moto"}}</h2>
|
||||||
|
<p>{{msg . "moto3"}}</p>
|
||||||
|
<p>{{msg . "moto2"}}</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||||
|
|
||||||
|
|
||||||
|
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||||
|
{{if .openRegister}}
|
||||||
|
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
|
||||||
|
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview" style="position: relative;">
|
||||||
|
<div>
|
||||||
|
<div class="img-header">
|
||||||
|
<img src="/images/home/mac-btns.png"/>
|
||||||
|
</div>
|
||||||
|
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||||
|
</div>
|
||||||
|
<div class="mobile">
|
||||||
|
<div class="mobile-header">
|
||||||
|
<img src="/images/home/mac-dot.png" />
|
||||||
|
</div>
|
||||||
|
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="container" id="aboutLeanote">
|
||||||
|
<h2>{{msg . "aboutLeanote"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "knowledge"}}</h3>
|
||||||
|
<p>{{msg . "knowledgeInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "share"}}</h3>
|
||||||
|
<p>{{msg . "shareInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "cooperation"}}</h3>
|
||||||
|
<p>{{msg . "cooperationInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<h3>{{msg . "blog"}}</h3>
|
||||||
|
<p>{{msg . "blogInfo"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="download">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:300px; margin:auto; padding: 10px;">
|
||||||
|
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||||
|
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="donate">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:500px; margin:auto; padding: 10px;">
|
||||||
|
<p>
|
||||||
|
您可以通过<a href="http://alipay.com">支付宝</a>向leanote捐赠, 所捐赠的款项将用于开发leanote.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
支付宝账号: <b>pay@leanote.com</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
或使用支付宝扫以下二维码捐赠:
|
||||||
|
</p>
|
||||||
|
<p style="text-align: center">
|
||||||
|
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||||
|
border: 2px solid #eee;
|
||||||
|
border-radius: 10px; width: 200px;"/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
我们会定期将捐赠名单发布在 <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">捐赠列表</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
感谢您对leanote的支持!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
有任何疑问, 建议或需其它服务或支持, 欢迎联系 <code>leanote@leanote.com</code> 或加入官方QQ群: <code>158716820</code> 谢谢!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "home/footer.html"}}
|
||||||
|
|
||||||
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
/*
|
||||||
|
var u = navigator.userAgent;
|
||||||
|
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||||
|
if(isMobile || $("body").width() < 600) {
|
||||||
|
location.href = "/mobile/index";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// 平滑滚动
|
||||||
|
$(".smooth-scroll").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var t = $(this).attr("target");
|
||||||
|
var targetOffset = $(t).offset().top - 80;
|
||||||
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 2264 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user