Compare commits
327 Commits
1.0-beta.4
...
2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2585bf695 | ||
|
|
3b9bc687c4 | ||
|
|
2db182db1b | ||
|
|
f3e1eb6c3f | ||
|
|
956e1ba2bb | ||
|
|
f294fa4124 | ||
|
|
cabf89f9b8 | ||
|
|
d183cd5a77 | ||
|
|
000dfea92d | ||
|
|
a53398ebb4 | ||
|
|
b23592229a | ||
|
|
584bde247e | ||
|
|
6774392807 | ||
|
|
964cf1a750 | ||
|
|
52128e6453 | ||
|
|
032470c3df | ||
|
|
a8dd578624 | ||
|
|
f49624d3eb | ||
|
|
816af11db2 | ||
|
|
eda03f0aa4 | ||
|
|
6a06511405 | ||
|
|
15d8ebdc0f | ||
|
|
5dc929c4c0 | ||
|
|
a4d6a99fee | ||
|
|
15d3b847cb | ||
|
|
065ac99942 | ||
|
|
08ec359b93 | ||
|
|
2f81c04f41 | ||
|
|
e8bff79425 | ||
|
|
4ca8e8cd83 | ||
|
|
c0cc08a3c2 | ||
|
|
d32a6dd277 | ||
|
|
8bacc15309 | ||
|
|
8a3f24b9c6 | ||
|
|
2a7d1fe7b5 | ||
|
|
9a05ffcd8f | ||
|
|
aa95e680f9 | ||
|
|
874ab69c34 | ||
|
|
d43f5fd7ab | ||
|
|
6a048f0d9a | ||
|
|
cb3681f651 | ||
|
|
dfd7159401 | ||
|
|
929ec975da | ||
|
|
e826dc7b93 | ||
|
|
629a49e54b | ||
|
|
6ebedf94f0 | ||
|
|
a07bb25128 | ||
|
|
a007b89ebb | ||
|
|
cc4b003503 | ||
|
|
091922175a | ||
|
|
371c93912d | ||
|
|
27221acda7 | ||
|
|
5db724e80b | ||
|
|
14265d9de4 | ||
|
|
5c9e95ed60 | ||
|
|
2fc97ed42d | ||
|
|
45cca30cec | ||
|
|
31167b6aaf | ||
|
|
139906b9d6 | ||
|
|
a9d49369e2 | ||
|
|
303e0da5c0 | ||
|
|
ff5523bfaa | ||
|
|
063dd0140d | ||
|
|
c52d388d5d | ||
|
|
18bcdb48af | ||
|
|
db8f132507 | ||
|
|
439d5212b0 | ||
|
|
88e2320027 | ||
|
|
659a4e590a | ||
|
|
ab7f2386e0 | ||
|
|
ec82ff18f2 | ||
|
|
f3f00626e6 | ||
|
|
80fbb56426 | ||
|
|
a5c952882f | ||
|
|
973b452a7e | ||
|
|
25bcd21ea9 | ||
|
|
09de5e1e83 | ||
|
|
15b0ef21ff | ||
|
|
9cf9ded855 | ||
|
|
7af433ebaf | ||
|
|
67b608b324 | ||
|
|
2aa3f5a654 | ||
|
|
f5538218bd | ||
|
|
0e3bdd177c | ||
|
|
12520cc09d | ||
|
|
cb67892124 | ||
|
|
45c09c9a26 | ||
|
|
20951ea2dd | ||
|
|
530f2368da | ||
|
|
e685a99628 | ||
|
|
bfc5acc3ee | ||
|
|
551e3d965e | ||
|
|
7c479b5595 | ||
|
|
b135f9717f | ||
|
|
08ae37cae0 | ||
|
|
315a7bbe62 | ||
|
|
e173b18ddc | ||
|
|
dcc25df679 | ||
|
|
c561dec14c | ||
|
|
43e8f2e701 | ||
|
|
dd9952c453 | ||
|
|
19517dd634 | ||
|
|
a5b006aae7 | ||
|
|
90bd07cdcc | ||
|
|
92576e9239 | ||
|
|
c58e6874c2 | ||
|
|
cfebf00cf1 | ||
|
|
19be0990da | ||
|
|
3f27e4b0d4 | ||
|
|
4710fb6686 | ||
|
|
28324c0178 | ||
|
|
f270ade8d7 | ||
|
|
3b3e665a9f | ||
|
|
bfa85e2d34 | ||
|
|
fcf270a521 | ||
|
|
eba113c73c | ||
|
|
41f63156ea | ||
|
|
f54fe397c3 | ||
|
|
6f157289d3 | ||
|
|
65792d020c | ||
|
|
926882dce6 | ||
|
|
f834f469fc | ||
|
|
06d42c36f0 | ||
|
|
17d513a9de | ||
|
|
8cc00c1f66 | ||
|
|
cb433d9392 | ||
|
|
86ca1efd11 | ||
|
|
263f978c54 | ||
|
|
c8af7eda5d | ||
|
|
3724811802 | ||
|
|
10ff48267f | ||
|
|
cd0913aec0 | ||
|
|
f8d4c2ef20 | ||
|
|
f16b5e816e | ||
|
|
9a9968760a | ||
|
|
b1f36dfbf1 | ||
|
|
bc0e09f222 | ||
|
|
0dab71e72b | ||
|
|
10f23c19ab | ||
|
|
bba57ea302 | ||
|
|
f052117989 | ||
|
|
df4ec53647 | ||
|
|
a7eaf6114a | ||
|
|
b25bf0e16c | ||
|
|
d13447e6d0 | ||
|
|
6a1e84da0c | ||
|
|
51aeb7d46e | ||
|
|
2dbd025768 | ||
|
|
d52d80d529 | ||
|
|
2000bc585b | ||
|
|
8301a1e515 | ||
|
|
bee65eb36d | ||
|
|
78199583b0 | ||
|
|
28d5678349 | ||
|
|
e97c468f6e | ||
|
|
5d18554542 | ||
|
|
3ff0a9e09c | ||
|
|
6a753682b7 | ||
|
|
ce491e62c3 | ||
|
|
e4b847b731 | ||
|
|
a12b285a35 | ||
|
|
7f0ada8016 | ||
|
|
bac5ab4d79 | ||
|
|
b362406819 | ||
|
|
9e2edbb987 | ||
|
|
7809d00787 | ||
|
|
cba69444a8 | ||
|
|
5e02816c09 | ||
|
|
20b085aeae | ||
|
|
0f5e683a4f | ||
|
|
e134ca7244 | ||
|
|
6818574605 | ||
|
|
6eea03f81e | ||
|
|
1242834b7f | ||
|
|
1844513f08 | ||
|
|
b0be7a14d2 | ||
|
|
7e17c68dba | ||
|
|
6259f15ffa | ||
|
|
f65d027a0d | ||
|
|
e9e2ca50ee | ||
|
|
a64ef8517e | ||
|
|
c9bda60554 | ||
|
|
c3478520c0 | ||
|
|
8346ffe915 | ||
|
|
f49b046601 | ||
|
|
263c03291e | ||
|
|
29244c247e | ||
|
|
320de8637f | ||
|
|
33bc6bf84b | ||
|
|
0cd2c42b68 | ||
|
|
1716acf9e0 | ||
|
|
45477119d4 | ||
|
|
716fbeae0c | ||
|
|
103891e0c0 | ||
|
|
638b5b51e0 | ||
|
|
90fea722aa | ||
|
|
90ce35327f | ||
|
|
60e3b9446a | ||
|
|
16a726223c | ||
|
|
dfe45f39bb | ||
|
|
413be4a6d0 | ||
|
|
6a35f98f89 | ||
|
|
ad295d97c8 | ||
|
|
cf8171c9cd | ||
|
|
c616a4e9a6 | ||
|
|
04d641a5ad | ||
|
|
ec68570a38 | ||
|
|
407b44382c | ||
|
|
71a2bcc7f0 | ||
|
|
a2dd09725c | ||
|
|
f757e00f03 | ||
|
|
b7652bb321 | ||
|
|
e6018d32ec | ||
|
|
cb7e272bbe | ||
|
|
a4d9d8e0d3 | ||
|
|
c844c8b188 | ||
|
|
320263eefa | ||
|
|
274875c6c4 | ||
|
|
1ea35324c1 | ||
|
|
3e20ad3cdd | ||
|
|
711e6b3d17 | ||
|
|
0438bbb414 | ||
|
|
70ee362cc8 | ||
|
|
0479f1a433 | ||
|
|
7e01cb8227 | ||
|
|
ae0eb3b918 | ||
|
|
097d2709e2 | ||
|
|
f1e56272ef | ||
|
|
db4cfbf605 | ||
|
|
da7d31fa00 | ||
|
|
62bc74d3c6 | ||
|
|
4467689ec3 | ||
|
|
69a874d90d | ||
|
|
b259a00c94 | ||
|
|
a0088ead9e | ||
|
|
228fd80abd | ||
|
|
8b3a1a646a | ||
|
|
c4954b94b8 | ||
|
|
2b56ebd620 | ||
|
|
a78d95ddad | ||
|
|
938362154a | ||
|
|
8bff2b7000 | ||
|
|
c56f228646 | ||
|
|
98f0313e3e | ||
|
|
bde2e891ef | ||
|
|
7acdaede0d | ||
|
|
45d1b4bee3 | ||
|
|
4d0a170f01 | ||
|
|
5e37e5a37d | ||
|
|
a60da3d592 | ||
|
|
9a88fab84e | ||
|
|
4981d6aad4 | ||
|
|
7193ac6833 | ||
|
|
3d1a32764d | ||
|
|
2b8df3ed76 | ||
|
|
e94b004a5a | ||
|
|
6cc6f26fa1 | ||
|
|
120cdd53c3 | ||
|
|
435aac4a9c | ||
|
|
f234cf285d | ||
|
|
54953b69c6 | ||
|
|
60878b7a65 | ||
|
|
dada88d8a2 | ||
|
|
7167705409 | ||
|
|
4217abca6e | ||
|
|
49a97f2285 | ||
|
|
4f2d7b8cd0 | ||
|
|
afbda7bfb2 | ||
|
|
c568756d16 | ||
|
|
5794f76b0a | ||
|
|
74a768c0fb | ||
|
|
4136060825 | ||
|
|
e249a953cd | ||
|
|
eddc2e6356 | ||
|
|
1604474d6e | ||
|
|
bbaf71481c | ||
|
|
952117818c | ||
|
|
a31432f1bf | ||
|
|
b0afe25730 | ||
|
|
024e0e9bae | ||
|
|
dbabc3a5a8 | ||
|
|
a30aec8254 | ||
|
|
7440218974 | ||
|
|
b3c771a87f | ||
|
|
8f8451cdff | ||
|
|
6d7fe83469 | ||
|
|
05a5280162 | ||
|
|
8dd55eb949 | ||
|
|
5838cc218f | ||
|
|
2e52c957e0 | ||
|
|
9486c58d78 | ||
|
|
6e7c1e0d41 | ||
|
|
6a0a60a644 | ||
|
|
94f9c2c3cb | ||
|
|
37e7ed8d14 | ||
|
|
4227c80ec7 | ||
|
|
6ec6ef698b | ||
|
|
0543dd015e | ||
|
|
b88f895acf | ||
|
|
fc517700cc | ||
|
|
b5e0cd31dd | ||
|
|
ab4b8b77a3 | ||
|
|
04c339896b | ||
|
|
e37056737d | ||
|
|
89f8bb934c | ||
|
|
b564989214 | ||
|
|
03aa8edd58 | ||
|
|
803fc90dd9 | ||
|
|
6987a38820 | ||
|
|
7e458bb433 | ||
|
|
b391375008 | ||
|
|
3f89e1cf83 | ||
|
|
9f5dc8a0e2 | ||
|
|
12ea17e89f | ||
|
|
1fd6610fa3 | ||
|
|
1ec28d80c8 | ||
|
|
fcbc23e964 | ||
|
|
6fba2a6416 | ||
|
|
0e5edb16f6 | ||
|
|
5726df1a81 | ||
|
|
f3a0a786c5 | ||
|
|
fa08b3393a | ||
|
|
5db148be9f | ||
|
|
d03cce2761 | ||
|
|
3a0bdd803d | ||
|
|
d1b6dddfd0 | ||
|
|
2676c5a85d |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,9 +2,9 @@
|
||||
pkg
|
||||
bin2
|
||||
bin/i18n
|
||||
bin/leanote-linux
|
||||
bin/leanote-mac
|
||||
bin/leanote*
|
||||
bin/release
|
||||
bin/test.sh
|
||||
bin/tmp
|
||||
bin/test
|
||||
bin/src
|
||||
@@ -16,3 +16,4 @@ app/tmp/main.go
|
||||
.project
|
||||
public/config.codekit
|
||||
files
|
||||
/node_modules
|
||||
|
||||
35
.travis.yml
Normal file
35
.travis.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
language: go
|
||||
go: 1.4
|
||||
|
||||
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/
|
||||
|
||||
# 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
|
||||
409
Gulpfile.js
Normal file
409
Gulpfile.js
Normal file
@@ -0,0 +1,409 @@
|
||||
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';
|
||||
|
||||
var messagesPath = leanoteBase + 'messages';
|
||||
|
||||
// 合并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'));
|
||||
});
|
||||
|
||||
// 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';
|
||||
}
|
||||
jss.push(base + '/js/plugins/libs-min/fileupload.js');
|
||||
|
||||
return gulp.src(jss)
|
||||
.pipe(uglify()) // 压缩
|
||||
.pipe(concat('main.min.js'))
|
||||
.pipe(gulp.dest(base + '/js/plugins'));
|
||||
});
|
||||
|
||||
// 合并requirejs和markdown为一个文件
|
||||
gulp.task('concatMarkdownJs', function() {
|
||||
var jss = [
|
||||
'js/require.js',
|
||||
'md/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'));
|
||||
});
|
||||
|
||||
// / 合并requirejs和markdown为一个文件
|
||||
gulp.task('concatMarkdownJsV2', function() {
|
||||
var jss = [
|
||||
'js/require.js',
|
||||
'md/main-v2.min.js',
|
||||
];
|
||||
|
||||
for(var i in jss) {
|
||||
jss[i] = base + '/' + jss[i];
|
||||
}
|
||||
|
||||
return gulp
|
||||
.src(jss)
|
||||
.pipe(uglify()) // 压缩
|
||||
.pipe(concat('markdown-v2.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_markdown_js -->/, '<script src="/js/markdown-v2.min.js"></script>')) // 替换
|
||||
.pipe(replace('/tinymce/tinymce.js', '/tinymce/tinymce.full.min.js')) // 替换
|
||||
.pipe(replace(/<!-- pro_tinymce_init_js -->/, "var tinyMCEPreInit = {base: '/public/tinymce', suffix: '.min'};")) // 替换
|
||||
.pipe(replace(/plugins\/main.js/, "plugins/main.min.js")) // 替换
|
||||
// 连续两个空行换成一个空行
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace(/\r\n\r\n/g, '\r\n'))
|
||||
.pipe(replace('console.log(o);', ''))
|
||||
.pipe(replace('console.trace(o);', ''))
|
||||
// .pipe(minifyHtml()) // 不行, 压缩后golang报错
|
||||
.pipe(rename('note.html'))
|
||||
.pipe(gulp.dest(noteProBase));
|
||||
});
|
||||
|
||||
// 只获取需要js i18n的key
|
||||
var path = require('path');
|
||||
gulp.task('i18n', function() {
|
||||
var keys = {};
|
||||
var reg = /getMsg\(["']+(.+?)["']+/g;
|
||||
// {rule: "required", msg: "inputNewPassword"},
|
||||
var reg2 = /msg: ?"?([0-9a-zA-Z]*)"?/g;
|
||||
function getKey(data) {
|
||||
while(ret = reg.exec(data)) {
|
||||
keys[ret[1]] = 1;
|
||||
}
|
||||
|
||||
while(ret2 = reg2.exec(data)) {
|
||||
keys[ret2[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 + '/md');
|
||||
ls(base + '/js');
|
||||
ls(base + '/album');
|
||||
ls(base + '/libs');
|
||||
ls(base + '/member');
|
||||
ls(base + '/tinymce');
|
||||
|
||||
ls(leanoteBase + '/app/views');
|
||||
|
||||
console.log('parsed');
|
||||
var langs = {}; // zh-cn: 1
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 得到所有的语言的后缀
|
||||
// 返回{en-us: 1, }
|
||||
function getAllLangs() {
|
||||
var langs = {};
|
||||
var files = fs.readdirSync(messagesPath);
|
||||
for(fn in files) {
|
||||
var fname = files[fn];
|
||||
if (fname.indexOf('-') > 0) {
|
||||
langs[fname] = 1;
|
||||
}
|
||||
}
|
||||
return langs;
|
||||
}
|
||||
|
||||
// msg.zh, msg.js
|
||||
function genI18nJsFile(targetFilename, lang, fromFilenames, keys) {
|
||||
var msgs = {};
|
||||
fromFilenames.forEach(function (name) {
|
||||
var tmpMsgs = getAllMsgs(leanoteBase + '/messages/' + lang + '/' + name + '.conf');
|
||||
for (var i in tmpMsgs) {
|
||||
msgs[i] = tmpMsgs[i];
|
||||
}
|
||||
});
|
||||
|
||||
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;' +
|
||||
'}';
|
||||
|
||||
// 写入到文件中
|
||||
var toFilename = targetFilename + '.' + lang + '.js';
|
||||
fs.writeFile(base + '/js/i18n/' + toFilename, str);
|
||||
}
|
||||
|
||||
function genTinymceLang(lang) {
|
||||
var msgs = getAllMsgs(leanoteBase + 'messages/' + lang + '/tinymce_editor.conf');
|
||||
var str = 'tinymce.addI18n("' + lang + '",' + JSON.stringify(msgs) + ');';
|
||||
fs.writeFile(base + '/tinymce/langs/' + lang + '.js', str);
|
||||
}
|
||||
|
||||
var langs = getAllLangs();
|
||||
for (var lang in langs) {
|
||||
genI18nJsFile('blog', lang, ['blog'], keys);
|
||||
genI18nJsFile('msg', lang, ['msg', 'member', 'markdown', 'album'], keys);
|
||||
|
||||
genTinymceLang(lang);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 合并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'));
|
||||
});
|
||||
|
||||
// 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,leaui_mindmap,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));
|
||||
});
|
||||
|
||||
// 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 + '/md/themes/default.css')
|
||||
.pipe(rename({suffix: '-min'}))
|
||||
.pipe(minifycss())
|
||||
.pipe(gulp.dest(base + '/md/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'));
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
gulp.task('concat', ['concatDepJs', 'concatAppJs', /* 'concatMarkdownJs', */'concatMarkdownJsV2']);
|
||||
gulp.task('html', ['devToProHtml']);
|
||||
gulp.task('default', ['concat', 'plugins', 'minifycss', 'i18n', 'concatAlbumJs', 'html']);
|
||||
6
LICENSE
6
LICENSE
@@ -1,6 +1,6 @@
|
||||
leanote - you own cloud note!
|
||||
LEANOTE - NOT JUST A NOTEPAD!
|
||||
|
||||
Copyright 2014 by the contributors
|
||||
Copyright 2014-2015 by the contributors
|
||||
|
||||
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
|
||||
@@ -12,7 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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)
|
||||
|
||||
|
||||
248
README.md
248
README.md
@@ -1,113 +1,189 @@
|
||||
|
||||
# Leanote
|
||||
|
||||
[](https://travis-ci.org/leanote/leanote)
|
||||
[](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
Leanote, not just a notebook!
|
||||
Leanote, not just a notepad!
|
||||

|
||||
|
||||
**Some Features**
|
||||
**Highlighted Features**
|
||||
|
||||
* 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.
|
||||
* Cooperation: Collaborate with friends to improve your skills.
|
||||
* Blog: Publish your knowledge and make leanote your blog.
|
||||
* Note-taking made easy: Leanote incorporates a clean and intuitive interface, the `tinymce` rich-text editor and a dedicated *markdown* editor, making your writing/typing more efficient and enjoyable. For more advanced users, we even offer `Vim` and `Emacs` writing modes to help boost your writing speed to another level.
|
||||
* Knowledge management: The flexible and versatile notebook-note-tagging system of Leanote makes it an ideal tool for knowledge management.
|
||||
* Sharing: Share your knowledge, thoughts and experiences with friends via Leanote. Invite your friends to join your notepad in the cloud.
|
||||
* Cooperating: Collaborate with colleagues to improve skills, fertilize ideas and brainstorm on the fly.
|
||||
* Blogging: Publish your work and make Leanote your personal 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:
|
||||
* 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 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!
|
||||
**Other Features**
|
||||
|
||||
* Markdown syntax support
|
||||
* Distraction-free writing mode
|
||||
* `Vim` and `Emacs` editing mode
|
||||
* Export notes to PDFs
|
||||
* Batch note operation
|
||||
* Customizable themes for blogging
|
||||
|
||||
## 2. Why we create Leanote
|
||||
|
||||
We have been using the popular note-taking software/service `Evernote` as our knowledge management tool on a daily basis. Benefited from and inspired by `Evernote`, we decided to create a brand-new tool that provides everything `Evernote` has to offer, plus a bunch of new features that `Evernote` failed to deliver, such as:
|
||||
|
||||
* A more powerful editor: `Evernote`'s editor lacks the functionalities of **document navigation**, **syntax based code rendering** (as a programmer, syntax highlighted code rendering is a necessity), **image resizing** and so forth.
|
||||
* Everybody loves *markdown*, however `Evernote` simply wouldn't add it despite of years' of requests from users. So we will do the favor and bring a *markdown* enabled editor to you, guess what, it is also rendered in real-time!
|
||||
* If you a developer and miss the `Vim` or `Emacs` ways of writing, we offer you the choice of `Vim` and `Emacs` editting modes. Equipped with *markdown* syntax for text formatting, you will never need to touch your mouse while writing.
|
||||
* We love managing knowledge and thoughts as much as sharing them, so everybody has their own note account (`Evernote`, `Onenote`, `Google doc`, `Wiz note` etc.) and social media account (`Facebook`, `Wordpress`, blogs, etc.). But why can’t those two be one? Leanote makes this first step to bridge the private note-taking and public knowledge sharing seamlessly.
|
||||
* A complete and all-platform (sorry Windows phone) covering software suite: that includes 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 they are all open source!
|
||||
* ......
|
||||
|
||||
## 3. How to install leanote
|
||||
## 3. How to get Leanote
|
||||
|
||||
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)
|
||||
The Leanote software suite 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).
|
||||
|
||||
### 3.1. Download leanote
|
||||
Interested in our product and want to try it out from your web browser? Welcome to sign up on https://leanote.com.
|
||||
|
||||
Leanote V1.0.3-beta has been released. Binaries:
|
||||
Feeling suspicious about how those note-taking companies treat your personal data? You can install Leanote on your server, and use Leanote App (Desktop, iOS, Android) to sync notes with your self-hosted server.
|
||||
|
||||
* Linux: [leanote-linux-x86_64.v1.0-beta.3.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta.3/leanote-linux-x86_64.v1.0-beta.3.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-x86_64.v1.0-beta.3.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta.3/leanote-mac-x86_64.v1.0-beta.3.bin.tar.gz)
|
||||
More information about how to install Leanote please see:
|
||||
|
||||
Or you can clone [Leanote bin repository](https://github.com/leanote/leanote-bin) (Recommend)
|
||||
* Leanote binary installation tutorial:
|
||||
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
|
||||
* [Mac and Linux](https://github.com/leanote/leanote/wiki/leanote-binary-installation-on-Mac-and-Linux-(En))
|
||||
* Leanote source installation tutorial:
|
||||
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
|
||||
* [Mac and Linux](https://github.com/leanote/leanote/wiki/Leanote-source-installation-on-Mac-and-Linux-(En))
|
||||
|
||||
### 3.2. Install MongoDB
|
||||
## 4. Documentation
|
||||
|
||||
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 [wiki](https://github.com/leanote/leanote/wiki) for detailed instruction on how to install Leanote on various platforms, trouble shooting and configuration explanations.
|
||||
|
||||
|
||||
## 5. Contributors
|
||||
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
||||
this project. Your help is much appreciated.
|
||||
## 5. How to develop Leanote
|
||||
|
||||
## 6. Contributing
|
||||
If you are a developer yourself and feel like to build on top of Leanote, please refer to [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 fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||
|
||||
## 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)
|
||||
## 6. Contributions
|
||||
|
||||
## Discussion
|
||||
* [leanote bbs](http://bbs.leanote.com)
|
||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||
* QQ Group: 158716820
|
||||
Like or dislike Leanote, please leave your comments and suggestions to help us improve it.
|
||||
If you encounter any issue, we suggest you first do a search in the issues section to see whether a solution already exists, or open up a new one otherwise.
|
||||
|
||||
We’d like to acknowledge the contributions made by our [developers and contributors](https://github.com/leanote/leanote/graphs/contributors) to
|
||||
this project. Leanote won’t exist without your hard work. Your help is much appreciated.
|
||||
|
||||
## 7. Join us
|
||||
|
||||
Please feel free to fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||
|
||||
If you find any problems or have any good ideas, feature requests, please submit here [issues](https://github.com/leanote/leanote/issues).
|
||||
|
||||
|
||||
## 8. Donation
|
||||
|
||||
If you like our product, consider supporting us via [donate us](http://leanote.org/#donate).
|
||||
We acknowledge the donations make by all the [donators](http://leanote.leanote.com/post/leanote-donation-list).
|
||||
|
||||
## 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
|
||||
|
||||
You are welcome to join us.
|
||||
|
||||
## 10. Contacts
|
||||
|
||||
* Email: leanote@leanote.com
|
||||
* [Leanote BBS](http://bbs.leanote.com)
|
||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
||||
* QQ Groups: 326073529, 256076853, 158716820
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
[中文](README_zh.md)
|
||||
|
||||
# Leanote
|
||||
|
||||
## 1. 介绍
|
||||
|
||||
Leanote, 不只是笔记!
|
||||
|
||||
**特性**
|
||||
|
||||
* 高效笔记:Leanote 有易操作的界面, 包含一款富文本编辑器和Markdown编辑器,让您的笔记记录更轻松和高效。对高阶用户,我们还提供`Vim` 和`Emacs` 编辑模式,助推你的写作速度更上层楼。
|
||||
* 知识管理: Leanote 灵活而强大的“笔记本-笔记-标签”系统,让它成为你个人知识管理的利器。
|
||||
* 分享: 你可以通过Leanote同好友分享知识、想法和经历, 邀请好友加入你的笔记簿,通过云端交流信息。
|
||||
* 协作: Leanote协助你与同事之间相互协作,激荡新思路,随时随地头脑风暴。
|
||||
* 博客: Leanote也可以作为你的个人博客, 把你的知识传播的更远!
|
||||
|
||||
**其它特性**
|
||||
|
||||
* 支持Markdown编辑
|
||||
* 写作模式
|
||||
* `Vim` 及 `Emacs` 编辑模式
|
||||
* 支持PDF导出
|
||||
* 支持批量操作
|
||||
* 博客自定义主题, 实现高度定制化
|
||||
|
||||
## 2. 为什么我们要创建Leanote?
|
||||
我们都曾是`Evernote`的忠实粉丝, 一直以来`Evernote`都是我们日常知识管理的有效工具。于是我们决定重新创造一款工具,提供`Evernote`所能提供的功能,同时弥补`Evernote`的不足,比如:
|
||||
* 功能更强的文本编辑器:`Evernote`的编辑器不能满足我们的需求, 不能实现文档导航、不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放等。
|
||||
* `Evernote` 不支持所有人都喜爱的markdown语法,于是我们为Leanote配备了一款可以实时渲染的markdown编辑器。
|
||||
* 如果你是一名开发者,觉得手指怀念`Vim` 或 `Emacs` 了,那么我们还提供给你`Vim` 和 `Emacs` 写作模式,配合*markdown*的格式编辑,写作的时候再也不用去碰鼠标了。
|
||||
* 知识积累和知识分享同样重要,因此大家都有自己的笔记账号和社交账号。但为什么这两者不能合二为一呢? Leanote 做到了将二者无缝衔接。
|
||||
* 一套完整的、全平台覆盖的软件套装,包括了web、桌面、安卓、IOS设备,而且全部开源!
|
||||
* 还有...
|
||||
|
||||
## 3. 获取Leanote
|
||||
|
||||
Leanote云笔记产品包括: Leanote Web & Server(即本仓库), 桌面客户端, IOS, android. 4端全部开源!
|
||||
|
||||
如果想试用我们的产品,欢迎在 https://leanote.com 上注册, Leanote团队为你提供稳定可靠的服务。
|
||||
担心服务厂商如何处理你的个人数据吗?你可以下载Leanote安装在自己的服务器上, 通过Leanote客户端连接与自建服务同步数据。
|
||||
|
||||
这里详细整理了Leanote二进版和Leanote开发版的安装教程, 请移步至:
|
||||
|
||||
* Leanote二进制详细安装教程:
|
||||
* [Windows](https://github.com/leanote/leanote/wiki/Leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B---Windows)
|
||||
* [Mac, Linux](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源码详细安装教程:
|
||||
* [Windows](https://github.com/leanote/leanote/wiki/Leanote-%E6%BA%90%E7%A0%81%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B----Windows)
|
||||
* [Mac, Linux](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. 相关文档
|
||||
|
||||
更多详细的安装说明、问题处理和配置说明文档,请查看 [wiki](https://github.com/leanote/leanote/wiki)。
|
||||
|
||||
## 5. 如何对Leanote进行二次开发
|
||||
|
||||
如果您有兴趣基于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)。
|
||||
|
||||
## 6. 贡献者
|
||||
|
||||
在此对向Leanote贡献力量的[贡献者们](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)区是否已经有解决方法。如果没有,欢迎提交新issue。
|
||||
|
||||
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群](http://leanote.leanote.com/post/Leanote-groups)
|
||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
||||
|
||||
|
||||
113
README_zh.md
113
README_zh.md
@@ -1,113 +0,0 @@
|
||||
|
||||
# Leanote产品
|
||||
|
||||
## 1. 介绍
|
||||
|
||||
Leanote, 不只是笔记!
|
||||

|
||||
|
||||
**特性**
|
||||
|
||||
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||
|
||||
## 2. 为什么我们要创建leanote?
|
||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||
* 还有...
|
||||
|
||||
## 3.安装leanote
|
||||
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||
|
||||
这里详细整理了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)
|
||||
|
||||
### 3.1. 下载leanote
|
||||
|
||||
Leanote V1.0-beta.3 已发布, 二进制文件(暂时没有windows版的):
|
||||
|
||||
* Linux: [leanote-linux-x86_64.v1.0-beta.3.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta.3/leanote-linux-x86_64.v1.0-beta.3.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-x86_64.v1.0-beta.3.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta.3/leanote-mac-x86_64.v1.0-beta.3.bin.tar.gz)
|
||||
|
||||
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
|
||||
|
||||
### 3.2. 安装 MongodbDB
|
||||
|
||||
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||
|
||||
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||
|
||||
### 3.3. 导入初始数据
|
||||
|
||||
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||
|
||||
```
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||
```
|
||||
|
||||
初始数据包含两个用户:
|
||||
|
||||
```
|
||||
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||
```
|
||||
|
||||
### 3.4. 配置
|
||||
|
||||
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||
|
||||
``mongodb`` **必须配置!**
|
||||
|
||||
```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)
|
||||
19
app/cmd/main.go
Normal file
19
app/cmd/main.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/cmd/harness"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -2,11 +2,11 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
// Album controller
|
||||
@@ -14,12 +14,17 @@ type Album struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 图片管理, iframe
|
||||
func (c Album) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
return c.RenderTemplate("album/index.html")
|
||||
}
|
||||
|
||||
// all albums by userId
|
||||
func (c Album) GetAlbums() revel.Result {
|
||||
re := albumService.GetAlbums(c.GetUserId())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
||||
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
||||
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
||||
@@ -29,12 +34,12 @@ func (c Album) DeleteAlbum(albumId string) revel.Result {
|
||||
func (c Album) AddAlbum(name string) revel.Result {
|
||||
album := info.Album{
|
||||
AlbumId: bson.NewObjectId(),
|
||||
Name: name,
|
||||
Seq: -1,
|
||||
UserId: c.GetObjectUserId()}
|
||||
Name: name,
|
||||
Seq: -1,
|
||||
UserId: c.GetObjectUserId()}
|
||||
re := albumService.AddAlbum(album)
|
||||
|
||||
if(re) {
|
||||
if re {
|
||||
return c.RenderJson(album)
|
||||
} else {
|
||||
return c.RenderJson(false)
|
||||
@@ -44,4 +49,4 @@ func (c Album) AddAlbum(name string) revel.Result {
|
||||
// update alnum name
|
||||
func (c Album) UpdateAlbum(albumId, name string) revel.Result {
|
||||
return c.RenderJson(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "encoding/json"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
"io"
|
||||
"fmt"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
)
|
||||
|
||||
// 附件
|
||||
@@ -31,44 +31,46 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
var resultMsg = "error" // 错误信息
|
||||
var Ok = false
|
||||
var fileInfo info.Attach
|
||||
|
||||
|
||||
re = info.NewRe()
|
||||
|
||||
|
||||
defer func() {
|
||||
re.Id = fileId // 只是id, 没有其它信息
|
||||
re.Msg = resultMsg
|
||||
re.Ok = Ok
|
||||
re.Item = fileInfo
|
||||
}()
|
||||
|
||||
|
||||
// 判断是否有权限为笔记添加附件
|
||||
if !shareService.HasUpdateNotePerm(noteId, c.GetUserId()) {
|
||||
return re
|
||||
}
|
||||
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
// > 5M?
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize")
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
if float64(len(data)) > maxFileSize*float64(1024*1024) {
|
||||
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
|
||||
// 生成上传路径
|
||||
filePath := "files/" + c.GetUserId() + "/attachs"
|
||||
dir := revel.BasePath + "/" + filePath
|
||||
// filePath := "files/" + c.GetUserId() + "/attachs"
|
||||
newGuid := NewGuid()
|
||||
filePath := "files/" + GetRandomFilePath(c.GetUserId(), newGuid) + "/attachs"
|
||||
dir := revel.BasePath + "/" + filePath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return re
|
||||
@@ -76,13 +78,13 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
_, ext := SplitFilename(filename) // .doc
|
||||
filename = NewGuid() + ext
|
||||
toPath := dir + "/" + filename;
|
||||
filename = newGuid + ext
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
|
||||
|
||||
// add File to db
|
||||
fileType := ""
|
||||
if ext != "" {
|
||||
@@ -90,22 +92,22 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
}
|
||||
filesize := GetFilesize(toPath)
|
||||
fileInfo = info.Attach{Name: filename,
|
||||
Title: handel.Filename,
|
||||
NoteId: bson.ObjectIdHex(noteId),
|
||||
Title: handel.Filename,
|
||||
NoteId: bson.ObjectIdHex(noteId),
|
||||
UploadUserId: c.GetObjectUserId(),
|
||||
Path: filePath + "/" + filename,
|
||||
Type: fileType,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId();
|
||||
Path: filePath + "/" + filename,
|
||||
Type: fileType,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId()
|
||||
fileInfo.AttachId = id
|
||||
fileId = id.Hex()
|
||||
Ok, resultMsg = attachService.AddAttach(fileInfo, false)
|
||||
if resultMsg != "" {
|
||||
resultMsg = c.Message(resultMsg)
|
||||
}
|
||||
|
||||
fileInfo.Path = ""; // 不要返回
|
||||
|
||||
fileInfo.Path = "" // 不要返回
|
||||
if Ok {
|
||||
resultMsg = "success"
|
||||
}
|
||||
@@ -130,15 +132,15 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
|
||||
// 下载附件
|
||||
// 权限判断
|
||||
func (c Attach) Download(attachId string) revel.Result {
|
||||
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
|
||||
attach := attachService.GetAttach(attachId, c.GetUserId()) // 得到路径
|
||||
path := attach.Path
|
||||
if path == "" {
|
||||
return c.RenderText("")
|
||||
}
|
||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||
file, _ := os.Open(fn)
|
||||
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
||||
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
|
||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||
file, _ := os.Open(fn)
|
||||
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
||||
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
|
||||
}
|
||||
|
||||
func (c Attach) DownloadAll(noteId string) revel.Result {
|
||||
@@ -151,69 +153,75 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
|
||||
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("")
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
|
||||
dir := revel.BasePath + "/files/attach_all"
|
||||
|
||||
if !MkdirAll(dir) {
|
||||
return c.RenderText("error")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
fw, err := os.Create(dir + "/" + filename)
|
||||
if err != nil {
|
||||
return c.RenderText("error")
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
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
|
||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "strconv"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
// "strconv"
|
||||
)
|
||||
|
||||
// 用户登录/注销/找回密码
|
||||
@@ -21,14 +22,14 @@ func (c Auth) Login(email, from string) revel.Result {
|
||||
c.RenderArgs["email"] = email
|
||||
c.RenderArgs["from"] = from
|
||||
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
||||
|
||||
|
||||
sessionId := c.Session.Id()
|
||||
if sessionService.LoginTimesIsOver(sessionId) {
|
||||
c.RenderArgs["needCaptcha"] = true
|
||||
}
|
||||
|
||||
|
||||
c.SetLocale()
|
||||
|
||||
|
||||
if c.Has("demo") {
|
||||
c.RenderArgs["demo"] = true
|
||||
c.RenderArgs["email"] = "demo@leanote.com"
|
||||
@@ -40,41 +41,42 @@ func (c Auth) Login(email, from string) revel.Result {
|
||||
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||
sessionId := c.Session.Id()
|
||||
var msg = ""
|
||||
|
||||
userInfo := authService.Login(email, pwd)
|
||||
if userInfo.Email != "" {
|
||||
|
||||
userInfo, err := authService.Login(email, pwd)
|
||||
if err != nil {
|
||||
// 登录错误, 则错误次数++
|
||||
msg = "wrongUsernameOrPassword"
|
||||
} else {
|
||||
c.SetSession(userInfo)
|
||||
sessionService.ClearLoginTimes(sessionId)
|
||||
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 {
|
||||
sessionId := c.Session.Id()
|
||||
var msg = ""
|
||||
|
||||
|
||||
// > 5次需要验证码, 直到登录成功
|
||||
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||
msg = "captchaError"
|
||||
} else {
|
||||
userInfo := authService.Login(email, pwd)
|
||||
if userInfo.Email != "" {
|
||||
c.SetSession(userInfo)
|
||||
sessionService.ClearLoginTimes(sessionId)
|
||||
return c.RenderJson(info.Re{Ok: true})
|
||||
} else {
|
||||
userInfo, err := authService.Login(email, pwd)
|
||||
if err != nil {
|
||||
// 登录错误, 则错误次数++
|
||||
msg = "wrongUsernameOrPassword"
|
||||
sessionService.IncrLoginTimes(sessionId)
|
||||
} else {
|
||||
c.SetSession(userInfo)
|
||||
sessionService.ClearLoginTimes(sessionId)
|
||||
return c.RenderJson(info.Re{Ok: true})
|
||||
}
|
||||
}
|
||||
|
||||
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) Logout() revel.Result {
|
||||
sessionId := c.Session.Id()
|
||||
@@ -85,8 +87,17 @@ func (c Auth) Logout() revel.Result {
|
||||
|
||||
// 体验一下
|
||||
func (c Auth) Demo() revel.Result {
|
||||
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
|
||||
return c.Redirect("/note")
|
||||
email := configService.GetGlobalStringConfig("demoUsername")
|
||||
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 nil
|
||||
}
|
||||
|
||||
//--------
|
||||
@@ -98,7 +109,7 @@ func (c Auth) Register(from, iu string) revel.Result {
|
||||
c.SetLocale()
|
||||
c.RenderArgs["from"] = from
|
||||
c.RenderArgs["iu"] = iu
|
||||
|
||||
|
||||
c.RenderArgs["title"] = c.Message("register")
|
||||
c.RenderArgs["subTitle"] = c.Message("register")
|
||||
return c.RenderTemplate("home/register.html")
|
||||
@@ -107,30 +118,33 @@ func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
||||
if !configService.IsOpenRegister() {
|
||||
return c.Redirect("/index")
|
||||
}
|
||||
|
||||
re := info.NewRe();
|
||||
|
||||
|
||||
re := info.NewRe()
|
||||
|
||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
|
||||
email = strings.ToLower(email)
|
||||
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd, iu)
|
||||
|
||||
|
||||
// 注册成功, 则立即登录之
|
||||
if re.Ok {
|
||||
c.doLogin(email, pwd)
|
||||
}
|
||||
|
||||
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
//--------
|
||||
// 找回密码
|
||||
func (c Auth) FindPassword() revel.Result {
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = c.Message("findPassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||
return c.RenderTemplate("home/find_password.html")
|
||||
@@ -141,30 +155,33 @@ func (c Auth) DoFindPassword(email string) revel.Result {
|
||||
re.Ok = true
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 点击链接后, 先验证之
|
||||
func (c Auth) FindPassword2(token string) revel.Result {
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = c.Message("findPassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||
if token == "" {
|
||||
return c.RenderTemplate("find_password2_timeout.html")
|
||||
}
|
||||
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
|
||||
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd)
|
||||
if !ok {
|
||||
return c.RenderTemplate("home/find_password2_timeout.html")
|
||||
}
|
||||
c.RenderArgs["findPwd"] = findPwd
|
||||
|
||||
|
||||
c.RenderArgs["title"] = c.Message("updatePassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("updatePassword")
|
||||
|
||||
|
||||
return c.RenderTemplate("home/find_password2.html")
|
||||
}
|
||||
|
||||
// 找回密码修改密码
|
||||
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
re := info.NewRe()
|
||||
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 修改之
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
"github.com/leanote/leanote/app/lea/i18n"
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
"bytes"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// 公用Controller, 其它Controller继承它
|
||||
@@ -19,6 +20,11 @@ type BaseController struct {
|
||||
*revel.Controller
|
||||
}
|
||||
|
||||
// 覆盖revel.Message
|
||||
func (c *BaseController) Message(message string, args ...interface{}) (value string) {
|
||||
return i18n.Message(c.Request.Locale, message, args...)
|
||||
}
|
||||
|
||||
func (c BaseController) GetUserId() string {
|
||||
if userId, ok := c.Session["UserId"]; ok {
|
||||
return userId
|
||||
@@ -56,34 +62,41 @@ func (c BaseController) GetUsername() string {
|
||||
// 得到用户信息
|
||||
func (c BaseController) GetUserInfo() info.User {
|
||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||
return userService.GetUserInfo(userId);
|
||||
return userService.GetUserInfo(userId)
|
||||
/*
|
||||
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
|
||||
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
|
||||
mdEditorWidth, _ := strconv.Atoi(c.Session["MdEditorWidth"])
|
||||
LogJ(c.Session)
|
||||
user := info.User{UserId: bson.ObjectIdHex(userId),
|
||||
Email: c.Session["Email"],
|
||||
Logo: c.Session["Logo"],
|
||||
Username: c.Session["Username"],
|
||||
UsernameRaw: c.Session["UsernameRaw"],
|
||||
Theme: c.Session["Theme"],
|
||||
NotebookWidth: notebookWidth,
|
||||
NoteListWidth: noteListWidth,
|
||||
MdEditorWidth: mdEditorWidth,
|
||||
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
|
||||
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
|
||||
mdEditorWidth, _ := strconv.Atoi(c.Session["MdEditorWidth"])
|
||||
LogJ(c.Session)
|
||||
user := info.User{UserId: bson.ObjectIdHex(userId),
|
||||
Email: c.Session["Email"],
|
||||
Logo: c.Session["Logo"],
|
||||
Username: c.Session["Username"],
|
||||
UsernameRaw: c.Session["UsernameRaw"],
|
||||
Theme: c.Session["Theme"],
|
||||
NotebookWidth: notebookWidth,
|
||||
NoteListWidth: noteListWidth,
|
||||
MdEditorWidth: mdEditorWidth,
|
||||
}
|
||||
if c.Session["Verified"] == "1" {
|
||||
user.Verified = true
|
||||
}
|
||||
if c.Session["Verified"] == "1" {
|
||||
user.Verified = true
|
||||
}
|
||||
if c.Session["LeftIsMin"] == "1" {
|
||||
user.LeftIsMin = true
|
||||
}
|
||||
return user
|
||||
if c.Session["LeftIsMin"] == "1" {
|
||||
user.LeftIsMin = true
|
||||
}
|
||||
return 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无关
|
||||
func (c BaseController) GetSession(key string) string {
|
||||
v, ok := c.Session[key]
|
||||
@@ -100,16 +113,16 @@ func (c BaseController) SetSession(userInfo info.User) {
|
||||
c.Session["UsernameRaw"] = userInfo.UsernameRaw
|
||||
c.Session["Theme"] = userInfo.Theme
|
||||
c.Session["Logo"] = userInfo.Logo
|
||||
|
||||
|
||||
c.Session["NotebookWidth"] = strconv.Itoa(userInfo.NotebookWidth)
|
||||
c.Session["NoteListWidth"] = strconv.Itoa(userInfo.NoteListWidth)
|
||||
|
||||
|
||||
if userInfo.Verified {
|
||||
c.Session["Verified"] = "1"
|
||||
} else {
|
||||
c.Session["Verified"] = "0"
|
||||
}
|
||||
|
||||
|
||||
if userInfo.LeftIsMin {
|
||||
c.Session["LeftIsMin"] = "1"
|
||||
} else {
|
||||
@@ -132,8 +145,8 @@ func (c BaseController) UpdateSession(key, value string) {
|
||||
|
||||
// 返回json
|
||||
func (c BaseController) Json(i interface{}) string {
|
||||
// b, _ := json.MarshalIndent(i, "", " ")
|
||||
b, _ := json.Marshal(i)
|
||||
// b, _ := json.MarshalIndent(i, "", " ")
|
||||
b, _ := json.Marshal(i)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -150,9 +163,9 @@ func (c BaseController) GetPage() int {
|
||||
// 判断是否含有某参数
|
||||
func (c BaseController) Has(key string) bool {
|
||||
if _, ok := c.Params.Values[key]; ok {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -162,33 +175,37 @@ func (c Blog) GetPage(page, count int, list interface{}) info.Page {
|
||||
*/
|
||||
|
||||
func (c BaseController) GetTotalPage(page, count int) int {
|
||||
return int(math.Ceil(float64(count)/float64(page)))
|
||||
return int(math.Ceil(float64(count) / float64(page)))
|
||||
}
|
||||
|
||||
//-------------
|
||||
func (c BaseController) E404() revel.Result {
|
||||
c.RenderArgs["title"] = "404";
|
||||
c.RenderArgs["title"] = "404"
|
||||
return c.NotFound("", nil)
|
||||
}
|
||||
|
||||
// 设置本地
|
||||
func (c BaseController) SetLocale() string {
|
||||
locale := string(c.Request.Locale) // zh-CN
|
||||
// lang := locale
|
||||
// if strings.Contains(locale, "-") {
|
||||
// pos := strings.Index(locale, "-")
|
||||
// lang = locale[0:pos]
|
||||
// }
|
||||
// if lang != "zh" && lang != "en" {
|
||||
// lang = "en"
|
||||
// }
|
||||
lang := locale
|
||||
if strings.Contains(locale, "-") {
|
||||
pos := strings.Index(locale, "-")
|
||||
lang = locale[0:pos]
|
||||
if !i18n.HasLang(locale) {
|
||||
lang = i18n.GetDefaultLang()
|
||||
}
|
||||
if lang != "zh" && lang != "en" {
|
||||
lang = "en";
|
||||
}
|
||||
c.RenderArgs["locale"] = lang;
|
||||
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
c.RenderArgs["locale"] = lang
|
||||
c.RenderArgs["siteUrl"] = configService.GetSiteUrl()
|
||||
|
||||
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||
c.RenderArgs["noteUrl"] = configService.GetNoteUrl()
|
||||
|
||||
|
||||
return lang
|
||||
}
|
||||
|
||||
@@ -196,7 +213,7 @@ func (c BaseController) SetLocale() string {
|
||||
func (c BaseController) SetUserInfo() info.User {
|
||||
userInfo := c.GetUserInfo()
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
if(userInfo.Username == configService.GetAdminUsername()) {
|
||||
if userInfo.Username == configService.GetAdminUsername() {
|
||||
c.RenderArgs["isAdmin"] = true
|
||||
}
|
||||
return userInfo
|
||||
@@ -215,10 +232,10 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
|
||||
Template: template,
|
||||
RenderArgs: c.RenderArgs, // 把args给它
|
||||
}
|
||||
|
||||
|
||||
var buffer bytes.Buffer
|
||||
tpl.Template.Render(&buffer, c.RenderArgs)
|
||||
return buffer.String();
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// json, result
|
||||
@@ -227,7 +244,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
|
||||
func (c BaseController) RenderRe(re info.Re) revel.Result {
|
||||
oldMsg := re.Msg
|
||||
if re.Msg != "" {
|
||||
if(strings.Contains(re.Msg, "-")) {
|
||||
if strings.Contains(re.Msg, "-") {
|
||||
msgAndValues := strings.Split(re.Msg, "-")
|
||||
if len(msgAndValues) == 2 {
|
||||
re.Msg = c.Message(msgAndValues[0], msgAndValues[1])
|
||||
|
||||
@@ -57,9 +57,9 @@ func (c Blog) render(templateName string, themePath string) revel.Result {
|
||||
isPreview = true
|
||||
themePath = themePath2.(string)
|
||||
c.setPreviewUrl()
|
||||
|
||||
|
||||
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
|
||||
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"];
|
||||
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"]
|
||||
}
|
||||
return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
|
||||
}
|
||||
@@ -113,15 +113,15 @@ func (c Blog) setPreviewUrl() {
|
||||
themeId := c.Session["themeId"]
|
||||
theme := themeService.GetTheme(userId, themeId)
|
||||
|
||||
siteUrl := configService.GetSiteUrl()
|
||||
blogUrl := siteUrl + "/preview" // blog.leanote.com
|
||||
// siteUrl := configService.GetSiteUrl()
|
||||
blogUrl := "/preview" // blog.leanote.com
|
||||
|
||||
indexUrl = blogUrl + "/" + userIdOrEmail
|
||||
cateUrl = blogUrl + "/cate/" + userIdOrEmail // /notebookId
|
||||
|
||||
postUrl = blogUrl + "/post/" + userIdOrEmail // /xxxxx
|
||||
postUrl = blogUrl + "/post/" + userIdOrEmail // /xxxxx
|
||||
searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId
|
||||
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/singleId
|
||||
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/singleId
|
||||
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
|
||||
tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
|
||||
|
||||
@@ -143,8 +143,8 @@ func (c Blog) setPreviewUrl() {
|
||||
// 各种地址设置
|
||||
func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
|
||||
// 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com
|
||||
host := c.Request.Request.Host
|
||||
var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
|
||||
// host := c.Request.Request.Host
|
||||
// var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
|
||||
// staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com
|
||||
// life.leanote.com, lealife.com
|
||||
siteUrl := configService.GetSiteUrl()
|
||||
@@ -168,20 +168,20 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
|
||||
c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
|
||||
|
||||
// 其它static js
|
||||
c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js"
|
||||
c.RenderArgs["jQueryUrl"] = "/js/jquery-1.9.0.min.js"
|
||||
|
||||
c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js"
|
||||
c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css"
|
||||
c.RenderArgs["prettifyJsUrl"] = "/js/google-code-prettify/prettify.js"
|
||||
c.RenderArgs["prettifyCssUrl"] = "/js/google-code-prettify/prettify.css"
|
||||
|
||||
c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js"
|
||||
c.RenderArgs["blogCommonJsUrl"] = "/public/blog/js/common.js"
|
||||
|
||||
c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css"
|
||||
c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js"
|
||||
c.RenderArgs["shareCommentCssUrl"] = "/public/blog/css/share_comment.css"
|
||||
c.RenderArgs["shareCommentJsUrl"] = "/public/blog/js/share_comment.js"
|
||||
|
||||
c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css"
|
||||
c.RenderArgs["fontAwesomeUrl"] = "/css/font-awesome-4.2.0/css/font-awesome.css"
|
||||
|
||||
c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css"
|
||||
c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js"
|
||||
c.RenderArgs["bootstrapCssUrl"] = "/css/bootstrap.css"
|
||||
c.RenderArgs["bootstrapJsUrl"] = "/js/bootstrap-min.js"
|
||||
}
|
||||
|
||||
// 笔记本分类
|
||||
@@ -220,7 +220,7 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 之后添加没有排序的
|
||||
for _, n := range notebooks {
|
||||
id := n.NotebookId.Hex()
|
||||
@@ -234,19 +234,19 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// LogJ(">>")
|
||||
// LogJ(cates)
|
||||
|
||||
|
||||
// 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)
|
||||
// Log("________")
|
||||
// LogJ(parentCate)
|
||||
// LogJ(cate)
|
||||
if parentCate.Children == nil {
|
||||
parentCate.Children = []*info.Cate{cate}
|
||||
} else {
|
||||
@@ -256,7 +256,7 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 得到没有父的cate, 作为第一级cate
|
||||
catesTree := []*info.Cate{}
|
||||
for _, cate := range cates {
|
||||
@@ -264,11 +264,7 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
||||
catesTree = append(catesTree, cate)
|
||||
}
|
||||
}
|
||||
|
||||
Log("cates")
|
||||
LogJ(cates)
|
||||
LogJ(catesTree);
|
||||
|
||||
|
||||
c.RenderArgs["cates"] = cates
|
||||
c.RenderArgs["catesTree"] = catesTree
|
||||
}
|
||||
@@ -352,9 +348,10 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
|
||||
// 得到主题信息
|
||||
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
|
||||
c.RenderArgs["themeInfo"] = themeInfo
|
||||
Log(">>")
|
||||
Log(userBlog.Style)
|
||||
Log(userBlog.ThemeId.Hex())
|
||||
|
||||
// Log(">>")
|
||||
// Log(userBlog.Style)
|
||||
// Log(userBlog.ThemeId.Hex())
|
||||
|
||||
return true, userBlog
|
||||
}
|
||||
@@ -510,6 +507,7 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re
|
||||
// 进入某个用户的博客
|
||||
var blogPageSize = 5
|
||||
var searchBlogPageSize = 30
|
||||
|
||||
// 分类 /cate/xxxxxxxx?notebookId=1212
|
||||
func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
|
||||
// 自定义域名
|
||||
@@ -824,7 +822,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
|
||||
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
||||
return c.RenderJsonP(callback, re)
|
||||
}
|
||||
func (c Blog) GetComments(noteId string) revel.Result {
|
||||
func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
||||
// 评论
|
||||
userId := c.GetUserId()
|
||||
page := c.GetPage()
|
||||
@@ -837,6 +835,10 @@ func (c Blog) GetComments(noteId string) revel.Result {
|
||||
result["commentUserInfo"] = commentUserInfo
|
||||
re.Item = result
|
||||
|
||||
if callback != "" {
|
||||
return c.RenderJsonP(callback, result)
|
||||
}
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/lea/captcha"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
// "strconv"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
// "strconv"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -22,22 +22,23 @@ type Captcha struct {
|
||||
}
|
||||
|
||||
type Ca string
|
||||
|
||||
func (r Ca) Apply(req *revel.Request, resp *revel.Response) {
|
||||
resp.WriteHeader(http.StatusOK, "image/png")
|
||||
resp.WriteHeader(http.StatusOK, "image/png")
|
||||
}
|
||||
|
||||
func (c Captcha) Get() revel.Result {
|
||||
c.Response.ContentType = "image/png"
|
||||
image, str := captcha.Fetch()
|
||||
image.WriteTo(c.Response.Out)
|
||||
|
||||
|
||||
sessionId := c.Session["_ID"]
|
||||
// LogJ(c.Session)
|
||||
// Log("------")
|
||||
// Log(str)
|
||||
// Log(sessionId)
|
||||
Log("..")
|
||||
// LogJ(c.Session)
|
||||
// Log("------")
|
||||
// Log(str)
|
||||
// Log(sessionId)
|
||||
Log("..")
|
||||
sessionService.SetCaptcha(sessionId, str)
|
||||
|
||||
|
||||
return c.Render()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/lea/netutil"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"fmt"
|
||||
// "strconv"
|
||||
// "strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -22,8 +22,8 @@ type File struct {
|
||||
// 上传的是博客logo
|
||||
// TODO logo不要设置权限, 另外的目录
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
re := c.uploadImage("blogLogo", "");
|
||||
|
||||
re := c.uploadImage("blogLogo", "")
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
@@ -34,48 +34,50 @@ func (c File) UploadBlogLogo() revel.Result {
|
||||
// 拖拉上传, pasteImage
|
||||
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
|
||||
func (c File) PasteImage(noteId string) revel.Result {
|
||||
re := c.uploadImage("pasteImage", "");
|
||||
|
||||
userId := c.GetUserId()
|
||||
note := noteService.GetNoteById(noteId)
|
||||
if note.UserId != "" {
|
||||
noteUserId := note.UserId.Hex()
|
||||
if noteUserId != userId {
|
||||
// 是否是有权限协作的
|
||||
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
|
||||
// 复制图片之, 图片复制给noteUserId
|
||||
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
|
||||
} else {
|
||||
// 怎么可能在这个笔记下paste图片呢?
|
||||
// 正常情况下不会
|
||||
re := c.uploadImage("pasteImage", "")
|
||||
|
||||
if noteId != "" {
|
||||
userId := c.GetUserId()
|
||||
note := noteService.GetNoteById(noteId)
|
||||
if note.UserId != "" {
|
||||
noteUserId := note.UserId.Hex()
|
||||
if noteUserId != userId {
|
||||
// 是否是有权限协作的
|
||||
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
|
||||
// 复制图片之, 图片复制给noteUserId
|
||||
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
|
||||
} else {
|
||||
// 怎么可能在这个笔记下paste图片呢?
|
||||
// 正常情况下不会
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 头像设置
|
||||
func (c File) UploadAvatar() revel.Result {
|
||||
re := c.uploadImage("logo", "");
|
||||
|
||||
re := c.uploadImage("logo", "")
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
|
||||
|
||||
if re.Ok {
|
||||
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
|
||||
if re.Ok {
|
||||
c.UpdateSession("Logo", re.Id);
|
||||
c.UpdateSession("Logo", re.Id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// leaui image plugin upload image
|
||||
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||
re := c.uploadImage("", albumId);
|
||||
re := c.uploadImage("", albumId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -84,74 +86,82 @@ func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||
func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
var fileUrlPath = ""
|
||||
var fileId = ""
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultMsg = "error" // 错误信息
|
||||
var Ok = false
|
||||
|
||||
|
||||
defer func() {
|
||||
re.Id = fileId // 只是id, 没有其它信息
|
||||
re.Code = resultCode
|
||||
re.Msg = resultMsg
|
||||
re.Ok = Ok
|
||||
}()
|
||||
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 生成上传路径
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||
newGuid := NewGuid()
|
||||
|
||||
userId := c.GetUserId()
|
||||
|
||||
if from == "logo" || from == "blogLogo" {
|
||||
fileUrlPath = "public/upload/" + Digest3(userId) + "/" + userId + "/images/logo"
|
||||
} else {
|
||||
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||
// fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
|
||||
fileUrlPath = "files/" + GetRandomFilePath(userId, newGuid) + "/images"
|
||||
}
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
|
||||
var ext string;
|
||||
|
||||
var ext string
|
||||
if from == "pasteImage" {
|
||||
ext = ".png"; // TODO 可能不是png类型
|
||||
handel.Filename = c.Message("unTitled")
|
||||
ext = ".png" // TODO 可能不是png类型
|
||||
} else {
|
||||
_, 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"
|
||||
return re
|
||||
}
|
||||
}
|
||||
|
||||
filename = NewGuid() + ext
|
||||
filename = newGuid + ext
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
return re
|
||||
}
|
||||
|
||||
|
||||
var maxFileSize float64
|
||||
if(from == "logo") {
|
||||
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
|
||||
if from == "logo" {
|
||||
maxFileSize = configService.GetUploadSize("uploadAvatarSize")
|
||||
} else if from == "blogLogo" {
|
||||
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
|
||||
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize")
|
||||
} else {
|
||||
maxFileSize = configService.GetUploadSize("uploadImageSize");
|
||||
maxFileSize = configService.GetUploadSize("uploadImageSize")
|
||||
}
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
|
||||
|
||||
// > 2M?
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
if float64(len(data)) > maxFileSize*float64(1024*1024) {
|
||||
resultCode = 0
|
||||
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
toPath := dir + "/" + filename;
|
||||
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
@@ -164,26 +174,27 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
fileUrlPath += "/" + filename
|
||||
resultCode = 1
|
||||
resultMsg = "Upload Success!"
|
||||
|
||||
|
||||
// File
|
||||
fileInfo := info.File{Name: filename,
|
||||
Title: handel.Filename,
|
||||
Path: fileUrlPath,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId();
|
||||
Path: fileUrlPath,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId()
|
||||
fileInfo.FileId = id
|
||||
fileId = id.Hex()
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||
|
||||
if from == "logo" || from == "blogLogo" {
|
||||
fileId = fileUrlPath
|
||||
}
|
||||
|
||||
|
||||
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
|
||||
resultMsg = c.Message(resultMsg)
|
||||
|
||||
fileInfo.Path = ""; // 不要返回
|
||||
|
||||
fileInfo.Path = "" // 不要返回
|
||||
re.Item = fileInfo
|
||||
|
||||
|
||||
return re
|
||||
}
|
||||
|
||||
@@ -204,18 +215,19 @@ func (c File) DeleteImage(fileId string) revel.Result {
|
||||
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//-----------
|
||||
|
||||
// 输出image
|
||||
// 权限判断
|
||||
func (c File) OutputImage(noteId, fileId string) revel.Result {
|
||||
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
|
||||
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
|
||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||
file, _ := os.Open(fn)
|
||||
return c.RenderFile(file, revel.Inline) // revel.Attachment
|
||||
}
|
||||
|
||||
// 协作时复制图片到owner
|
||||
@@ -226,35 +238,40 @@ func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 复制外网的图片, 成公共图片 放在/upload下
|
||||
// 复制外网的图片
|
||||
// 都要好好的计算大小
|
||||
func (c File) CopyHttpImage(src string) revel.Result {
|
||||
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"
|
||||
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
filesize, filename, _, ok := netutil.WriteUrl(src, dir)
|
||||
|
||||
|
||||
if !ok {
|
||||
re.Msg = "copy error"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
// File
|
||||
fileInfo := info.File{Name: filename,
|
||||
Title: filename,
|
||||
Path: fileUrlPath + "/" + filename,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId();
|
||||
Path: fileUrlPath + "/" + filename,
|
||||
Size: filesize}
|
||||
|
||||
id := bson.NewObjectId()
|
||||
fileInfo.FileId = id
|
||||
|
||||
|
||||
re.Id = id.Hex()
|
||||
re.Item = fileInfo.Path
|
||||
// re.Item = fileInfo.Path
|
||||
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
)
|
||||
|
||||
// 首页
|
||||
@@ -13,32 +13,32 @@ type Index struct {
|
||||
}
|
||||
|
||||
func (c Index) Default() revel.Result {
|
||||
if configService.HomePageIsAdminsBlog(){
|
||||
if configService.HomePageIsAdminsBlog() {
|
||||
blog := Blog{c.BaseController}
|
||||
return blog.Index(configService.GetAdminUsername());
|
||||
return blog.Index(configService.GetAdminUsername())
|
||||
}
|
||||
return c.Index()
|
||||
}
|
||||
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Index) Index() revel.Result {
|
||||
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "leanote"
|
||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||
lang := c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("home/index_" + lang + ".html");
|
||||
c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("home/index.html")
|
||||
}
|
||||
|
||||
// 建议
|
||||
func (c Index) Suggestion(addr, suggestion string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = suggestionService.AddSuggestion(info.Suggestion{Addr: addr, UserId: c.GetObjectUserId(), Suggestion: suggestion})
|
||||
|
||||
|
||||
// 发给我
|
||||
go func() {
|
||||
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: " + c.GetUserId() + " <br /> Suggestions: " + suggestion)
|
||||
}();
|
||||
|
||||
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: "+c.GetUserId()+" <br /> Suggestions: "+suggestion)
|
||||
}()
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@ type NoteContentHistory struct {
|
||||
// 得到list
|
||||
func (c NoteContentHistory) ListHistories(noteId string) revel.Result {
|
||||
histories := noteContentHistoryService.ListHistories(noteId, c.GetUserId())
|
||||
|
||||
|
||||
return c.RenderJson(histories)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,20 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
// "time"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "bytes"
|
||||
// "os"
|
||||
"time"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
"fmt"
|
||||
// "bytes"
|
||||
// "os"
|
||||
)
|
||||
|
||||
type Note struct {
|
||||
@@ -22,55 +25,56 @@ type Note struct {
|
||||
// 笔记首页, 判断是否已登录
|
||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||
// 否则, 转向登录页面
|
||||
func (c Note) Index(noteId string) revel.Result {
|
||||
func (c Note) Index(noteId, online string) revel.Result {
|
||||
c.SetLocale()
|
||||
userInfo := c.GetUserInfo()
|
||||
|
||||
userInfo := c.GetUserAndBlogUrl()
|
||||
|
||||
userId := userInfo.UserId.Hex()
|
||||
|
||||
|
||||
// 没有登录
|
||||
if userId == "" {
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
|
||||
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
||||
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
|
||||
|
||||
// 还需要按时间排序(DESC)得到notes
|
||||
notes := []info.Note{}
|
||||
noteContent := info.NoteContent{}
|
||||
|
||||
|
||||
if len(notebooks) > 0 {
|
||||
// noteId是否存在
|
||||
// 是否传入了正确的noteId
|
||||
hasRightNoteId := false
|
||||
if IsObjectId(noteId) {
|
||||
note := noteService.GetNoteById(noteId)
|
||||
var noteOwner = note.UserId.Hex()
|
||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||
|
||||
|
||||
if note.NoteId != "" {
|
||||
var noteOwner = note.UserId.Hex()
|
||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||
|
||||
hasRightNoteId = true
|
||||
c.RenderArgs["curNoteId"] = noteId
|
||||
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
||||
|
||||
|
||||
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
|
||||
if noteOwner != c.GetUserId() {
|
||||
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
|
||||
// 不要获取notebook下的笔记
|
||||
// 在前端下发请求
|
||||
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
|
||||
c.RenderArgs["curSharedUserId"] = noteOwner;
|
||||
// 没有读写权限
|
||||
c.RenderArgs["curSharedUserId"] = noteOwner
|
||||
// 没有读写权限
|
||||
} else {
|
||||
hasRightNoteId = false
|
||||
}
|
||||
} else {
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false)
|
||||
|
||||
// 如果指定了某笔记, 则该笔记放在首位
|
||||
lenNotes := len(notes)
|
||||
if lenNotes > 1 {
|
||||
@@ -80,7 +84,7 @@ func (c Note) Index(noteId string) revel.Result {
|
||||
for _, note := range notes {
|
||||
if note.NoteId.Hex() != noteId {
|
||||
if i == lenNotes { // 防止越界
|
||||
break;
|
||||
break
|
||||
}
|
||||
notes2[i] = note
|
||||
i++
|
||||
@@ -90,42 +94,43 @@ func (c Note) Index(noteId string) revel.Result {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 得到最近的笔记
|
||||
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
||||
c.RenderArgs["latestNotes"] = latestNotes
|
||||
}
|
||||
|
||||
|
||||
// 没有传入笔记
|
||||
// 那么得到最新笔记
|
||||
if !hasRightNoteId {
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
||||
if len(notes) > 0 {
|
||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
||||
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 当然, 还需要得到第一个notes的content
|
||||
//...
|
||||
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["notebooks"] = notebooks
|
||||
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
|
||||
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
|
||||
|
||||
|
||||
c.RenderArgs["notes"] = notes
|
||||
c.RenderArgs["noteContentJson"] = noteContent
|
||||
c.RenderArgs["noteContent"] = noteContent.Content
|
||||
|
||||
|
||||
c.RenderArgs["tags"] = tagService.GetTags(c.GetUserId())
|
||||
|
||||
|
||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||
|
||||
// return c.RenderTemplate("note/note.html")
|
||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||
|
||||
// return c.RenderTemplate("note/note.html")
|
||||
|
||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev && online == "" {
|
||||
return c.RenderTemplate("note/note-dev.html")
|
||||
} else {
|
||||
return c.RenderTemplate("note/note.html")
|
||||
@@ -136,13 +141,13 @@ func (c Note) Index(noteId string) revel.Result {
|
||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||
// 否则, 转向登录页面
|
||||
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)
|
||||
}
|
||||
|
||||
// 得到trash
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -157,125 +162,139 @@ func (c Note) GetNoteContent(noteId string) revel.Result {
|
||||
return c.RenderJson(noteContent)
|
||||
}
|
||||
|
||||
// 更新note或content
|
||||
// 肯定会传userId(谁的), NoteId
|
||||
// 会传Title, Content, Tags, 一种或几种
|
||||
type NoteOrContent struct {
|
||||
NotebookId string
|
||||
NoteId string
|
||||
UserId string
|
||||
Title string
|
||||
Desc string
|
||||
ImgSrc string
|
||||
Tags string
|
||||
Content string
|
||||
Abstract string
|
||||
IsNew bool
|
||||
IsMarkdown bool
|
||||
FromUserId string // 为共享而新建
|
||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
||||
}
|
||||
// 这里不能用json, 要用post
|
||||
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result {
|
||||
// 新添加note
|
||||
if noteOrContent.IsNew {
|
||||
userId := c.GetObjectUserId();
|
||||
// myUserId := userId
|
||||
userId := c.GetObjectUserId()
|
||||
// myUserId := userId
|
||||
// 为共享新建?
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
}
|
||||
|
||||
note := info.Note{UserId: userId,
|
||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||
Title: noteOrContent.Title,
|
||||
Tags: strings.Split(noteOrContent.Tags, ","),
|
||||
Desc: noteOrContent.Desc,
|
||||
ImgSrc: noteOrContent.ImgSrc,
|
||||
IsBlog: noteOrContent.IsBlog,
|
||||
|
||||
note := info.Note{UserId: userId,
|
||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||
Title: noteOrContent.Title,
|
||||
Tags: strings.Split(noteOrContent.Tags, ","),
|
||||
Desc: noteOrContent.Desc,
|
||||
ImgSrc: noteOrContent.ImgSrc,
|
||||
IsBlog: noteOrContent.IsBlog,
|
||||
IsMarkdown: noteOrContent.IsMarkdown,
|
||||
};
|
||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
||||
UserId: userId,
|
||||
IsBlog: note.IsBlog,
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract};
|
||||
|
||||
}
|
||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
||||
UserId: userId,
|
||||
IsBlog: note.IsBlog,
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract}
|
||||
|
||||
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||
return c.RenderJson(note)
|
||||
}
|
||||
|
||||
|
||||
noteUpdate := bson.M{}
|
||||
needUpdateNote := false
|
||||
|
||||
|
||||
// Desc前台传来
|
||||
if c.Has("Desc") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Desc"] = noteOrContent.Desc;
|
||||
noteUpdate["Desc"] = noteOrContent.Desc
|
||||
}
|
||||
if c.Has("ImgSrc") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc;
|
||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
|
||||
}
|
||||
if c.Has("Title") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Title"] = noteOrContent.Title;
|
||||
noteUpdate["Title"] = noteOrContent.Title
|
||||
}
|
||||
|
||||
|
||||
if c.Has("Tags") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",");
|
||||
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",")
|
||||
}
|
||||
|
||||
|
||||
// web端不控制
|
||||
if needUpdateNote {
|
||||
noteService.UpdateNote(c.GetUserId(),
|
||||
if needUpdateNote {
|
||||
noteService.UpdateNote(c.GetUserId(),
|
||||
noteOrContent.NoteId, noteUpdate, -1)
|
||||
}
|
||||
|
||||
|
||||
//-------------
|
||||
afterContentUsn := 0
|
||||
contentOk := false
|
||||
contentMsg := ""
|
||||
if c.Has("Content") {
|
||||
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
||||
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
||||
// 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)
|
||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract,
|
||||
needUpdateNote, -1, time.Now())
|
||||
}
|
||||
|
||||
|
||||
Log(afterContentUsn)
|
||||
Log(contentOk)
|
||||
Log(contentMsg)
|
||||
|
||||
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
|
||||
// 删除note/ 删除别人共享给我的笔记
|
||||
// userId 是note.UserId
|
||||
func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
|
||||
if(!isShared) {
|
||||
return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
|
||||
func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result {
|
||||
if !isShared {
|
||||
for _, noteId := range noteIds {
|
||||
trashService.DeleteNote(noteId, c.GetUserId())
|
||||
}
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
|
||||
return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
|
||||
|
||||
for _, noteId := range noteIds {
|
||||
trashService.DeleteSharedNote(noteId, c.GetUserId())
|
||||
}
|
||||
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
// 删除trash
|
||||
|
||||
// 删除trash, 已弃用, 用DeleteNote
|
||||
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
|
||||
func (c Note) MoveNote(noteId, notebookId string) revel.Result {
|
||||
return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
|
||||
func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result {
|
||||
userId := c.GetUserId()
|
||||
for _, noteId := range noteIds {
|
||||
noteService.MoveNote(noteId, notebookId, userId)
|
||||
}
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
|
||||
// 复制note
|
||||
func (c Note) CopyNote(noteId, notebookId string) revel.Result {
|
||||
return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
|
||||
func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result {
|
||||
copyNotes := make([]info.Note, len(noteIds))
|
||||
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(noteId, notebookId, fromUserId string) revel.Result {
|
||||
return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
|
||||
func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) revel.Result {
|
||||
copyNotes := make([]info.Note, len(noteIds))
|
||||
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)
|
||||
}
|
||||
|
||||
//------------
|
||||
@@ -285,14 +304,178 @@ func (c Note) SearchNote(key string) revel.Result {
|
||||
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
||||
return c.RenderJson(blogs)
|
||||
}
|
||||
|
||||
// 通过tags搜索
|
||||
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
||||
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
||||
return c.RenderJson(blogs)
|
||||
}
|
||||
|
||||
// 设置/取消Blog; 置顶
|
||||
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||
return c.RenderJson(re)
|
||||
// 生成PDF
|
||||
func (c Note) ToPdf(noteId, appKey string) revel.Result {
|
||||
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
|
||||
appKeyTrue, _ := revel.Config.String("app.secret")
|
||||
if appKeyTrue != appKey {
|
||||
return c.RenderText("auth error")
|
||||
}
|
||||
note := noteService.GetNoteById(noteId)
|
||||
if note.NoteId == "" {
|
||||
return c.RenderText("no note")
|
||||
}
|
||||
|
||||
noteUserId := note.UserId.Hex()
|
||||
content := noteService.GetNoteContent(noteId, 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)
|
||||
}
|
||||
|
||||
siteUrlPattern = "(?:" + siteUrlPattern + ")*"
|
||||
|
||||
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["content"] = contentStr
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
userBlog := blogService.GetUserBlog(noteUserId)
|
||||
c.RenderArgs["userBlog"] = userBlog
|
||||
|
||||
return c.RenderTemplate("file/pdf.html")
|
||||
}
|
||||
|
||||
// 导出成PDF
|
||||
func (c Note) ExportPdf(noteId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
userId := c.GetUserId()
|
||||
note := noteService.GetNoteById(noteId)
|
||||
if note.NoteId == "" {
|
||||
re.Msg = "No Note"
|
||||
return c.RenderText("error")
|
||||
}
|
||||
|
||||
noteUserId := note.UserId.Hex()
|
||||
// 是否有权限
|
||||
if noteUserId != userId {
|
||||
// 是否是有权限协作的
|
||||
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
||||
re.Msg = "No Perm"
|
||||
return c.RenderText("No Perm")
|
||||
}
|
||||
}
|
||||
|
||||
// path 判断是否需要重新生成之
|
||||
guid := NewGuid()
|
||||
fileUrlPath := "files/export_pdf"
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
if !MkdirAll(dir) {
|
||||
return c.RenderText("error, no dir")
|
||||
}
|
||||
filename := guid + ".pdf"
|
||||
path := dir + "/" + filename
|
||||
|
||||
// leanote.com的secret
|
||||
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
|
||||
// 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 + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||
} else {
|
||||
cc = binPath + " --lowquality \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
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 {
|
||||
filenameReturn += ".pdf"
|
||||
}
|
||||
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
|
||||
}
|
||||
|
||||
// 设置/取消Blog; 置顶
|
||||
func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
|
||||
for _, noteId := range noteIds {
|
||||
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||
}
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
type Notebook struct {
|
||||
@@ -30,22 +30,23 @@ func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
||||
|
||||
// 添加notebook
|
||||
func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.Result {
|
||||
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||
Title: title,
|
||||
Seq: -1,
|
||||
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||
Title: title,
|
||||
Seq: -1,
|
||||
UserId: c.GetObjectUserId()}
|
||||
if(parentNotebookId != "") {
|
||||
if parentNotebookId != "" {
|
||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
||||
}
|
||||
|
||||
re, notebook := notebookService.AddNotebook(notebook)
|
||||
|
||||
if(re) {
|
||||
|
||||
if re {
|
||||
return c.RenderJson(notebook)
|
||||
} else {
|
||||
return c.RenderJson(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改标题
|
||||
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
||||
@@ -53,21 +54,22 @@ func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||
|
||||
// 排序
|
||||
// 无用
|
||||
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
||||
}
|
||||
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||
// return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
||||
// }
|
||||
|
||||
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
|
||||
type DragNotebooksInfo struct {
|
||||
CurNotebookId string
|
||||
CurNotebookId string
|
||||
ParentNotebookId string
|
||||
Siblings []string
|
||||
Siblings []string
|
||||
}
|
||||
|
||||
// 传过来的data是JSON.stringfy数据
|
||||
func (c Notebook) DragNotebooks(data string) revel.Result {
|
||||
info := DragNotebooksInfo{}
|
||||
json.Unmarshal([]byte(data), &info)
|
||||
|
||||
|
||||
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
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")
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "strings"
|
||||
// "time"
|
||||
// "strings"
|
||||
// "time"
|
||||
// "encoding/json"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/lea/blog"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/lea/blog"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "math"
|
||||
@@ -23,7 +23,7 @@ type Preview struct {
|
||||
// 得到要预览的主题绝对路径
|
||||
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
||||
if themeId != "" {
|
||||
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
|
||||
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了, 待优化, 有时会取不到
|
||||
} else {
|
||||
themeId = c.Session["themeId"] // 直接从session中获取
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
||||
return false
|
||||
}
|
||||
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
||||
|
||||
|
||||
c.RenderArgs["isPreview"] = true
|
||||
c.RenderArgs["themeId"] = themeId
|
||||
c.RenderArgs["themeInfoPreview"] = theme.Info
|
||||
@@ -47,7 +47,7 @@ func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Index(c.GetUserId())
|
||||
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||
}
|
||||
|
||||
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
||||
@@ -61,43 +61,43 @@ func (c Preview) Tags(userIdOrEmail string) revel.Result {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Tags(c.GetUserId())
|
||||
// if tag == "" {
|
||||
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// }
|
||||
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// if tag == "" {
|
||||
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// }
|
||||
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
|
||||
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Cate(userIdOrEmail, notebookId)
|
||||
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Post(userIdOrEmail, noteId)
|
||||
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Single(userIdOrEmail, singleId)
|
||||
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Search(c.GetUserId(), keywords)
|
||||
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
)
|
||||
|
||||
type Share struct {
|
||||
@@ -19,20 +19,20 @@ type Share struct {
|
||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
// 自己不能给自己添加共享
|
||||
myEmail := c.GetEmail();
|
||||
myEmail := c.GetEmail()
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
if(myEmail != email) {
|
||||
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email);
|
||||
if myEmail != email {
|
||||
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email)
|
||||
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
|
||||
|
||||
|
||||
} else {
|
||||
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return c.RenderJson(status)
|
||||
}
|
||||
|
||||
@@ -40,19 +40,19 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
// 自己不能给自己添加共享
|
||||
myEmail := c.GetEmail();
|
||||
myEmail := c.GetEmail()
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
if(myEmail != email) {
|
||||
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email);
|
||||
if myEmail != email {
|
||||
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email)
|
||||
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
|
||||
} else {
|
||||
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return c.RenderJson(status)
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
|
||||
// 表示是默认笔记本, 不是某个特定notebook的共享
|
||||
var notes []info.ShareNoteWithPerm
|
||||
if notebookId == "" {
|
||||
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false);
|
||||
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false)
|
||||
return c.RenderJson(notes)
|
||||
} else {
|
||||
// 有notebookId的
|
||||
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false));
|
||||
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,106 +83,110 @@ func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
|
||||
// 还要查看该note的notebookId分享的信息
|
||||
func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
||||
note := noteService.GetNote(noteId, c.GetUserId())
|
||||
|
||||
|
||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||
|
||||
|
||||
c.RenderArgs["isNote"] = true
|
||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex()
|
||||
c.RenderArgs["title"] = note.Title
|
||||
|
||||
|
||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||
}
|
||||
func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
||||
notebook := notebookService.GetNotebook(notebookId, c.GetUserId())
|
||||
|
||||
|
||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
||||
|
||||
|
||||
c.RenderArgs["isNote"] = false
|
||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex()
|
||||
c.RenderArgs["title"] = notebook.Title
|
||||
|
||||
|
||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||
}
|
||||
|
||||
//------------
|
||||
// 改变share note 权限
|
||||
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId));
|
||||
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId))
|
||||
}
|
||||
|
||||
// 改变share notebook 权限
|
||||
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId));
|
||||
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId))
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 删除share note
|
||||
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId));
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId))
|
||||
}
|
||||
|
||||
// 删除share notebook
|
||||
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId));
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId))
|
||||
}
|
||||
|
||||
// 删除share note, 被共享方删除
|
||||
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()));
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()))
|
||||
}
|
||||
|
||||
// 删除share notebook, 被共享方删除
|
||||
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()));
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()))
|
||||
}
|
||||
|
||||
// 删除fromUserId分享给我的所有note, notebook
|
||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()))
|
||||
}
|
||||
|
||||
//-------------
|
||||
// 用户组
|
||||
|
||||
|
||||
// 将笔记分享给分组
|
||||
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
|
||||
return c.RenderJson(re);
|
||||
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
|
||||
return c.RenderJson(re);
|
||||
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 更新, 也是一样, 先删后加
|
||||
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
|
||||
return c.AddShareNoteGroup(noteId, groupId, perm)
|
||||
}
|
||||
|
||||
|
||||
//------
|
||||
|
||||
// 将笔记分享给分组
|
||||
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
|
||||
return c.RenderJson(re);
|
||||
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
|
||||
return c.RenderJson(re);
|
||||
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 更新, 也是一样, 先删后加
|
||||
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "os/exec"
|
||||
// "os/exec"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
@@ -27,4 +27,4 @@ func (c Tag) DeleteTag(tag string) revel.Result {
|
||||
ret.Ok = true
|
||||
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
|
||||
return c.RenderJson(ret)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -29,59 +29,59 @@ func (c User) Account(tab int) revel.Result {
|
||||
|
||||
// 修改用户名, 需要重置session
|
||||
func (c User) UpdateUsername(username string) revel.Result {
|
||||
re := info.NewRe();
|
||||
if(c.GetUsername() == "demo") {
|
||||
re := info.NewRe()
|
||||
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
|
||||
re.Msg = "cannotUpdateDemo"
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
|
||||
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
|
||||
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
|
||||
if(re.Ok) {
|
||||
if re.Ok {
|
||||
c.UpdateSession("Username", username)
|
||||
}
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
if(c.GetUsername() == "demo") {
|
||||
re := info.NewRe()
|
||||
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
|
||||
re.Msg = "cannotUpdateDemo"
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 更新主题
|
||||
func (c User) UpdateTheme(theme string) revel.Result {
|
||||
re := info.NewRe();
|
||||
re := info.NewRe()
|
||||
re.Ok = userService.UpdateTheme(c.GetUserId(), theme)
|
||||
if re.Ok {
|
||||
c.UpdateSession("Theme", theme)
|
||||
}
|
||||
return c.RenderJson(re);
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 发送邀请链接
|
||||
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
||||
re := info.NewRe()
|
||||
if content == "" || !IsEmail(toEmail) {
|
||||
return c.RenderJson(re);
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
|
||||
return c.RenderJson(re);
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
@@ -93,79 +93,43 @@ func (c User) ReSendActiveEmail() revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 修改Email发送激活邮箱
|
||||
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
|
||||
re := info.NewRe()
|
||||
if(c.GetUsername() == "demo") {
|
||||
re.Msg = "cannotUpdateDemo"
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = emailService.UpdateEmailSendActiveEmail(c.GetUserInfo(), email)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 通过点击链接
|
||||
// 修改邮箱
|
||||
func (c User) UpdateEmail(token string) revel.Result {
|
||||
c.SetUserInfo();
|
||||
|
||||
c.SetUserInfo()
|
||||
|
||||
ok, msg, email := userService.UpdateEmail(token)
|
||||
|
||||
|
||||
c.RenderArgs["title"] = "验证邮箱"
|
||||
c.RenderArgs["ok"] = ok
|
||||
c.RenderArgs["msg"] = msg
|
||||
c.RenderArgs["email"] = email
|
||||
|
||||
|
||||
// 修改session
|
||||
if ok {
|
||||
c.UpdateSession("Email", email)
|
||||
}
|
||||
|
||||
|
||||
return c.RenderTemplate("user/update_email.html")
|
||||
}
|
||||
|
||||
// 注册后激活邮箱
|
||||
func (c User) ActiveEmail(token string) revel.Result {
|
||||
c.SetUserInfo();
|
||||
|
||||
c.SetUserInfo()
|
||||
|
||||
ok, msg, email := userService.ActiveEmail(token)
|
||||
|
||||
|
||||
// 需要修改session
|
||||
if ok {
|
||||
c.UpdateSession("Verified", "1");
|
||||
c.UpdateSession("Verified", "1")
|
||||
}
|
||||
|
||||
|
||||
c.RenderArgs["title"] = "验证邮箱"
|
||||
c.RenderArgs["ok"] = ok
|
||||
c.RenderArgs["msg"] = msg
|
||||
c.RenderArgs["email"] = email
|
||||
|
||||
return c.RenderTemplate("user/active_email.html")
|
||||
}
|
||||
|
||||
//------------
|
||||
// 第三方账号添加leanote账号
|
||||
func (c User) AddAccount(email, pwd string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = userService.ThirdAddUser(c.GetUserId(), email, pwd)
|
||||
|
||||
if re.Ok {
|
||||
c.UpdateSession("Email", email);
|
||||
}
|
||||
|
||||
return c.RenderRe(re)
|
||||
return c.RenderTemplate("user/active_email.html")
|
||||
}
|
||||
|
||||
//-----------------
|
||||
@@ -174,10 +138,10 @@ func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int)
|
||||
re := info.NewRe()
|
||||
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth)
|
||||
if re.Ok {
|
||||
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
|
||||
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
|
||||
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth));
|
||||
|
||||
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth))
|
||||
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth))
|
||||
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth))
|
||||
|
||||
LogJ(c.Session)
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
@@ -187,10 +151,10 @@ func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
|
||||
re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin)
|
||||
if re.Ok {
|
||||
if leftIsMin {
|
||||
c.UpdateSession("LeftIsMin", "1");
|
||||
c.UpdateSession("LeftIsMin", "1")
|
||||
} else {
|
||||
c.UpdateSession("LeftIsMin", "0");
|
||||
c.UpdateSession("LeftIsMin", "0")
|
||||
}
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
// "github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "strconv"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -20,26 +20,26 @@ type AdminBaseController struct {
|
||||
|
||||
// 得到sorterField 和 isAsc
|
||||
// okSorter = ['email', 'username']
|
||||
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
|
||||
sorter := ""
|
||||
c.Params.Bind(&sorter, "sorter")
|
||||
if sorter == "" {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
|
||||
// sorter形式 email-up, email-down
|
||||
s2 := strings.Split(sorter, "-")
|
||||
if len(s2) != 2 {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
|
||||
// 必须是可用的sorter
|
||||
if okSorter != nil && len(okSorter) > 0 {
|
||||
if !InArray(okSorter, s2[0]) {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sorterField = strings.Title(s2[0])
|
||||
if s2[1] == "up" {
|
||||
isAsc = true
|
||||
@@ -47,7 +47,7 @@ func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter
|
||||
isAsc = false
|
||||
}
|
||||
c.RenderArgs["sorter"] = sorter
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
func (c AdminBaseController) updateConfig(keys []string) {
|
||||
@@ -56,4 +56,4 @@ func (c AdminBaseController) updateConfig(keys []string) {
|
||||
v := c.Params.Values.Get(key)
|
||||
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
@@ -15,16 +15,16 @@ type AdminBlog struct {
|
||||
// admin 主页
|
||||
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
|
||||
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"})
|
||||
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["blogs"] = blogs
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
return c.RenderTemplate("admin/blog/list.html");
|
||||
return c.RenderTemplate("admin/blog/list.html")
|
||||
}
|
||||
|
||||
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.SetRecommend(noteId, recommend);
|
||||
re.Ok = blogService.SetRecommend(noteId, recommend)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ type Admin struct {
|
||||
// admin 主页
|
||||
func (c Admin) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
|
||||
|
||||
c.RenderArgs["title"] = "leanote"
|
||||
c.SetLocale()
|
||||
|
||||
|
||||
c.RenderArgs["countUser"] = userService.CountUser()
|
||||
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||
|
||||
return c.RenderTemplate("admin/index.html");
|
||||
|
||||
return c.RenderTemplate("admin/index.html")
|
||||
}
|
||||
|
||||
// 模板
|
||||
@@ -35,5 +35,5 @@ func (c Admin) T(t string) revel.Result {
|
||||
}
|
||||
|
||||
func (c Admin) GetView(view string) revel.Result {
|
||||
return c.RenderTemplate("admin/" + view);
|
||||
}
|
||||
return c.RenderTemplate("admin/" + view)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"os"
|
||||
"io"
|
||||
"time"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 数据管理, 备份和恢复
|
||||
@@ -22,18 +22,18 @@ func (c AdminData) Index() revel.Result {
|
||||
// 逆序之
|
||||
backups2 := make([]map[string]string, len(backups))
|
||||
j := 0
|
||||
for i := len(backups)-1; i >= 0; i-- {
|
||||
for i := len(backups) - 1; i >= 0; i-- {
|
||||
backups2[j] = backups[i]
|
||||
j++
|
||||
}
|
||||
c.RenderArgs["backups"] = backups2
|
||||
return c.RenderTemplate("admin/data/index.html");
|
||||
return c.RenderTemplate("admin/data/index.html")
|
||||
}
|
||||
|
||||
func (c AdminData) Backup() revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = configService.Backup("")
|
||||
return c.RenderJson(re)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 还原
|
||||
@@ -51,7 +51,7 @@ func (c AdminData) Delete(createdTime string) revel.Result {
|
||||
func (c AdminData) UpdateRemark(createdTime, remark string) revel.Result {
|
||||
re := info.Re{}
|
||||
re.Ok, re.Msg = configService.UpdateBackupRemark(createdTime, remark)
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c AdminData) Download(createdTime string) revel.Result {
|
||||
@@ -59,56 +59,56 @@ func (c AdminData) Download(createdTime string) revel.Result {
|
||||
if !ok {
|
||||
return c.RenderText("")
|
||||
}
|
||||
|
||||
|
||||
dbname, _ := revel.Config.String("db.dbname")
|
||||
path := backup["path"] + "/" + dbname
|
||||
allFiles := ListDir(path)
|
||||
|
||||
allFiles := ListDir(path)
|
||||
|
||||
filename := "backup_" + dbname + "_" + backup["createdTime"] + ".tar.gz"
|
||||
|
||||
|
||||
// file write
|
||||
fw, err := os.Create(revel.BasePath + "/files/" + filename)
|
||||
if err != nil {
|
||||
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 _, file := range allFiles {
|
||||
}
|
||||
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
|
||||
// gzip write
|
||||
gw := gzip.NewWriter(fw)
|
||||
defer gw.Close()
|
||||
|
||||
// tar write
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
|
||||
// 遍历文件列表
|
||||
for _, file := range allFiles {
|
||||
fn := path + "/" + file
|
||||
fr, err := os.Open(fn)
|
||||
fileInfo, _ := fr.Stat()
|
||||
if err != nil {
|
||||
fr, err := os.Open(fn)
|
||||
fileInfo, _ := fr.Stat()
|
||||
if err != nil {
|
||||
return c.RenderText("")
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// 信息头
|
||||
h := new(tar.Header)
|
||||
h.Name = file
|
||||
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
|
||||
|
||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachm
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// 信息头
|
||||
h := new(tar.Header)
|
||||
h.Name = file
|
||||
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
|
||||
|
||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachm
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"strings"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -25,14 +25,14 @@ func (c AdminEmail) Blog() revel.Result {
|
||||
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
||||
return c.RenderTemplate("admin/setting/blog.html");
|
||||
return c.RenderTemplate("admin/setting/blog.html")
|
||||
}
|
||||
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -41,21 +41,24 @@ func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||
func (c AdminEmail) Demo() revel.Result {
|
||||
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||
return c.RenderTemplate("admin/setting/demo.html");
|
||||
return c.RenderTemplate("admin/setting/demo.html")
|
||||
}
|
||||
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
userInfo := authService.Login(demoUsername, demoPassword)
|
||||
|
||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
||||
if err != nil {
|
||||
return c.RenderJson(info.Re{Ok: false})
|
||||
}
|
||||
if userInfo.UserId == "" {
|
||||
re.Msg = "The User is Not Exists";
|
||||
re.Msg = "The User is Not Exists"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -63,7 +66,7 @@ func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||
// 长微博的bin路径phantomJs
|
||||
func (c AdminEmail) ToImage() revel.Result {
|
||||
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
||||
return c.RenderTemplate("admin/setting/toImage.html");
|
||||
return c.RenderTemplate("admin/setting/toImage.html")
|
||||
}
|
||||
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
|
||||
re := info.NewRe()
|
||||
@@ -71,19 +74,20 @@ func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword string) revel.Result {
|
||||
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emailSSL string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
|
||||
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c AdminEmail) Template() revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
keys := []string{"emailTemplateHeader", "emailTemplateFooter",
|
||||
|
||||
keys := []string{"emailTemplateHeader", "emailTemplateFooter",
|
||||
"emailTemplateRegisterSubject",
|
||||
"emailTemplateRegister",
|
||||
"emailTemplateFindPasswordSubject",
|
||||
@@ -95,7 +99,7 @@ func (c AdminEmail) Template() revel.Result {
|
||||
"emailTemplateCommentSubject",
|
||||
"emailTemplateComment",
|
||||
}
|
||||
|
||||
|
||||
userId := c.GetUserId()
|
||||
for _, key := range keys {
|
||||
v := c.Params.Values.Get(key)
|
||||
@@ -110,7 +114,7 @@ func (c AdminEmail) Template() revel.Result {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
re.Ok = true
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -118,100 +122,99 @@ func (c AdminEmail) Template() revel.Result {
|
||||
// 发送Email
|
||||
func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
|
||||
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
|
||||
|
||||
|
||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||
re.Msg = "subject or body is blank"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
if saveAsOldEmail {
|
||||
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||
oldEmails[latestEmailSubject] = latestEmailBody
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
|
||||
}
|
||||
|
||||
|
||||
sendEmails = strings.Replace(sendEmails, "\r", "", -1)
|
||||
emails := strings.Split(sendEmails, "\n")
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody);
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 发送Email
|
||||
func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
|
||||
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
|
||||
|
||||
|
||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||
re.Msg = "subject or body is blank"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
if saveAsOldEmail {
|
||||
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||
oldEmails[latestEmailSubject] = latestEmailBody
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
|
||||
}
|
||||
|
||||
|
||||
emails = strings.Replace(emails, "\r", "", -1)
|
||||
emailsArr := strings.Split(emails, "\n")
|
||||
|
||||
|
||||
users := userService.ListUserInfosByEmails(emailsArr)
|
||||
LogJ(emailsArr)
|
||||
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
|
||||
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// send Email dialog
|
||||
func (c AdminEmail) SendEmailDialog(emails string) revel.Result{
|
||||
func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
|
||||
emailsArr := strings.Split(emails, ",")
|
||||
emailsNl := strings.Join(emailsArr, "\n")
|
||||
|
||||
|
||||
c.RenderArgs["emailsNl"] = emailsNl
|
||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||
|
||||
return c.RenderTemplate("admin/email/emailDialog.html");
|
||||
|
||||
return c.RenderTemplate("admin/email/emailDialog.html")
|
||||
}
|
||||
|
||||
func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilterBlackList, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
|
||||
c.updateConfig([]string{"userFilterEmail", "userFilterWhiteList", "userFilterBlackList", "latestEmailSubject", "latestEmailBody"})
|
||||
|
||||
|
||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||
re.Msg = "subject or body is blank"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
if saveAsOldEmail {
|
||||
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||
oldEmails[latestEmailSubject] = latestEmailBody
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
|
||||
}
|
||||
|
||||
|
||||
users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified)
|
||||
|
||||
if(users == nil || len(users) == 0) {
|
||||
|
||||
if users == nil || len(users) == 0 {
|
||||
re.Ok = false
|
||||
re.Msg = "no users"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
|
||||
if(!re.Ok) {
|
||||
|
||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
||||
if !re.Ok {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
re.Ok = true
|
||||
re.Msg = "users:" + strconv.Itoa(len(users))
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -224,10 +227,10 @@ func (c AdminEmail) DeleteEmails(ids string) revel.Result {
|
||||
|
||||
func (c AdminEmail) List(sorter, keywords string) revel.Result {
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"});
|
||||
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"})
|
||||
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords)
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["emails"] = emails
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
return c.RenderTemplate("admin/email/list.html");
|
||||
}
|
||||
return c.RenderTemplate("admin/email/list.html")
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -25,24 +25,24 @@ func (c AdminSetting) Blog() revel.Result {
|
||||
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
||||
return c.RenderTemplate("admin/setting/blog.html");
|
||||
return c.RenderTemplate("admin/setting/blog.html")
|
||||
}
|
||||
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 共享设置
|
||||
func (c AdminSetting) ShareNote(registerSharedUserId string,
|
||||
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||
func (c AdminSetting) ShareNote(registerSharedUserId string,
|
||||
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result {
|
||||
|
||||
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds);
|
||||
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -51,33 +51,37 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
|
||||
func (c AdminSetting) Demo() revel.Result {
|
||||
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||
return c.RenderTemplate("admin/setting/demo.html");
|
||||
return c.RenderTemplate("admin/setting/demo.html")
|
||||
}
|
||||
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
userInfo := authService.Login(demoUsername, demoPassword)
|
||||
|
||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return c.RenderJson(info.Re{Ok: false})
|
||||
}
|
||||
if userInfo.UserId == "" {
|
||||
re.Msg = "The User is Not Exists";
|
||||
re.Msg = "The User is Not Exists"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
func (c AdminSetting) ExportPdf(path string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -85,23 +89,23 @@ func (c AdminSetting) DoToImage(toImageBinPath string) revel.Result {
|
||||
func (c AdminSetting) SubDomain() revel.Result {
|
||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||
|
||||
|
||||
c.RenderArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
|
||||
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
|
||||
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
|
||||
|
||||
return c.RenderTemplate("admin/setting/subDomain.html");
|
||||
|
||||
return c.RenderTemplate("admin/setting/subDomain.html")
|
||||
}
|
||||
func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, blackSubDomains, allowCustomDomain, blackCustomDomains string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "noteSubDomain", noteSubDomain)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "blogSubDomain", blogSubDomain)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "leaSubDomain", leaSubDomain)
|
||||
|
||||
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "allowCustomDomain", allowCustomDomain)
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackSubDomains", strings.Split(blackSubDomains, ","))
|
||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackCustomDomains", strings.Split(blackCustomDomains, ","))
|
||||
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -135,4 +139,4 @@ func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLo
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
// Upgrade controller
|
||||
@@ -14,7 +14,7 @@ type AdminUpgrade struct {
|
||||
|
||||
func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
||||
upgradeService.UpgradeBlog()
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
||||
@@ -27,4 +27,4 @@ func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "time"
|
||||
"github.com/revel/revel"
|
||||
// "time"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
@@ -15,37 +15,38 @@ type AdminUser struct {
|
||||
|
||||
// admin 主页
|
||||
var userPageSize = 10
|
||||
|
||||
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||
pageNumber := c.GetPage()
|
||||
if userPageSize == 0 {
|
||||
pageSize = userPageSize
|
||||
}
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
|
||||
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"})
|
||||
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords)
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["users"] = users
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
return c.RenderTemplate("admin/user/list.html");
|
||||
return c.RenderTemplate("admin/user/list.html")
|
||||
}
|
||||
|
||||
func (c AdminUser) Add() revel.Result {
|
||||
return c.RenderTemplate("admin/user/add.html");
|
||||
return c.RenderTemplate("admin/user/add.html")
|
||||
}
|
||||
|
||||
// 添加
|
||||
func (c AdminUser) Register(email, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
|
||||
re := info.NewRe()
|
||||
|
||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
||||
|
||||
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
@@ -53,14 +54,14 @@ func (c AdminUser) Register(email, pwd string) revel.Result {
|
||||
func (c AdminUser) ResetPwd(userId string) revel.Result {
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
return c.RenderTemplate("admin/user/reset_pwd.html");
|
||||
return c.RenderTemplate("admin/user/reset_pwd.html")
|
||||
}
|
||||
|
||||
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
re := info.NewRe()
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
// "strings"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
var userService *service.UserService
|
||||
@@ -19,9 +19,9 @@ 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 suggestionService *service.SuggestionService
|
||||
var albumService *service.AlbumService
|
||||
var noteImageService *service.NoteImageService
|
||||
var fileService *service.FileService
|
||||
var attachService *service.AttachService
|
||||
var configService *service.ConfigService
|
||||
@@ -31,31 +31,32 @@ var upgradeService *service.UpgradeService
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"SearchBlog": true,
|
||||
},
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
"ActiveEmail":true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"ActiveEmail": true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||
}
|
||||
|
||||
func needValidate(controller, method string) bool {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
@@ -66,33 +67,33 @@ func needValidate(controller, method string) bool {
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
// 全部变成首字大写
|
||||
/*
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// 验证是否已登录
|
||||
// 必须是管理员
|
||||
if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
|
||||
// 没有登录, 判断是否是ajax操作
|
||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
re := info.NewRe()
|
||||
re.Msg = "NOTLOGIN"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ func InitService() {
|
||||
tokenService = service.TokenS
|
||||
noteImageService = service.NoteImageS
|
||||
fileService = service.FileS
|
||||
albumService= service.AlbumS
|
||||
albumService = service.AlbumS
|
||||
attachService = service.AttachS
|
||||
pwdService = service.PwdS
|
||||
suggestionService = service.SuggestionS
|
||||
|
||||
@@ -24,8 +24,8 @@ type ApiAuth struct {
|
||||
func (c ApiAuth) Login(email, pwd string) revel.Result {
|
||||
var msg = ""
|
||||
|
||||
userInfo := authService.Login(email, pwd)
|
||||
if userInfo.Email != "" {
|
||||
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})
|
||||
@@ -66,4 +66,4 @@ func (c ApiAuth) Register(email, pwd string) revel.Result {
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ 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"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"os"
|
||||
// "fmt"
|
||||
// "fmt"
|
||||
"io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
@@ -43,73 +43,76 @@ func (c ApiBaseContrller) getUserInfo() info.User {
|
||||
|
||||
// 上传附件
|
||||
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
|
||||
userId := c.getUserId();
|
||||
|
||||
userId := c.getUserId()
|
||||
|
||||
// 判断是否有权限为笔记添加附件
|
||||
// 如果笔记还没有添加是不是会有问题
|
||||
/*
|
||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
return
|
||||
}
|
||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
file, handel, err := c.Request.FormFile(name)
|
||||
if err != nil {
|
||||
return
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return
|
||||
return
|
||||
}
|
||||
// > 5M?
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize")
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
msg = "fileIsTooLarge"
|
||||
return
|
||||
if float64(len(data)) > maxFileSize*float64(1024*1024) {
|
||||
msg = "fileIsTooLarge"
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 生成上传路径
|
||||
filePath := "files/" + userId + "/attachs"
|
||||
dir := revel.BasePath + "/" + filePath
|
||||
newGuid := NewGuid()
|
||||
// filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
|
||||
filePath := "files/" + GetRandomFilePath(userId, newGuid) + "/attachs"
|
||||
|
||||
dir := revel.BasePath + "/" + filePath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
return
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
_, ext := SplitFilename(filename) // .doc
|
||||
filename = NewGuid() + ext
|
||||
toPath := dir + "/" + filename;
|
||||
filename = newGuid + ext
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
return
|
||||
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),
|
||||
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}
|
||||
|
||||
Path: filePath + "/" + filename,
|
||||
Type: fileType,
|
||||
Size: filesize}
|
||||
|
||||
ok, msg = attachService.AddAttach(fileInfo, true)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
id = fileInfo.AttachId.Hex()
|
||||
return
|
||||
}
|
||||
@@ -121,12 +124,17 @@ func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok
|
||||
}
|
||||
file, handel, err := c.Request.FormFile(name)
|
||||
if err != nil {
|
||||
return
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
newGuid := NewGuid()
|
||||
// 生成上传路径
|
||||
fileUrlPath := "files/" + c.getUserId() + "/images"
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
userId := c.getUserId()
|
||||
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
|
||||
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
|
||||
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -134,45 +142,45 @@ func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
_, ext := SplitFilename(filename)
|
||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||
msg = "notImage"
|
||||
return
|
||||
}
|
||||
// if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
||||
// msg = "notImage"
|
||||
// return
|
||||
// }
|
||||
|
||||
filename = NewGuid() + ext
|
||||
filename = newGuid + ext
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
maxFileSize := configService.GetUploadSize("uploadImageSize");
|
||||
|
||||
maxFileSize := configService.GetUploadSize("uploadImageSize")
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
|
||||
|
||||
// > 2M?
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
if float64(len(data)) > maxFileSize*float64(1024*1024) {
|
||||
msg = "fileIsTooLarge"
|
||||
return
|
||||
}
|
||||
|
||||
toPath := dir + "/" + filename;
|
||||
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
return
|
||||
return
|
||||
}
|
||||
// 改变成gif图片
|
||||
_, toPathGif := TransToGif(toPath, 0, true)
|
||||
filename = GetFilename(toPathGif)
|
||||
filesize := GetFilesize(toPathGif)
|
||||
fileUrlPath += "/" + filename
|
||||
|
||||
|
||||
// File
|
||||
fileInfo := info.File{FileId: bson.NewObjectId(),
|
||||
Name: filename,
|
||||
Name: filename,
|
||||
Title: handel.Filename,
|
||||
Path: fileUrlPath,
|
||||
Size: filesize}
|
||||
Path: fileUrlPath,
|
||||
Size: filesize}
|
||||
ok, msg = fileService.AddImage(fileInfo, "", c.getUserId(), true)
|
||||
if ok {
|
||||
id = fileInfo.FileId.Hex()
|
||||
|
||||
@@ -3,18 +3,18 @@ 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"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/lea/netutil"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
"os"
|
||||
// "strconv"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"time"
|
||||
"strings"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 文件操作, 图片, 头像上传, 输出
|
||||
@@ -73,14 +73,14 @@ func (c ApiFile) GetImage(fileId string) revel.Result {
|
||||
// 下载附件
|
||||
// [OK]
|
||||
func (c ApiFile) GetAttach(fileId string) revel.Result {
|
||||
attach := attachService.GetAttach(fileId, c.getUserId()); // 得到路径
|
||||
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
|
||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||
file, _ := os.Open(fn)
|
||||
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
||||
}
|
||||
|
||||
// 下载所有附件
|
||||
@@ -95,70 +95,69 @@ func (c ApiFile) GetAllAttachs(noteId string) revel.Result {
|
||||
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("")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"regexp"
|
||||
"strings"
|
||||
"os"
|
||||
"os/exec"
|
||||
// "strings"
|
||||
"time"
|
||||
"regexp"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
@@ -56,7 +58,7 @@ func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
|
||||
// 得到笔记本下的笔记
|
||||
// [OK]
|
||||
func (c ApiNote) GetNotes(notebookId string) revel.Result {
|
||||
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
||||
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
||||
re := info.NewApiRe()
|
||||
re.Msg = "notebookIdInvalid"
|
||||
return c.RenderJson(re)
|
||||
@@ -70,6 +72,7 @@ func (c ApiNote) GetNotes(notebookId string) revel.Result {
|
||||
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
|
||||
@@ -82,7 +85,6 @@ func (c ApiNote) GetTrashNotes() revel.Result {
|
||||
"Title": "asdfadsf--=",
|
||||
"Desc": "",
|
||||
"Tags": [
|
||||
""
|
||||
],
|
||||
"Abstract": "",
|
||||
"Content": "",
|
||||
@@ -92,7 +94,7 @@ func (c ApiNote) GetTrashNotes() revel.Result {
|
||||
"Usn": 8,
|
||||
"Files": [
|
||||
{
|
||||
"FileId": "551975d599c37b970f000002",
|
||||
"FileId": "551975d599c37b970f000000",
|
||||
"LocalFileId": "",
|
||||
"Type": "",
|
||||
"Title": "",
|
||||
@@ -100,18 +102,18 @@ func (c ApiNote) GetTrashNotes() revel.Result {
|
||||
"IsAttach": false
|
||||
},
|
||||
{
|
||||
"FileId": "551975de99c37b970f000003",
|
||||
"FileId": "551975de99c37b970f000001",
|
||||
"LocalFileId": "",
|
||||
"Type": "doc",
|
||||
"Title": "李铁-简历-ali-print-en.doc",
|
||||
"Title": "李铁-print-en.doc",
|
||||
"HasBody": false,
|
||||
"IsAttach": true
|
||||
},
|
||||
{
|
||||
"FileId": "551975de99c37b970f000004",
|
||||
"FileId": "551975de99c37b970f000002",
|
||||
"LocalFileId": "",
|
||||
"Type": "doc",
|
||||
"Title": "李铁-简历-ali-print.doc",
|
||||
"Title": "李铁-print.doc",
|
||||
"HasBody": false,
|
||||
"IsAttach": true
|
||||
}
|
||||
@@ -122,12 +124,12 @@ func (c ApiNote) GetTrashNotes() revel.Result {
|
||||
}
|
||||
*/
|
||||
func (c ApiNote) GetNote(noteId string) revel.Result {
|
||||
if !bson.IsObjectIdHex(noteId) {
|
||||
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()
|
||||
@@ -142,71 +144,13 @@ func (c ApiNote) GetNote(noteId string) revel.Result {
|
||||
// [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
|
||||
apiNote.Content = noteService.FixContent(noteAndContent.Content, noteAndContent.IsMarkdown)
|
||||
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
|
||||
@@ -215,32 +159,54 @@ 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)
|
||||
LogJ(file)
|
||||
if !file.IsAttach {
|
||||
// <img src="https://"
|
||||
// 
|
||||
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getImage\?fileId=`+file.LocalFileId)
|
||||
// Log(reg)
|
||||
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getImage?fileId=`+file.FileId)
|
||||
|
||||
// // "http://a.com/api/file/getImage?fileId=localId" => /api/file/getImage?fileId=serverId
|
||||
// noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
||||
// baseUrl + "/api/file/getImage?fileId="+file.LocalFileId,
|
||||
// "/api/file/getImage?fileId="+file.FileId, -1)
|
||||
} else {
|
||||
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getAttach\?fileId=`+file.LocalFileId)
|
||||
Log(reg)
|
||||
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getAttach?fileId=`+file.FileId)
|
||||
/*
|
||||
noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
||||
baseUrl + "/api/file/getAttach?fileId="+file.LocalFileId,
|
||||
"/api/file/getAttach?fileId="+file.FileId, -1)
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 得到内容
|
||||
// [OK]
|
||||
func (c ApiNote) GetNoteContent(noteId string) revel.Result {
|
||||
userId := c.getUserId()
|
||||
note := noteService.GetNote(noteId, userId)
|
||||
// re := info.NewRe()
|
||||
noteContent := noteService.GetNoteContent(noteId, c.getUserId())
|
||||
noteContent := noteService.GetNoteContent(noteId, userId)
|
||||
if noteContent.Content != "" {
|
||||
noteContent.Content = c.fixContent(noteContent.Content)
|
||||
noteContent.Content = noteService.FixContent(noteContent.Content, note.IsMarkdown)
|
||||
}
|
||||
|
||||
|
||||
apiNoteContent := info.ApiNoteContent{
|
||||
NoteId: noteContent.NoteId,
|
||||
UserId: noteContent.UserId,
|
||||
NoteId: noteContent.NoteId,
|
||||
UserId: noteContent.UserId,
|
||||
Content: noteContent.Content,
|
||||
}
|
||||
|
||||
// re.Item = noteContent
|
||||
|
||||
return c.RenderJson(apiNoteContent)
|
||||
}
|
||||
|
||||
@@ -252,12 +218,13 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
||||
myUserId := userId
|
||||
// 为共享新建?
|
||||
/*
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
}
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
}
|
||||
*/
|
||||
// Log(noteOrContent.Title)
|
||||
// LogJ(noteOrContent)
|
||||
// LogJ(noteOrContent)
|
||||
|
||||
/*
|
||||
LogJ(c.Params)
|
||||
for name, _ := range c.Params.Files {
|
||||
@@ -312,8 +279,8 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
||||
|
||||
c.fixPostNotecontent(¬eOrContent)
|
||||
|
||||
// Log("Add")
|
||||
// LogJ(noteOrContent)
|
||||
// Log("Add")
|
||||
// LogJ(noteOrContent)
|
||||
|
||||
// return c.RenderJson(re)
|
||||
|
||||
@@ -323,23 +290,32 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
||||
Title: noteOrContent.Title,
|
||||
Tags: noteOrContent.Tags,
|
||||
Desc: noteOrContent.Desc,
|
||||
// ImgSrc: noteOrContent.ImgSrc,
|
||||
IsBlog: noteOrContent.IsBlog,
|
||||
IsMarkdown: noteOrContent.IsMarkdown,
|
||||
AttachNum: attachNum,
|
||||
// ImgSrc: noteOrContent.ImgSrc,
|
||||
IsBlog: noteOrContent.IsBlog,
|
||||
IsMarkdown: noteOrContent.IsMarkdown,
|
||||
AttachNum: attachNum,
|
||||
CreatedTime: noteOrContent.CreatedTime,
|
||||
UpdatedTime: noteOrContent.UpdatedTime,
|
||||
}
|
||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
||||
UserId: userId,
|
||||
IsBlog: note.IsBlog,
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract}
|
||||
UserId: userId,
|
||||
IsBlog: note.IsBlog,
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract,
|
||||
CreatedTime: noteOrContent.CreatedTime,
|
||||
UpdatedTime: noteOrContent.UpdatedTime,
|
||||
}
|
||||
|
||||
// 通过内容得到Desc, abstract
|
||||
note.Desc = SubStringHTMLToRaw(noteContent.Content, 50)
|
||||
noteContent.Abstract = SubStringHTML(noteContent.Content, 200, "")
|
||||
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)
|
||||
@@ -352,7 +328,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
||||
noteOrContent.UpdatedTime = note.UpdatedTime
|
||||
noteOrContent.UserId = c.getUserId()
|
||||
noteOrContent.IsMarkdown = note.IsMarkdown
|
||||
// 删除一些不要返回的
|
||||
// 删除一些不要返回的, 删除Desc?
|
||||
noteOrContent.Content = ""
|
||||
noteOrContent.Abstract = ""
|
||||
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
|
||||
@@ -379,8 +355,8 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// Log("_____________")
|
||||
// LogJ(noteOrContent)
|
||||
// Log("_____________")
|
||||
// LogJ(noteOrContent)
|
||||
/*
|
||||
LogJ(c.Params.Files)
|
||||
LogJ(c.Request.Header)
|
||||
@@ -399,18 +375,19 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
Log("conflict")
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
Log("没有冲突")
|
||||
|
||||
// 如果传了files
|
||||
// TODO 测试
|
||||
/*
|
||||
for key, v := range c.Params.Values {
|
||||
Log(key)
|
||||
Log(v)
|
||||
}
|
||||
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)
|
||||
// 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 {
|
||||
@@ -437,25 +414,26 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log("after upload")
|
||||
// LogJ(noteOrContent.Files)
|
||||
|
||||
// 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("ImgSrc") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
|
||||
}
|
||||
*/
|
||||
if c.Has("Title") {
|
||||
needUpdateNote = true
|
||||
@@ -465,7 +443,7 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
needUpdateNote = true
|
||||
noteUpdate["IsTrash"] = noteOrContent.IsTrash
|
||||
}
|
||||
|
||||
|
||||
// 是否是博客
|
||||
if c.Has("IsBlog") {
|
||||
needUpdateNote = true
|
||||
@@ -494,10 +472,16 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
}
|
||||
|
||||
if c.Has("Content") {
|
||||
// 通过内容得到Desc, abstract
|
||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Content, 50)
|
||||
// 通过内容得到Desc, 如果有Abstract, 则用Abstract生成Desc
|
||||
if noteOrContent.Abstract == "" {
|
||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Content, 200)
|
||||
} else {
|
||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Abstract, 200)
|
||||
}
|
||||
}
|
||||
|
||||
noteUpdate["UpdatedTime"] = noteOrContent.UpdatedTime
|
||||
|
||||
afterNoteUsn := 0
|
||||
noteOk := false
|
||||
noteMsg := ""
|
||||
@@ -521,10 +505,16 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
if noteOrContent.Abstract == "" {
|
||||
noteOrContent.Abstract = SubStringHTML(noteOrContent.Content, 200, "")
|
||||
}
|
||||
// Log("--------> afte fixed")
|
||||
// Log(noteOrContent.Content)
|
||||
|
||||
// Log("--------> afte fixed")
|
||||
// Log(noteOrContent.Content)
|
||||
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.getUserId(),
|
||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, noteOrContent.Usn)
|
||||
noteOrContent.NoteId,
|
||||
noteOrContent.Content,
|
||||
noteOrContent.Abstract,
|
||||
needUpdateNote,
|
||||
noteOrContent.Usn,
|
||||
noteOrContent.UpdatedTime)
|
||||
}
|
||||
|
||||
if needUpdateNote {
|
||||
@@ -545,8 +535,8 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
||||
noteOrContent.Usn = re.Usn
|
||||
noteOrContent.UpdatedTime = time.Now()
|
||||
|
||||
// Log("after upload")
|
||||
// LogJ(noteOrContent.Files)
|
||||
// Log("after upload")
|
||||
// LogJ(noteOrContent.Files)
|
||||
noteOrContent.UserId = c.getUserId()
|
||||
|
||||
return c.RenderJson(noteOrContent)
|
||||
@@ -570,4 +560,83 @@ func (c ApiNote) GetHistories(noteId string) revel.Result {
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
// 0.2 新增
|
||||
// 导出成PDF
|
||||
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/export_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 + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||
} else {
|
||||
cc = binPath + " --lowquality \"" + 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
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
@@ -30,17 +30,17 @@ func (c ApiNotebook) fixNotebook(notebook *info.Notebook) info.ApiNotebook {
|
||||
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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.
|
||||
// [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
|
||||
|
||||
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
@@ -53,4 +53,4 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@ 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"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
"io/ioutil"
|
||||
"io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
"os"
|
||||
"os"
|
||||
|
||||
// "path"
|
||||
// "strconv"
|
||||
@@ -31,10 +31,10 @@ func (c ApiUser) Info() revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
apiUser := info.ApiUser{
|
||||
UserId: userInfo.UserId.Hex(),
|
||||
UserId: userInfo.UserId.Hex(),
|
||||
Username: userInfo.Username,
|
||||
Email: userInfo.Email,
|
||||
Logo: userInfo.Logo,
|
||||
Email: userInfo.Email,
|
||||
Logo: userInfo.Logo,
|
||||
Verified: userInfo.Verified,
|
||||
}
|
||||
return c.RenderJson(apiUser)
|
||||
@@ -82,7 +82,6 @@ func (c ApiUser) GetSyncState() revel.Result {
|
||||
return c.RenderJson(ret)
|
||||
}
|
||||
|
||||
|
||||
// 头像设置
|
||||
// 参数file=文件
|
||||
// 成功返回{Logo: url} 头像新url
|
||||
@@ -112,7 +111,7 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
|
||||
|
||||
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
@@ -122,11 +121,11 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
|
||||
filename := handel.Filename
|
||||
|
||||
var ext string
|
||||
|
||||
|
||||
_, ext = SplitFilename(filename)
|
||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
||||
msg = "notImage"
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
filename = NewGuid() + ext
|
||||
@@ -148,8 +147,8 @@ func (c ApiUser) uploadImage() (ok bool, msg, url string) {
|
||||
LogJ(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ok = true
|
||||
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
)
|
||||
@@ -46,10 +46,10 @@ const (
|
||||
// 不需要拦截的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,
|
||||
"GetAttach": true,
|
||||
"GetAllAttachs": true,
|
||||
},
|
||||
}
|
||||
@@ -90,15 +90,15 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
if noToken && userId == "" {
|
||||
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
|
||||
// 客户端
|
||||
userId, _ = c.Session["UserId"];
|
||||
userId, _ = c.Session["UserId"]
|
||||
}
|
||||
c.Session["_userId"] = userId
|
||||
|
||||
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
if userId != "" {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/lea/blog"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
)
|
||||
@@ -48,7 +48,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Note": map[string]bool{"ToImage": true},
|
||||
"Note": map[string]bool{"ToPdf": true},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
@@ -68,7 +68,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": 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 {
|
||||
@@ -146,9 +146,10 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Album{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||
|
||||
revel.OnAppStart(func() {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
// "github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "strconv"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -20,26 +20,26 @@ type MemberBaseController struct {
|
||||
|
||||
// 得到sorterField 和 isAsc
|
||||
// okSorter = ['email', 'username']
|
||||
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
|
||||
sorter := ""
|
||||
c.Params.Bind(&sorter, "sorter")
|
||||
if sorter == "" {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
|
||||
// sorter形式 email-up, email-down
|
||||
s2 := strings.Split(sorter, "-")
|
||||
if len(s2) != 2 {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
|
||||
// 必须是可用的sorter
|
||||
if okSorter != nil && len(okSorter) > 0 {
|
||||
if !InArray(okSorter, s2[0]) {
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sorterField = strings.Title(s2[0])
|
||||
if s2[1] == "up" {
|
||||
isAsc = true
|
||||
@@ -47,7 +47,7 @@ func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter
|
||||
isAsc = false
|
||||
}
|
||||
c.RenderArgs["sorter"] = sorter
|
||||
return sorterField, isAsc;
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
func (c MemberBaseController) updateConfig(keys []string) {
|
||||
@@ -56,4 +56,4 @@ func (c MemberBaseController) updateConfig(keys []string) {
|
||||
v := c.Params.Values.Get(key)
|
||||
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
c.RenderArgs["title"] = "Posts"
|
||||
c.RenderArgs["title"] = c.Message("Posts")
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
|
||||
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
||||
@@ -85,6 +85,8 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
||||
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
|
||||
c.RenderArgs["userAndBlog"] = userAndBlog
|
||||
|
||||
c.common()
|
||||
|
||||
return c.RenderTemplate("member/blog/list.html")
|
||||
}
|
||||
|
||||
@@ -97,7 +99,8 @@ func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
|
||||
|
||||
// 修改笔记的urlTitle
|
||||
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
||||
c.RenderArgs["title"] = "Update Post Abstract"
|
||||
c.common()
|
||||
c.RenderArgs["title"] = c.Message("Update Post Abstract")
|
||||
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
|
||||
if !note.Note.IsBlog {
|
||||
return c.E404()
|
||||
@@ -107,7 +110,6 @@ func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
||||
return c.RenderTemplate("member/blog/update_abstract.html")
|
||||
}
|
||||
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
|
||||
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
|
||||
return c.RenderJson(re)
|
||||
@@ -116,24 +118,24 @@ func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string)
|
||||
// 基本信息设置
|
||||
func (c MemberBlog) Base() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Blog Base Info"
|
||||
c.RenderArgs["title"] = c.Message("Blog Base Info")
|
||||
return c.RenderTemplate("member/blog/base.html")
|
||||
}
|
||||
func (c MemberBlog) Comment() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Comment"
|
||||
c.RenderArgs["title"] = c.Message("Comment")
|
||||
return c.RenderTemplate("member/blog/comment.html")
|
||||
}
|
||||
|
||||
func (c MemberBlog) Paging() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Paging"
|
||||
c.RenderArgs["title"] = c.Message("Paging")
|
||||
return c.RenderTemplate("member/blog/paging.html")
|
||||
}
|
||||
|
||||
func (c MemberBlog) Cate() revel.Result {
|
||||
userBlog := c.common()
|
||||
c.RenderArgs["title"] = "Cate"
|
||||
c.RenderArgs["title"] = c.Message("Category")
|
||||
|
||||
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
||||
notebooksMap := map[string]info.Notebook{}
|
||||
@@ -190,10 +192,10 @@ func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.R
|
||||
}
|
||||
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Add Single"
|
||||
c.RenderArgs["title"] = c.Message("Add Single")
|
||||
c.RenderArgs["singleId"] = singleId
|
||||
if singleId != "" {
|
||||
c.RenderArgs["title"] = "Update Single"
|
||||
c.RenderArgs["title"] = c.Message("Update Single")
|
||||
c.RenderArgs["single"] = blogService.GetSingle(singleId)
|
||||
}
|
||||
return c.RenderTemplate("member/blog/add_single.html")
|
||||
@@ -219,7 +221,7 @@ func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result
|
||||
|
||||
func (c MemberBlog) Single() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Cate"
|
||||
c.RenderArgs["title"] = c.Message("Single")
|
||||
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
||||
|
||||
return c.RenderTemplate("member/blog/single.html")
|
||||
@@ -234,7 +236,7 @@ func (c MemberBlog) Theme() revel.Result {
|
||||
|
||||
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
|
||||
|
||||
c.RenderArgs["title"] = "Theme"
|
||||
c.RenderArgs["title"] = c.Message("Theme")
|
||||
return c.RenderTemplate("member/blog/theme.html")
|
||||
}
|
||||
|
||||
@@ -251,7 +253,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
||||
}
|
||||
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Upate Theme"
|
||||
c.RenderArgs["title"] = c.Message("Update Theme")
|
||||
c.RenderArgs["isNew"] = isNew
|
||||
|
||||
// 先复制之
|
||||
@@ -443,8 +445,8 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
||||
if err != nil {
|
||||
re.Msg = fmt.Sprintf("%v", err)
|
||||
return c.RenderJson(re)
|
||||
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
userId := c.GetUserId()
|
||||
@@ -460,7 +462,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
||||
var ext string
|
||||
_, ext = SplitFilename(filename)
|
||||
if ext != ".zip" {
|
||||
re.Msg = "请上传zip文件"
|
||||
re.Msg = "Please upload zip file"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -472,7 +474,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
||||
|
||||
// > 10M?
|
||||
if len(data) > 10*1024*1024 {
|
||||
re.Msg = "文件大于10M"
|
||||
re.Msg = "File is big than 10M"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// 分组管理
|
||||
@@ -14,9 +14,9 @@ type MemberGroup struct {
|
||||
func (c MemberGroup) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "My Group"
|
||||
c.RenderArgs["title"] = c.Message("My Group")
|
||||
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
|
||||
return c.RenderTemplate("member/group/index.html");
|
||||
return c.RenderTemplate("member/group/index.html")
|
||||
}
|
||||
|
||||
// 添加分组
|
||||
|
||||
@@ -13,14 +13,14 @@ type MemberIndex struct {
|
||||
// admin 主页
|
||||
func (c MemberIndex) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "Leanote Member Center"
|
||||
|
||||
c.RenderArgs["title"] = c.Message("Leanote Member Center")
|
||||
|
||||
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
||||
|
||||
|
||||
c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("member/index.html");
|
||||
|
||||
return c.RenderTemplate("member/index.html")
|
||||
}
|
||||
|
||||
// 模板
|
||||
@@ -33,5 +33,5 @@ func (c MemberIndex) T(t string) revel.Result {
|
||||
}
|
||||
|
||||
func (c MemberIndex) GetView(view string) revel.Result {
|
||||
return c.RenderTemplate("admin/" + view);
|
||||
}
|
||||
return c.RenderTemplate("admin/" + view)
|
||||
}
|
||||
|
||||
@@ -13,34 +13,28 @@ type MemberUser struct {
|
||||
func (c MemberUser) Username() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Username"
|
||||
return c.RenderTemplate("member/user/username.html");
|
||||
c.RenderArgs["title"] = c.Message("Username")
|
||||
return c.RenderTemplate("member/user/username.html")
|
||||
}
|
||||
|
||||
func (c MemberUser) Email() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Email"
|
||||
return c.RenderTemplate("member/user/email.html");
|
||||
c.RenderArgs["title"] = c.Message("Email")
|
||||
return c.RenderTemplate("member/user/email.html")
|
||||
}
|
||||
|
||||
func (c MemberUser) Password() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Password"
|
||||
return c.RenderTemplate("member/user/password.html");
|
||||
c.RenderArgs["title"] = c.Message("Password")
|
||||
return c.RenderTemplate("member/user/password.html")
|
||||
}
|
||||
|
||||
func (c MemberUser) Avatar() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Avatar"
|
||||
c.RenderArgs["title"] = c.Message("Avatar")
|
||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||
return c.RenderTemplate("member/user/avatar.html");
|
||||
return c.RenderTemplate("member/user/avatar.html")
|
||||
}
|
||||
func (c MemberUser) AddAccount() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Add Account"
|
||||
return c.RenderTemplate("member/user/add_account.html");
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
// "strings"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
var userService *service.UserService
|
||||
@@ -20,9 +20,9 @@ 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 suggestionService *service.SuggestionService
|
||||
var albumService *service.AlbumService
|
||||
var noteImageService *service.NoteImageService
|
||||
var fileService *service.FileService
|
||||
var attachService *service.AttachService
|
||||
var configService *service.ConfigService
|
||||
@@ -33,31 +33,32 @@ var themeService *service.ThemeService
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"SearchBlog": true,
|
||||
},
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
"ActiveEmail":true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"ActiveEmail": true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||
}
|
||||
|
||||
func needValidate(controller, method string) bool {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
@@ -68,33 +69,33 @@ func needValidate(controller, method string) bool {
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
// 全部变成首字大写
|
||||
/*
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// 验证是否已登录
|
||||
// 必须是管理员
|
||||
if _, ok := c.Session["Username"]; ok {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
|
||||
// 没有登录, 判断是否是ajax操作
|
||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
re := info.NewRe()
|
||||
re.Msg = "NOTLOGIN"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ func InitService() {
|
||||
tokenService = service.TokenS
|
||||
noteImageService = service.NoteImageS
|
||||
fileService = service.FileS
|
||||
albumService= service.AlbumS
|
||||
albumService = service.AlbumS
|
||||
attachService = service.AttachS
|
||||
pwdService = service.PwdS
|
||||
suggestionService = service.SuggestionS
|
||||
@@ -131,4 +132,4 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberGroup{})
|
||||
revel.OnAppStart(func() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
包括基本信息设置
|
||||
博客设置
|
||||
@@ -2,10 +2,11 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Init mgo and the common DAO
|
||||
@@ -60,12 +61,28 @@ var Sessions *mgo.Collection
|
||||
func Init(url, dbname string) {
|
||||
ok := true
|
||||
config := revel.Config
|
||||
if url == "" {
|
||||
if 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 == "" {
|
||||
dbname, _ = config.String("db.dbname")
|
||||
}
|
||||
|
||||
// get db config from host, port, username, password
|
||||
if !ok {
|
||||
host, _ := revel.Config.String("db.host")
|
||||
port, _ := revel.Config.String("db.port")
|
||||
@@ -107,7 +124,7 @@ func Init(url, dbname string) {
|
||||
|
||||
// user
|
||||
Users = Session.DB(dbname).C("users")
|
||||
// group
|
||||
// group
|
||||
Groups = Session.DB(dbname).C("groups")
|
||||
GroupUsers = Session.DB(dbname).C("group_users")
|
||||
|
||||
@@ -338,3 +355,20 @@ func Err(err error) bool {
|
||||
}
|
||||
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("重连失败!!!! 警告")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"bufio"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// convert revel msg to js msg
|
||||
|
||||
var msgBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/messages/"
|
||||
var targetBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/public/js/i18n/"
|
||||
func parse(filename string) {
|
||||
file, err := os.Open(msgBasePath + filename)
|
||||
reader := bufio.NewReader(file)
|
||||
msg := map[string]string{}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for true {
|
||||
line, _, err := reader.ReadLine()
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
// 对每一行进行处理
|
||||
if line[0] == '#' || line[1] == '#' {
|
||||
continue;
|
||||
}
|
||||
lineStr := string(line)
|
||||
|
||||
// 找到第一个=位置
|
||||
pos := strings.Index(lineStr, "=")
|
||||
|
||||
if pos < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
key := string(line[0:pos])
|
||||
value := string(line[pos+1:])
|
||||
|
||||
// fmt.Println(lineStr)
|
||||
// fmt.Println(value)
|
||||
|
||||
msg[key] = value
|
||||
}
|
||||
|
||||
// JSON
|
||||
b, _ := json.Marshal(msg)
|
||||
str := string(b)
|
||||
fmt.Println(str);
|
||||
|
||||
targetName := targetBasePath + filename + ".js"
|
||||
file2, err2 := os.OpenFile(targetName, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err2 != nil {
|
||||
file2, err2 = os.Create(targetName)
|
||||
}
|
||||
file2.WriteString("var MSG = " + 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;
|
||||
}`)
|
||||
}
|
||||
|
||||
// 生成js的i18n文件
|
||||
func main() {
|
||||
parse("msg.en")
|
||||
parse("msg.zh")
|
||||
parse("blog.zh")
|
||||
parse("blog.en")
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"time"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
//---------
|
||||
// 数据结构
|
||||
//---------
|
||||
type NoteFile struct {
|
||||
FileId string // 服务器端Id
|
||||
FileId string // 服务器端Id
|
||||
LocalFileId string // 客户端Id
|
||||
Type string // images/png, doc, xls, 根据fileName确定
|
||||
Title string
|
||||
HasBody bool // 传过来的值是否要更新内容
|
||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
||||
Type string // images/png, doc, xls, 根据fileName确定
|
||||
Title string
|
||||
HasBody bool // 传过来的值是否要更新内容
|
||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
||||
}
|
||||
type ApiNote struct {
|
||||
NoteId string
|
||||
@@ -22,32 +22,31 @@ type ApiNote struct {
|
||||
UserId string
|
||||
Title string
|
||||
Desc string
|
||||
// ImgSrc 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
|
||||
// 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
|
||||
PublicTime time.Time
|
||||
}
|
||||
|
||||
|
||||
// 内容
|
||||
type ApiNoteContent struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
|
||||
Content string `Content`
|
||||
Content string `Content`
|
||||
|
||||
// CreatedTime time.Time `CreatedTime`
|
||||
// UpdatedTime time.Time `UpdatedTime`
|
||||
// CreatedTime time.Time `CreatedTime`
|
||||
// UpdatedTime time.Time `UpdatedTime`
|
||||
}
|
||||
|
||||
// 转换
|
||||
@@ -61,11 +60,11 @@ func NoteToApiNote(note Note, files []NoteFile) ApiNote {
|
||||
//----------
|
||||
|
||||
type ApiUser struct {
|
||||
UserId string
|
||||
UserId string
|
||||
Username string
|
||||
Email string
|
||||
Email string
|
||||
Verified bool
|
||||
Logo string
|
||||
Logo string
|
||||
}
|
||||
|
||||
//----------
|
||||
@@ -81,8 +80,8 @@ type ApiNotebook struct {
|
||||
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`
|
||||
Usn int `Usn` // UpdateSequenceNum
|
||||
IsDeleted bool `IsDeleted`
|
||||
}
|
||||
|
||||
//---------
|
||||
@@ -91,7 +90,7 @@ type ApiNotebook struct {
|
||||
|
||||
// 一般返回
|
||||
type ApiRe struct {
|
||||
Ok bool
|
||||
Ok bool
|
||||
Msg string
|
||||
}
|
||||
|
||||
@@ -101,19 +100,20 @@ func NewApiRe() ApiRe {
|
||||
|
||||
// auth
|
||||
type AuthOk struct {
|
||||
Ok bool
|
||||
Token string
|
||||
UserId bson.ObjectId
|
||||
Email string
|
||||
Ok bool
|
||||
Token string
|
||||
UserId bson.ObjectId
|
||||
Email string
|
||||
Username string
|
||||
}
|
||||
|
||||
// 供notebook, note, tag更新的返回数据用
|
||||
type ReUpdate struct {
|
||||
Ok bool
|
||||
Ok bool
|
||||
Msg string
|
||||
Usn int
|
||||
}
|
||||
|
||||
func NewReUpdate() ReUpdate {
|
||||
return ReUpdate{Ok: false}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
|
||||
// Attach belongs to note
|
||||
type Attach struct {
|
||||
AttachId bson.ObjectId `bson:"_id,omitempty"` //
|
||||
NoteId bson.ObjectId `bson:"NoteId"` //
|
||||
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
|
||||
Name string `Name` // file name, md5, such as 13232312.doc
|
||||
Title string `Title` // raw file name
|
||||
Size int64 `Size` // file size (byte)
|
||||
Type string `Type` // file type, "doc" = word
|
||||
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
AttachId bson.ObjectId `bson:"_id,omitempty"` //
|
||||
NoteId bson.ObjectId `bson:"NoteId"` //
|
||||
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
|
||||
Name string `Name` // file name, md5, such as 13232312.doc
|
||||
Title string `Title` // raw file name
|
||||
Size int64 `Size` // file size (byte)
|
||||
Type string `Type` // file type, "doc" = word
|
||||
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
// FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
|
||||
}
|
||||
|
||||
@@ -7,51 +7,52 @@ import (
|
||||
// 仅仅为了博客的主题
|
||||
|
||||
type BlogInfoCustom struct {
|
||||
UserId string
|
||||
Username string
|
||||
UserLogo string
|
||||
Title string
|
||||
SubTitle string
|
||||
Logo string
|
||||
UserId string
|
||||
Username string
|
||||
UserLogo string
|
||||
Title string
|
||||
SubTitle string
|
||||
Logo string
|
||||
OpenComment bool
|
||||
CommentType string
|
||||
ThemeId string
|
||||
SubDomain string
|
||||
Domain string
|
||||
ThemeId string
|
||||
SubDomain string
|
||||
Domain string
|
||||
}
|
||||
|
||||
type Post struct {
|
||||
NoteId string
|
||||
Title string
|
||||
UrlTitle string
|
||||
ImgSrc string
|
||||
NoteId string
|
||||
Title string
|
||||
UrlTitle string
|
||||
ImgSrc string
|
||||
CreatedTime time.Time
|
||||
UpdatedTime time.Time
|
||||
PublicTime time.Time
|
||||
Desc string
|
||||
Abstract string
|
||||
Content string
|
||||
Tags []string
|
||||
CommentNum int
|
||||
ReadNum int
|
||||
LikeNum int
|
||||
IsMarkdown bool
|
||||
PublicTime time.Time
|
||||
Desc string
|
||||
Abstract string
|
||||
Content string
|
||||
Tags []string
|
||||
CommentNum int
|
||||
ReadNum int
|
||||
LikeNum int
|
||||
IsMarkdown bool
|
||||
}
|
||||
|
||||
// 归档
|
||||
type ArchiveMonth struct {
|
||||
Month int
|
||||
Posts []*Post
|
||||
}
|
||||
type Archive struct {
|
||||
Year int
|
||||
Year int
|
||||
MonthAchives []ArchiveMonth
|
||||
Posts []*Post
|
||||
Posts []*Post
|
||||
}
|
||||
|
||||
type Cate struct {
|
||||
CateId string
|
||||
CateId string
|
||||
ParentCateId string
|
||||
Title string
|
||||
UrlTitle string
|
||||
Children []*Cate
|
||||
Title string
|
||||
UrlTitle string
|
||||
Children []*Cate
|
||||
}
|
||||
|
||||
@@ -9,17 +9,17 @@ import (
|
||||
|
||||
type BlogItem struct {
|
||||
Note
|
||||
Abstract string
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
User User // 用户信息
|
||||
Abstract string
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
User User // 用户信息
|
||||
}
|
||||
|
||||
type UserBlogBase struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
// AboutMe string `AboutMe` // 关于我
|
||||
// AboutMe string `AboutMe` // 关于我
|
||||
}
|
||||
|
||||
type UserBlogComment struct {
|
||||
@@ -49,32 +49,32 @@ type UserBlog struct {
|
||||
Style string `Style` // 风格
|
||||
Css string `Css` // 自定义css
|
||||
|
||||
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
|
||||
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
|
||||
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
|
||||
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
|
||||
|
||||
CateIds []string `CateIds,omitempty` // 分类Id, 排序好的
|
||||
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
|
||||
|
||||
PerPageSize int `PerPageSize,omitempty`
|
||||
SortField string `SortField` // 排序字段
|
||||
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
|
||||
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
|
||||
|
||||
PerPageSize int `PerPageSize,omitempty`
|
||||
SortField string `SortField` // 排序字段
|
||||
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
|
||||
|
||||
SubDomain string `SubDomain` // 二级域名
|
||||
Domain string `Domain` // 自定义域名
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 博客统计信息
|
||||
type BlogStat struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||
}
|
||||
|
||||
// 单页
|
||||
type BlogSingle struct {
|
||||
SingleId bson.ObjectId `bson:"_id,omitempty"`
|
||||
SingleId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `UserId`
|
||||
Title string `Title`
|
||||
UrlTitle string `UrlTitle` // 2014/11/11
|
||||
@@ -117,12 +117,12 @@ type BlogCommentPublic struct {
|
||||
}
|
||||
|
||||
type BlogUrls struct {
|
||||
IndexUrl string
|
||||
CateUrl string
|
||||
SearchUrl string
|
||||
SingleUrl string
|
||||
PostUrl string
|
||||
ArchiveUrl string
|
||||
TagsUrl string
|
||||
IndexUrl string
|
||||
CateUrl string
|
||||
SearchUrl string
|
||||
SingleUrl string
|
||||
PostUrl string
|
||||
ArchiveUrl string
|
||||
TagsUrl string
|
||||
TagPostsUrl string
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ type Config struct {
|
||||
ConfigId bson.ObjectId `bson:"_id"`
|
||||
UserId bson.ObjectId `UserId`
|
||||
Key string `Key`
|
||||
ValueStr string `ValueStr,omitempty` // "1"
|
||||
ValueArr []string `ValueArr,omitempty` // ["1","b","c"]
|
||||
ValueMap map[string]string `ValueMap,omitempty` // {"a":"bb", "CC":"xx"}
|
||||
ValueStr string `ValueStr,omitempty` // "1"
|
||||
ValueArr []string `ValueArr,omitempty` // ["1","b","c"]
|
||||
ValueMap map[string]string `ValueMap,omitempty` // {"a":"bb", "CC":"xx"}
|
||||
ValueArrMap []map[string]string `ValueArrMap,omitempty` // [{"a":"B"}, {}, {}]
|
||||
IsArr bool `IsArr` // 是否是数组
|
||||
IsMap bool `IsMap` // 是否是Map
|
||||
|
||||
@@ -9,4 +9,4 @@ type NoteImage struct {
|
||||
NoteImageId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
NoteId bson.ObjectId `bson:"NoteId"` // 笔记
|
||||
ImageId bson.ObjectId `bson:"ImageId"` // 图片fileId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,15 @@ type Note struct {
|
||||
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
||||
|
||||
AttachNum int `AttachNum` // 2014/9/21, attachments num
|
||||
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
|
||||
|
||||
// 2015/1/15, 更新序号
|
||||
Usn int `Usn` // UpdateSequenceNum
|
||||
Usn int `Usn` // UpdateSequenceNum
|
||||
|
||||
IsDeleted bool `IsDeleted` // 删除位
|
||||
}
|
||||
@@ -80,3 +80,24 @@ type NoteContentHistory struct {
|
||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||
Histories []EachHistory `Histories`
|
||||
}
|
||||
|
||||
// 为了NoteController接收参数
|
||||
|
||||
// 更新note或content
|
||||
// 肯定会传userId(谁的), NoteId
|
||||
// 会传Title, Content, Tags, 一种或几种
|
||||
type NoteOrContent struct {
|
||||
NotebookId string
|
||||
NoteId string
|
||||
UserId string
|
||||
Title string
|
||||
Desc string
|
||||
ImgSrc string
|
||||
Tags string
|
||||
Content string
|
||||
Abstract string
|
||||
IsNew bool
|
||||
IsMarkdown bool
|
||||
FromUserId string // 为共享而新建
|
||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ type Notebook struct {
|
||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||
CreatedTime time.Time `CreatedTime,omitempty`
|
||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
||||
|
||||
|
||||
// 2015/1/15, 更新序号
|
||||
Usn int `Usn` // UpdateSequenceNum
|
||||
Usn int `Usn` // UpdateSequenceNum
|
||||
IsDeleted bool `IsDeleted`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
)
|
||||
import ()
|
||||
|
||||
// controller ajax返回
|
||||
type Re struct {
|
||||
Ok bool
|
||||
Ok bool
|
||||
Code int
|
||||
Msg string
|
||||
Id string
|
||||
Msg string
|
||||
Id string
|
||||
List interface{}
|
||||
Item interface{}
|
||||
}
|
||||
|
||||
func NewRe() Re {
|
||||
return Re{Ok: false}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ type Session struct {
|
||||
|
||||
LoginTimes int `LoginTimes` // 登录错误时间
|
||||
Captcha string `Captcha` // 验证码
|
||||
|
||||
UserId string `UserId` // API时有值UserId
|
||||
|
||||
UserId string `UserId` // API时有值UserId
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
||||
|
||||
@@ -78,7 +78,7 @@ type ShareNotebook struct {
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||
Seq int `bson:"Seq"` // 排序
|
||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||
@@ -138,7 +138,7 @@ type ShareNote struct {
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
@@ -18,28 +18,28 @@ type TagNote struct {
|
||||
|
||||
// 每个用户一条记录, 存储用户的所有tags
|
||||
type Tag struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Tags []string `Tags`
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
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` // 删除位
|
||||
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 {
|
||||
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `UserId` // 谁的
|
||||
Tag string `Tag`
|
||||
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||
Count int `Count` // 统计数量
|
||||
UserId bson.ObjectId `UserId` // 谁的
|
||||
Tag string `Tag`
|
||||
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||
Count int `Count` // 统计数量
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -14,11 +14,11 @@ type Theme struct {
|
||||
Version string `Version`
|
||||
Author string `Author`
|
||||
AuthorUrl string `AuthorUrl`
|
||||
Path string `Path` // 文件夹路径
|
||||
Path string `Path` // 文件夹路径, public/upload/54d7620d99c37b030600002c/themes/54d867c799c37b533e000001
|
||||
Info map[string]interface{} `Info` // 所有信息
|
||||
IsActive bool `IsActive` // 是否在用
|
||||
|
||||
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
|
||||
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
|
||||
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
|
||||
// 过期时间
|
||||
const (
|
||||
PwdOverHours = 2.0
|
||||
PwdOverHours = 2.0
|
||||
ActiveEmailOverHours = 48.0
|
||||
UpdateEmailOverHours = 2.0
|
||||
)
|
||||
@@ -29,4 +29,4 @@ type Token struct {
|
||||
Token string `Token`
|
||||
Type int `Type`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,13 @@ type UserAccount struct {
|
||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||
}
|
||||
|
||||
// note主页需要
|
||||
type UserAndBlogUrl struct {
|
||||
User
|
||||
BlogUrl string `BlogUrl`
|
||||
PostUrl string `PostUrl`
|
||||
}
|
||||
|
||||
// 用户与博客信息结合, 公开
|
||||
type UserAndBlog struct {
|
||||
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
|
||||
@@ -4,14 +4,13 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
|
||||
// 分页数据
|
||||
type Page struct {
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
PerPageSize int
|
||||
Count int // 总记录数
|
||||
List interface{}
|
||||
Count int // 总记录数
|
||||
List interface{}
|
||||
}
|
||||
|
||||
func NewPage(page, perPageSize, count int, list interface{}) Page {
|
||||
|
||||
343
app/init.go
343
app/init.go
@@ -1,67 +1,79 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"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/member"
|
||||
_ "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"
|
||||
"reflect"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
"github.com/leanote/leanote/app/controllers/admin"
|
||||
"github.com/leanote/leanote/app/controllers/api"
|
||||
"github.com/leanote/leanote/app/controllers/member"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
_ "github.com/leanote/leanote/app/lea/binder"
|
||||
"github.com/leanote/leanote/app/lea/i18n"
|
||||
"github.com/leanote/leanote/app/lea/route"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/revel/revel"
|
||||
"html/template"
|
||||
"math"
|
||||
"strings"
|
||||
"strconv"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Filters is the default set of global filters.
|
||||
revel.Filters = []revel.Filter{
|
||||
revel.PanicFilter, // Recover from panics and display an error page instead.
|
||||
revel.PanicFilter, // Recover from panics and display an error page instead.
|
||||
route.RouterFilter,
|
||||
// revel.RouterFilter, // Use the routing table to select the right Action
|
||||
// AuthFilter, // Invoke the action.
|
||||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
||||
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中得到
|
||||
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
||||
session.SessionFilter, // leanote session
|
||||
// session.MSessionFilter, // leanote memcache session
|
||||
|
||||
revel.FlashFilter, // Restore and write the flash cookie.
|
||||
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
|
||||
revel.I18nFilter, // Resolve the requested language
|
||||
revel.InterceptorFilter, // Run interceptors around the action.
|
||||
revel.CompressFilter, // Compress the result.
|
||||
revel.ActionInvoker, // Invoke the action.
|
||||
// session.SessionFilter, // leanote session
|
||||
// session.MSessionFilter, // leanote memcache session
|
||||
|
||||
revel.FlashFilter, // Restore and write the flash cookie.
|
||||
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
|
||||
// revel.I18nFilter, // Resolve the requested language
|
||||
i18n.I18nFilter, // Resolve the requested language by leanote
|
||||
revel.InterceptorFilter, // Run interceptors around the action.
|
||||
revel.CompressFilter, // Compress the result.
|
||||
revel.ActionInvoker, // Invoke the action.
|
||||
}
|
||||
|
||||
|
||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||
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 {
|
||||
i = i + 1;
|
||||
i = i + 1
|
||||
return fmt.Sprintf("%v", i)
|
||||
}
|
||||
revel.TemplateFuncs["sub"] = func(i int) int {
|
||||
i = i - 1;
|
||||
i = i - 1
|
||||
return i
|
||||
}
|
||||
// 增加或减少
|
||||
revel.TemplateFuncs["incr"] = func(n, i int) int {
|
||||
n = n + i;
|
||||
n = n + i
|
||||
return n
|
||||
}
|
||||
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
||||
@@ -85,11 +97,11 @@ func init() {
|
||||
return v.Get("a")
|
||||
}
|
||||
revel.TemplateFuncs["json"] = func(i interface{}) string {
|
||||
b, _ := json.Marshal(i)
|
||||
b, _ := json.Marshal(i)
|
||||
return string(b)
|
||||
}
|
||||
revel.TemplateFuncs["jsonJs"] = func(i interface{}) template.JS {
|
||||
b, _ := json.Marshal(i)
|
||||
b, _ := json.Marshal(i)
|
||||
return template.JS(string(b))
|
||||
}
|
||||
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||
@@ -103,10 +115,10 @@ func init() {
|
||||
t := time.Unix(int64(sec), 0)
|
||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
|
||||
// interface是否有该字段
|
||||
revel.TemplateFuncs["has"] = func(i interface{}, key string) bool {
|
||||
t := reflect.TypeOf(i)
|
||||
t := reflect.TypeOf(i)
|
||||
_, ok := t.FieldByName(key)
|
||||
return ok
|
||||
}
|
||||
@@ -120,9 +132,9 @@ func init() {
|
||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
|
||||
|
||||
tagPostUrl, _ := renderArgs["tagPostsUrl"].(string)
|
||||
|
||||
|
||||
for i, tag := range tags {
|
||||
str := revel.Message(locale, tag)
|
||||
var classes = "label"
|
||||
@@ -134,33 +146,78 @@ func init() {
|
||||
} else {
|
||||
classes += " label-default"
|
||||
}
|
||||
|
||||
|
||||
classes += " label-post"
|
||||
var url = tagPostUrl + "/" + url.QueryEscape(tag)
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
|
||||
if i != lenTags - 1 {
|
||||
var url = tagPostUrl + "/" + tag
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
||||
if i != lenTags-1 {
|
||||
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.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
|
||||
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return template.HTML(i18n.Message(str, message, args...))
|
||||
}
|
||||
|
||||
// 不用revel的msg
|
||||
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
|
||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
str := i18n.Message(locale, key)
|
||||
if strings.HasPrefix(str, "???") {
|
||||
str = key
|
||||
}
|
||||
return template.HTML(str)
|
||||
}
|
||||
|
||||
// lea++
|
||||
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
|
||||
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, typeStr string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
}
|
||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
|
||||
|
||||
tagPostUrl := "http://lea.leanote.com/"
|
||||
if isRecommend {
|
||||
tagPostUrl += "?tag=";
|
||||
if typeStr == "recommend" {
|
||||
tagPostUrl += "?tag="
|
||||
} else if typeStr == "latest" {
|
||||
tagPostUrl += "latest?tag="
|
||||
} else {
|
||||
tagPostUrl += "latest?tag=";
|
||||
tagPostUrl += "subscription?tag="
|
||||
}
|
||||
|
||||
|
||||
for i, tag := range tags {
|
||||
str := revel.Message(locale, tag)
|
||||
var classes = "label"
|
||||
@@ -173,67 +230,67 @@ func init() {
|
||||
classes += " label-default"
|
||||
}
|
||||
classes += " label-post"
|
||||
var url = tagPostUrl + url.QueryEscape(tag)
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
|
||||
if i != lenTags - 1 {
|
||||
var url = tagPostUrl + tag
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
||||
if i != lenTags-1 {
|
||||
tagStr += " "
|
||||
}
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
}
|
||||
// TODO 这里判断语言, 从语言包中拿
|
||||
tagMap := map[string]string{"red": "红色", "yellow": "黄色", "blue": "蓝色", "green": "绿色"}
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
for i, tag := range tags {
|
||||
if text, ok := tagMap[tag]; ok {
|
||||
tagStr += text
|
||||
} else {
|
||||
tagStr += tag
|
||||
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
}
|
||||
if i != lenTags - 1 {
|
||||
tagStr += ","
|
||||
// TODO 这里判断语言, 从语言包中拿
|
||||
tagMap := map[string]string{"red": "红色", "yellow": "黄色", "blue": "蓝色", "green": "绿色"}
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
for i, tag := range tags {
|
||||
if text, ok := tagMap[tag]; ok {
|
||||
tagStr += text
|
||||
} else {
|
||||
tagStr += tag
|
||||
}
|
||||
if i != lenTags - 1 {
|
||||
tagStr += ","
|
||||
}
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
*/
|
||||
revel.TemplateFuncs["li"] = func(a string) string {
|
||||
return ""
|
||||
}
|
||||
// str连接
|
||||
revel.TemplateFuncs["urlConcat"] = func(url string, v... interface{}) string {
|
||||
revel.TemplateFuncs["urlConcat"] = func(url string, v ...interface{}) string {
|
||||
html := ""
|
||||
for i := 0; i < len(v); i = i + 2 {
|
||||
item := v[i]
|
||||
if i+1 == len(v) {
|
||||
break;
|
||||
break
|
||||
}
|
||||
value := v[i+1]
|
||||
if item != nil && value != nil {
|
||||
keyStr, _ := item.(string)
|
||||
valueStr, err := value.(string)
|
||||
if !err {
|
||||
valueInt, _ := value.(int)
|
||||
valueStr = strconv.Itoa(valueInt)
|
||||
}
|
||||
if keyStr != "" && valueStr != "" {
|
||||
s := keyStr + "=" + valueStr
|
||||
if html != "" {
|
||||
html += "&" + s
|
||||
} else {
|
||||
html += s
|
||||
}
|
||||
}
|
||||
}
|
||||
keyStr, _ := item.(string)
|
||||
valueStr, err := value.(string)
|
||||
if !err {
|
||||
valueInt, _ := value.(int)
|
||||
valueStr = strconv.Itoa(valueInt)
|
||||
}
|
||||
if keyStr != "" && valueStr != "" {
|
||||
s := keyStr + "=" + valueStr
|
||||
if html != "" {
|
||||
html += "&" + s
|
||||
} else {
|
||||
html += s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if html != "" {
|
||||
if strings.Index(url, "?") >= 0 {
|
||||
return url + "&" + html
|
||||
@@ -243,11 +300,11 @@ func init() {
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
|
||||
revel.TemplateFuncs["urlCond"] = func(url string, sorterI, keyords interface{}) template.HTML {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// http://stackoverflow.com/questions/14226416/go-lang-templates-always-quotes-a-string-and-removes-comments
|
||||
revel.TemplateFuncs["rawMsg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.JS {
|
||||
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
@@ -256,38 +313,38 @@ func init() {
|
||||
}
|
||||
return template.JS(revel.Message(str, message, args...))
|
||||
}
|
||||
|
||||
|
||||
// 为后台管理sorter th使用
|
||||
// 必须要返回HTMLAttr, 返回html, golang 会执行安全检查返回ZgotmplZ
|
||||
// sorterI 可能是nil, 所以用interfalce{}来接收
|
||||
/*
|
||||
data-url="/adminUser/index"
|
||||
data-sorter="email"
|
||||
class="th-sortable {{if eq .sorter "email-up"}}th-sort-up{{else}}{{if eq .sorter "email-down"}}th-sort-down{{end}}{{end}}"
|
||||
data-url="/adminUser/index"
|
||||
data-sorter="email"
|
||||
class="th-sortable {{if eq .sorter "email-up"}}th-sort-up{{else}}{{if eq .sorter "email-down"}}th-sort-down{{end}}{{end}}"
|
||||
*/
|
||||
revel.TemplateFuncs["sorterTh"] = func(url, sorterField string, sorterI interface{}) template.HTMLAttr {
|
||||
sorter := ""
|
||||
if sorterI != nil {
|
||||
sorter, _ = sorterI.(string)
|
||||
}
|
||||
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"";
|
||||
html += " class=\"th-sortable ";
|
||||
if sorter == sorterField + "-up" {
|
||||
html += "th-sort-up\"";
|
||||
} else if(sorter == sorterField + "-down") {
|
||||
html += "th-sort-down";
|
||||
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\""
|
||||
html += " class=\"th-sortable "
|
||||
if sorter == sorterField+"-up" {
|
||||
html += "th-sort-up\""
|
||||
} else if sorter == sorterField+"-down" {
|
||||
html += "th-sort-down"
|
||||
}
|
||||
html += "\"";
|
||||
html += "\""
|
||||
return template.HTMLAttr(html)
|
||||
}
|
||||
|
||||
|
||||
// pagination
|
||||
revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML {
|
||||
if count == 0 {
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
totalPage := int(math.Ceil(float64(count)/float64(pageSize)))
|
||||
|
||||
totalPage := int(math.Ceil(float64(count) / float64(pageSize)))
|
||||
|
||||
preClass := ""
|
||||
prePage := page - 1
|
||||
if prePage == 0 {
|
||||
@@ -296,10 +353,10 @@ func init() {
|
||||
nextClass := ""
|
||||
nextPage := page + 1
|
||||
var preUrl, nextUrl string
|
||||
|
||||
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
|
||||
|
||||
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
|
||||
nextUrl = urlBase + "?page=" + strconv.Itoa(nextPage)
|
||||
|
||||
|
||||
// 没有上一页了
|
||||
if page == 1 {
|
||||
preClass = "disabled"
|
||||
@@ -317,49 +374,49 @@ func init() {
|
||||
// http://play.golang.org/p/snygrVpQva
|
||||
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
||||
/*
|
||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||
switch a1.(type) {
|
||||
case string:
|
||||
switch a2.(type) {
|
||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||
switch a1.(type) {
|
||||
case string:
|
||||
return reflect.ValueOf(a1).String() > reflect.ValueOf(a2).String()
|
||||
}
|
||||
case int, int8, int16, int32, int64:
|
||||
switch a2.(type) {
|
||||
switch a2.(type) {
|
||||
case string:
|
||||
return reflect.ValueOf(a1).String() > reflect.ValueOf(a2).String()
|
||||
}
|
||||
case int, int8, int16, int32, int64:
|
||||
return reflect.ValueOf(a1).Int() > reflect.ValueOf(a2).Int()
|
||||
}
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
switch a2.(type) {
|
||||
switch a2.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
return reflect.ValueOf(a1).Int() > reflect.ValueOf(a2).Int()
|
||||
}
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return reflect.ValueOf(a1).Uint() > reflect.ValueOf(a2).Uint()
|
||||
}
|
||||
case float32, float64:
|
||||
switch a2.(type) {
|
||||
switch a2.(type) {
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return reflect.ValueOf(a1).Uint() > reflect.ValueOf(a2).Uint()
|
||||
}
|
||||
case float32, float64:
|
||||
return reflect.ValueOf(a1).Float() > reflect.ValueOf(a2).Float()
|
||||
switch a2.(type) {
|
||||
case float32, float64:
|
||||
return reflect.ValueOf(a1).Float() > reflect.ValueOf(a2).Float()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
{{range $i := N 1 10}}
|
||||
<div>{{$i}}</div>
|
||||
{{end}}
|
||||
*/
|
||||
{{range $i := N 1 10}}
|
||||
<div>{{$i}}</div>
|
||||
{{end}}
|
||||
*/
|
||||
revel.TemplateFuncs["N"] = func(start, end int) (stream chan int) {
|
||||
stream = make(chan int)
|
||||
go func() {
|
||||
for i := start; i <= end; i++ {
|
||||
stream <- i
|
||||
}
|
||||
close(stream)
|
||||
}()
|
||||
return
|
||||
stream = make(chan int)
|
||||
go func() {
|
||||
for i := start; i <= end; i++ {
|
||||
stream <- i
|
||||
}
|
||||
close(stream)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// init Email
|
||||
revel.OnAppStart(func() {
|
||||
// 数据库
|
||||
@@ -367,7 +424,7 @@ func init() {
|
||||
// email配置
|
||||
InitEmail()
|
||||
InitVd()
|
||||
memcache.InitMemcache() // session服务
|
||||
// memcache.InitMemcache() // session服务
|
||||
// 其它service
|
||||
service.InitService()
|
||||
controllers.InitService()
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/revel/revel"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
func Log(i interface{}) {
|
||||
revel.INFO.Println(i)
|
||||
func Log(i ...interface{}) {
|
||||
revel.INFO.Println(i...)
|
||||
}
|
||||
|
||||
func LogW(i ...interface{}) {
|
||||
revel.WARN.Println(i...)
|
||||
}
|
||||
|
||||
func Log1(key, i interface{}) {
|
||||
revel.INFO.Println(key, i)
|
||||
}
|
||||
|
||||
func LogJ(i interface{}) {
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
revel.INFO.Println(string(b))
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
revel.INFO.Println(string(b))
|
||||
}
|
||||
|
||||
// 为test用
|
||||
func L(i interface{}) {
|
||||
fmt.Println(i)
|
||||
fmt.Println(i)
|
||||
}
|
||||
|
||||
func LJ(i interface{}) {
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
fmt.Println(string(b))
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// 发送邮件
|
||||
var host = "smtp.ym.163.com"
|
||||
var port = "25"
|
||||
@@ -12,7 +13,7 @@ var username = "noreply@leanote.com"
|
||||
var password = "---"
|
||||
|
||||
func InitEmail() {
|
||||
config := revel.Config;
|
||||
config := revel.Config
|
||||
host, _ = config.String("email.host")
|
||||
port, _ = config.String("email.port")
|
||||
username, _ = config.String("email.username")
|
||||
@@ -56,26 +57,27 @@ var bodyTpl = `
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
func SendEmailOld(to, subject, body string) bool {
|
||||
hp := strings.Split(host, ":")
|
||||
auth := smtp.PlainAuth("", username, password, hp[0])
|
||||
|
||||
|
||||
var content_type string
|
||||
|
||||
|
||||
mailtype := "html"
|
||||
if mailtype == "html" {
|
||||
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
|
||||
} else{
|
||||
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
|
||||
} else {
|
||||
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
||||
}
|
||||
|
||||
|
||||
//body = strings.Replace(bodyTpl, "$body", body, 1)
|
||||
//body = strings.Replace(body, "$title", title, 1)
|
||||
|
||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||
send_to := strings.Split(to, ";")
|
||||
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
|
||||
|
||||
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return false
|
||||
@@ -85,5 +87,5 @@ func SendEmailOld(to, subject, body string) bool {
|
||||
|
||||
func SendToLeanoteOld(subject, title, body string) {
|
||||
to := "leanote@leanote.com"
|
||||
SendEmailOld(to, subject, body);
|
||||
}
|
||||
SendEmailOld(to, subject, body)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,14 @@ func ClearDir(dir string) bool {
|
||||
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
|
||||
func ListDir(dir string) []string {
|
||||
f, err := os.Open(dir)
|
||||
@@ -108,13 +116,13 @@ func CopyDir(source string, dest string) (err error) {
|
||||
// create sub-directories - recursively
|
||||
err = CopyDir(sourcefilepointer, destinationfilepointer)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
// fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
// perform copy
|
||||
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
// fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
|
||||
transPath = path
|
||||
wand.Genesis()
|
||||
defer wand.Terminus()
|
||||
|
||||
|
||||
w := wand.NewMagickWand()
|
||||
defer w.Destroy()
|
||||
|
||||
@@ -24,7 +24,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
width := w.ImageWidth()
|
||||
height := w.ImageHeight()
|
||||
if maxWidth != 0 {
|
||||
@@ -34,14 +34,14 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
|
||||
width = maxWidth
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
w.SetImageFormat("GIF");
|
||||
|
||||
if err := paint.Thumbnail(w, width, height); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 判断是否是gif图片, 是就不用转换了
|
||||
baseName, ext := SplitFilename(path)
|
||||
var toPath string
|
||||
@@ -50,19 +50,19 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
|
||||
} else {
|
||||
toPath = TransferExt(path, ".gif");
|
||||
}
|
||||
|
||||
|
||||
if err := w.WriteImage(toPath); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if afterDelete {
|
||||
os.Remove(path)
|
||||
}
|
||||
|
||||
|
||||
ok = true
|
||||
transPath = toPath
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPat
|
||||
func Reset(path string, maxWidth uint) (ok bool, transPath string){
|
||||
wand.Genesis()
|
||||
defer wand.Terminus()
|
||||
|
||||
|
||||
w := wand.NewMagickWand()
|
||||
defer w.Destroy()
|
||||
|
||||
@@ -79,7 +79,7 @@ func Reset(path string, maxWidth uint) (ok bool, transPath string){
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
width := w.ImageWidth()
|
||||
height := w.ImageHeight()
|
||||
if maxWidth != 0 {
|
||||
@@ -93,20 +93,20 @@ func Reset(path string, maxWidth uint) (ok bool, transPath string){
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
toPath := TransferExt(path, ".gif");
|
||||
if err := w.WriteImage(toPath); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ok = true
|
||||
transPath = toPath
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPath string) {
|
||||
return ok, path
|
||||
}
|
||||
}
|
||||
|
||||
22
app/lea/Pwd.go
Normal file
22
app/lea/Pwd.go
Normal file
@@ -0,0 +1,22 @@
|
||||
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)
|
||||
}
|
||||
236
app/lea/Util.go
236
app/lea/Util.go
@@ -1,16 +1,19 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"fmt"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"io"
|
||||
math_rand "math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
math_rand "math/rand"
|
||||
)
|
||||
|
||||
// 字符串
|
||||
@@ -22,6 +25,22 @@ func Md5(s string) string {
|
||||
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
|
||||
func NewGuid() string {
|
||||
b := make([]byte, 48)
|
||||
@@ -58,7 +77,7 @@ func Substr(str string, start, length int) string {
|
||||
func substr(str string, start, length int, isRune bool) string {
|
||||
rs := []rune(str)
|
||||
rs2 := []byte(str)
|
||||
|
||||
|
||||
rl := len(rs)
|
||||
if !isRune {
|
||||
rl = len(rs2)
|
||||
@@ -123,73 +142,48 @@ func ReplaceAll(oldStr, pattern, newStr string) string {
|
||||
}
|
||||
|
||||
// 获取纯文本
|
||||
func SubStringHTMLToRaw(param string, length int) (result string) {
|
||||
func SubStringHTMLToRaw(param string, length int) string {
|
||||
if param == "" {
|
||||
return ""
|
||||
return param
|
||||
}
|
||||
result = ""
|
||||
n := 0
|
||||
var temp rune // 中文问题, 用rune来解决
|
||||
rStr := []rune(param)
|
||||
lenStr := len(rStr)
|
||||
isCode := false
|
||||
for i := 0; i < len(rStr); i++ {
|
||||
|
||||
resultRune := make([]rune, length)
|
||||
// s := ""
|
||||
for i := 0; i < lenStr; i++ {
|
||||
temp = rStr[i]
|
||||
if temp == '<' {
|
||||
isCode = true
|
||||
continue
|
||||
} else if temp == '>' {
|
||||
isCode = false
|
||||
result += " "; // 空格
|
||||
resultRune[n] = ' '
|
||||
|
||||
n++
|
||||
if n >= length {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !isCode {
|
||||
result += string(temp)
|
||||
resultRune[n] = temp
|
||||
// s += string(temp)
|
||||
n++
|
||||
if n >= length {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
result := string(resultRune[0:n])
|
||||
return strings.Trim(result, " ")
|
||||
}
|
||||
|
||||
// 获取摘要, HTML
|
||||
func SubStringHTML(param string, length int, end string) string {
|
||||
if param == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 先取出<pre></pre>占位..
|
||||
result := ""
|
||||
|
||||
// 1
|
||||
n := 0
|
||||
var temp rune // 中文问题, 用rune来解决
|
||||
isCode := false //是不是HTML代码
|
||||
isHTML := false //是不是HTML特殊字符,如
|
||||
rStr := []rune(param)
|
||||
for i := 0; i < len(rStr); 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
|
||||
}
|
||||
result += string(temp)
|
||||
if n >= length {
|
||||
break
|
||||
}
|
||||
}
|
||||
result += end
|
||||
|
||||
// 自带方法补全html
|
||||
func fixHtml(result string) string {
|
||||
// 取出所有标签
|
||||
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
|
||||
|
||||
@@ -198,13 +192,13 @@ func SubStringHTML(param string, length int, end string) string {
|
||||
|
||||
// 把<div class=xxx的class=xxx去掉
|
||||
tempResult = ReplaceAll(tempResult, "<(/?[a-zA-Z]+)[^<>]*>", "<$1>")
|
||||
|
||||
|
||||
// 3 只能用正则,+stack来去有结束的
|
||||
// golang的正则暂不支持back reference, 以后可以用它来去掉重复的标签
|
||||
p, _ := regexp.Compile("<(/?[a-zA-Z]+)[^<>]*>") // 得到所有的<div>, </div>...
|
||||
strs := p.FindAllString(tempResult, -1)
|
||||
|
||||
// fmt.Println(strs)
|
||||
// fmt.Println(strs)
|
||||
stack := make([]string, len(strs))
|
||||
stackP := -1
|
||||
for _, each := range strs {
|
||||
@@ -221,17 +215,82 @@ func SubStringHTML(param string, length int, end string) string {
|
||||
// 补全tag
|
||||
if stackP != -1 {
|
||||
fmt.Println(stack[0 : stackP+1])
|
||||
|
||||
|
||||
for _, each := range stack[0 : stackP+1] {
|
||||
if each[1] != '/' {
|
||||
result += "</" + each[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if pwd == "" {
|
||||
@@ -246,16 +305,16 @@ func IsGoodPwd(pwd string) (bool, string) {
|
||||
// 是否是email
|
||||
func IsEmail(email string) bool {
|
||||
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,3}$`, email)
|
||||
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)
|
||||
return ok
|
||||
}
|
||||
|
||||
// 是否只包含数字, 字母 -, _
|
||||
func IsUsername(username string) bool {
|
||||
if username == "" {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username)
|
||||
return !ok
|
||||
@@ -292,15 +351,15 @@ func RandomPwd(num int) string {
|
||||
chars[j] = byte(i)
|
||||
j++
|
||||
}
|
||||
j--;
|
||||
|
||||
j--
|
||||
|
||||
str := ""
|
||||
math_rand.Seed(time.Now().UnixNano())
|
||||
for i := 0; i < num; i++ {
|
||||
x := math_rand.Intn(j)
|
||||
str += string(chars[x])
|
||||
}
|
||||
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -314,4 +373,61 @@ func InArray(arr []string, str string) bool {
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 是否是合法的时间
|
||||
// 不是, 0001-01-01T00:00:00Z, 且比今天小
|
||||
func IsValidTime(t time.Time) bool {
|
||||
if t.Year() > 20 {
|
||||
now := time.Now()
|
||||
Log("------")
|
||||
Log(t)
|
||||
Log(now)
|
||||
if t.Before(now) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// url传过来的时间没有时区信息, 转到本地时间
|
||||
func ToLocalTime(t time.Time) time.Time {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, time.Local)
|
||||
}
|
||||
|
||||
// 修复传过来的时间, 如果比今天大, 则设为现在
|
||||
func FixUrlTime(t time.Time) time.Time {
|
||||
localTime := ToLocalTime(t)
|
||||
if IsValidTime(localTime) {
|
||||
return localTime
|
||||
}
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// 得到用户的随机文件路径 3位/userId/2位
|
||||
func GetRandomFilePath(userId, uuid string) string {
|
||||
if uuid == "" {
|
||||
uuid = NewGuid()
|
||||
}
|
||||
return Digest3(userId) + "/" + userId + "/" + Digest2(uuid)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package lea
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 验证
|
||||
@@ -38,15 +38,15 @@ var rulesStr = `{
|
||||
`
|
||||
var rulesMap map[string][]map[string]string
|
||||
|
||||
var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
"required": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
var rules = map[string]func(string, map[string]string) (bool, string){
|
||||
"required": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
return
|
||||
},
|
||||
"minLength": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
"minLength": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
@@ -55,7 +55,7 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
ok = len(value) >= dataI
|
||||
return
|
||||
},
|
||||
"min": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
"min": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
@@ -65,8 +65,8 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
ok = vI >= dataI
|
||||
return
|
||||
},
|
||||
|
||||
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
|
||||
"sortField": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
@@ -74,22 +74,22 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
ok = InArray(sortFields, value)
|
||||
return
|
||||
},
|
||||
|
||||
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
|
||||
"password": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
ok = len(value) >= 6
|
||||
return
|
||||
},
|
||||
"email": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
"email": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
ok = IsEmail(value)
|
||||
return
|
||||
},
|
||||
"noSpecialChars": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
"noSpecialChars": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
@@ -97,8 +97,8 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
return
|
||||
},
|
||||
// www.baidu.com
|
||||
//
|
||||
"domain": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
//
|
||||
"domain": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
ok = true
|
||||
return // 可为空
|
||||
@@ -106,16 +106,16 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
ok2, _ := regexp.MatchString(`[^0-9a-zA-Z_\.\-]`, value)
|
||||
ok = !ok2
|
||||
if !ok {
|
||||
return
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
},
|
||||
// abcd
|
||||
"subDomain": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
"subDomain": func(value string, rule map[string]string) (ok bool, msg string) {
|
||||
if value == "" {
|
||||
ok = true
|
||||
return // 可为空
|
||||
return // 可为空
|
||||
}
|
||||
if len(value) < 4 {
|
||||
ok = false
|
||||
@@ -137,7 +137,7 @@ func InitVd() {
|
||||
|
||||
func Vd(name, value string) (ok bool, msg string) {
|
||||
rs, _ := rulesMap[name]
|
||||
|
||||
|
||||
for _, rule := range rs {
|
||||
ruleFunc, _ := rules[rule["rule"]]
|
||||
if ok2, msg2 := ruleFunc(value, rule); !ok2 {
|
||||
@@ -151,11 +151,11 @@ func Vd(name, value string) (ok bool, msg string) {
|
||||
if msgData != "" {
|
||||
msg += "-" + msgData
|
||||
}
|
||||
return
|
||||
return
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
func Vds(m map[string]string) (ok bool, msg string) {
|
||||
@@ -166,5 +166,5 @@ func Vds(m map[string]string) (ok bool, msg string) {
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// main functions shows how to TarGz a directory/file and
|
||||
@@ -16,66 +16,66 @@ import (
|
||||
|
||||
func main() {
|
||||
/*
|
||||
os.Mkdir("/home/ty4z2008/tar", 0777)
|
||||
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
|
||||
//targetfile,sourcefile
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
fmt.Println(w)
|
||||
os.Mkdir("/home/ty4z2008/tar", 0777)
|
||||
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
|
||||
//targetfile,sourcefile
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
fmt.Println(w)
|
||||
|
||||
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
|
||||
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
|
||||
os.RemoveAll("/home/ty4z2008/tar")
|
||||
*/
|
||||
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
|
||||
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
|
||||
fmt.Println("ok")
|
||||
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
|
||||
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
|
||||
os.RemoveAll("/home/ty4z2008/tar")
|
||||
*/
|
||||
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
|
||||
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
func TarGz(srcDirPath string, destFilePath string) (ok bool) {
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
}
|
||||
|
||||
|
||||
}()
|
||||
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
// Gzip writer
|
||||
gw := gzip.NewWriter(fw)
|
||||
defer gw.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
// Tar writer
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
// Gzip writer
|
||||
gw := gzip.NewWriter(fw)
|
||||
defer gw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
tarGzFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
// Tar writer
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
tarGzFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with directories
|
||||
@@ -83,148 +83,148 @@ func TarGz(srcDirPath string, destFilePath string) (ok bool) {
|
||||
// Every recurrence append the base path to the recPath
|
||||
// recPath is the path inside of tar.gz
|
||||
func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
|
||||
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with files
|
||||
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
// if last character of header name is '/' it also can be directory
|
||||
// but if you don't set Typeflag, error will occur when you untargz
|
||||
hdr.Name = recPath // + "/"
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Typeflag = tar.TypeDir
|
||||
// hdr.Size = 0
|
||||
//hdr.Mode = 0755 | c_ISDIR
|
||||
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
|
||||
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
// if last character of header name is '/' it also can be directory
|
||||
// but if you don't set Typeflag, error will occur when you untargz
|
||||
hdr.Name = recPath // + "/"
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Typeflag = tar.TypeDir
|
||||
// hdr.Size = 0
|
||||
//hdr.Mode = 0755 | c_ISDIR
|
||||
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
|
||||
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
|
||||
|
||||
// Write hander
|
||||
err := tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
// Write hander
|
||||
err := tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
hdr.Name = recPath
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Size = fi.Size()
|
||||
hdr.Mode = int64(fi.Mode())
|
||||
hdr.ModTime = fi.ModTime()
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
hdr.Name = recPath
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Size = fi.Size()
|
||||
hdr.Mode = int64(fi.Mode())
|
||||
hdr.ModTime = fi.ModTime()
|
||||
|
||||
// Write hander
|
||||
err = tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Write hander
|
||||
err = tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write file data
|
||||
_, err = io.Copy(tw, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
// Write file data
|
||||
_, err = io.Copy(tw, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ungzip and untar from source file to destination directory
|
||||
// you need check file exist before you call this function
|
||||
func UnTarGz(srcFilePath string, destDirPath string) {
|
||||
// fmt.Println("UnTarGzing " + srcFilePath + "...")
|
||||
// Create destination directory
|
||||
os.Mkdir(destDirPath, os.ModePerm)
|
||||
// fmt.Println("UnTarGzing " + srcFilePath + "...")
|
||||
// Create destination directory
|
||||
os.Mkdir(destDirPath, os.ModePerm)
|
||||
|
||||
fr, err := os.Open(srcFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
fr, err := os.Open(srcFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Gzip reader
|
||||
gr, err := gzip.NewReader(fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gr.Close()
|
||||
// Gzip reader
|
||||
gr, err := gzip.NewReader(fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gr.Close()
|
||||
|
||||
// Tar reader
|
||||
tr := tar.NewReader(gr)
|
||||
// Tar reader
|
||||
tr := tar.NewReader(gr)
|
||||
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
// End of tar archive
|
||||
break
|
||||
}
|
||||
//handleError(err)
|
||||
// fmt.Println("UnTarGzing file..." + hdr.Name)
|
||||
// Check if it is diretory or file
|
||||
if hdr.Typeflag != tar.TypeDir {
|
||||
// Get files from archive
|
||||
// Create diretory before create file
|
||||
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
|
||||
// Write data to file
|
||||
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, tr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fmt.Println("Well done!")
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
// End of tar archive
|
||||
break
|
||||
}
|
||||
//handleError(err)
|
||||
// fmt.Println("UnTarGzing file..." + hdr.Name)
|
||||
// Check if it is diretory or file
|
||||
if hdr.Typeflag != tar.TypeDir {
|
||||
// Get files from archive
|
||||
// Create diretory before create file
|
||||
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
|
||||
// Write data to file
|
||||
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, tr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fmt.Println("Well done!")
|
||||
}
|
||||
|
||||
// Copyfile
|
||||
func CopyFile(dstName, srcName string) (written int64, err error) {
|
||||
src, err := os.Open(srcName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
src, err := os.Open(srcName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"github.com/leanote/leanote/app/lea"
|
||||
)
|
||||
|
||||
// main functions shows how to TarGz a directory/file and
|
||||
@@ -15,43 +16,43 @@ import (
|
||||
// you need check file exist before you call this function
|
||||
|
||||
func Zip(srcDirPath string, destFilePath string) (ok bool) {
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
// Tar writer
|
||||
tw := zip.NewWriter(fw)
|
||||
defer tw.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
zipDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
zipFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
// Tar writer
|
||||
tw := zip.NewWriter(fw)
|
||||
defer tw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
zipDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
zipFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with directories
|
||||
@@ -59,69 +60,69 @@ func Zip(srcDirPath string, destFilePath string) (ok bool) {
|
||||
// Every recurrence append the base path to the recPath
|
||||
// recPath is the path inside of tar.gz
|
||||
func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
zipDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
zipDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
|
||||
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with files
|
||||
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
/*
|
||||
fh, err := zip.FileInfoHeader(fi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fh.Name = recPath // + "/"
|
||||
err = tw.WriteHeader(hdr)
|
||||
tw.Create(recPath)
|
||||
*/
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
/*
|
||||
fh, err := zip.FileInfoHeader(fi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fh.Name = recPath // + "/"
|
||||
err = tw.WriteHeader(hdr)
|
||||
tw.Create(recPath)
|
||||
*/
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Write hander
|
||||
w, err2 := tw.Create(recPath)
|
||||
if err2 != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Write file data
|
||||
_, err = io.Copy(w, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
// Write hander
|
||||
w, err2 := tw.Create(recPath)
|
||||
if err2 != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Write file data
|
||||
_, err = io.Copy(w, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ungzip and untar from source file to destination directory
|
||||
@@ -129,33 +130,39 @@ func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
|
||||
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
|
||||
ok = false
|
||||
msg = ""
|
||||
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
os.Mkdir(destDirPath, os.ModePerm)
|
||||
r, err := zip.OpenReader(srcFilePath);
|
||||
r, err := zip.OpenReader(srcFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close();
|
||||
defer r.Close()
|
||||
for _, f := range r.File {
|
||||
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
|
||||
rc, err := f.Open();
|
||||
if err!=nil {
|
||||
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
||||
// 包含恶意目录
|
||||
if strings.Contains(f.Name, "../") {
|
||||
lea.LogW("恶意文件", f.Name);
|
||||
continue
|
||||
}
|
||||
|
||||
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
|
||||
paths := strings.Split(f.Name, "/")
|
||||
prePath := ""
|
||||
filename := ""
|
||||
l := len(paths)
|
||||
// fmt.Println(l)
|
||||
// fmt.Println(l)
|
||||
if l > 1 {
|
||||
// 去掉第1个文件夹
|
||||
if l == 2 {
|
||||
@@ -167,26 +174,26 @@ func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
|
||||
} else {
|
||||
filename = f.Name
|
||||
}
|
||||
// fmt.Println(prePath)
|
||||
|
||||
// fmt.Println(prePath)
|
||||
|
||||
// 相对于目标文件件下的路径
|
||||
destPath := destDirPath + "/" + filename
|
||||
destPath := destDirPath + "/" + filename
|
||||
if prePath != "" {
|
||||
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
|
||||
os.MkdirAll(destDirPath+"/"+prePath, os.ModePerm)
|
||||
destPath = destDirPath + "/" + prePath + "/" + filename
|
||||
}
|
||||
// Write data to file
|
||||
// fmt.Println(destPath)
|
||||
fw, _ := os.Create(destPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Write data to file
|
||||
// fmt.Println(destPath)
|
||||
fw, _ := os.Create(destPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package binder
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
// "github.com/leanote/leanote/app/controllers/api"
|
||||
"github.com/revel/revel"
|
||||
// "github.com/leanote/leanote/app/controllers/api"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -12,7 +11,7 @@ import (
|
||||
|
||||
// leanote binder struct
|
||||
// rewrite revel struct binder
|
||||
// not need the struct name as prefix,
|
||||
// not need the struct name as prefix,
|
||||
// eg:
|
||||
// type Note struct {Name}
|
||||
// func (c Controller) List(note Note) revel.Result {}
|
||||
@@ -34,13 +33,13 @@ var MSSBinder = revel.Binder{
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
|
||||
Unbind: func(output map[string]string, name string, val interface{}) {
|
||||
mapValue := reflect.ValueOf(val)
|
||||
for _, key := range mapValue.MapKeys() {
|
||||
revel.Unbind(output, fmt.Sprintf("%v", key.Interface()),
|
||||
mapValue.MapIndex(key).Interface())
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -54,55 +53,56 @@ func nextKey(key string) string {
|
||||
}
|
||||
return key[:fieldLen]
|
||||
}
|
||||
|
||||
var leanoteStructBinder = revel.Binder{
|
||||
// name == "noteOrContent"
|
||||
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
||||
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取
|
||||
fieldValues := make(map[string]reflect.Value)
|
||||
// fmt.Println(name)
|
||||
// fmt.Println(name)
|
||||
// fmt.Println(typ) // api.NoteFiles
|
||||
// name = files[0], files[1], noteContent
|
||||
// fmt.Println(params.Values)
|
||||
// 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]]
|
||||
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
|
||||
// fmt.Println(params.Values["files[1]"])
|
||||
// fmt.Println(params.Values["Title"])
|
||||
for key, _ := range params.Values { // Title, Content, Files
|
||||
// 这里, 如果没有点, 默认就是a.
|
||||
// life
|
||||
// fmt.Println("key:" + key); // files[0][LocalFileId]
|
||||
// fmt.Println("name:" + name); // files[0][LocalFileId]
|
||||
// fmt.Println("key:" + key); // files[0][LocalFileId]
|
||||
// fmt.Println("name:" + name); // files[0][LocalFileId]
|
||||
var suffix string
|
||||
var noPrefix = false
|
||||
if nameIsSlice && strings.HasPrefix(key, name) {
|
||||
suffix = key[len(name)+1:len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
|
||||
} else 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
|
||||
suffix = key
|
||||
// continue
|
||||
// continue
|
||||
} else {
|
||||
// Get the name of the struct property.
|
||||
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
||||
suffix = key[len(name)+1:]
|
||||
}
|
||||
// fmt.Println(suffix);
|
||||
|
||||
// fmt.Println(suffix);
|
||||
|
||||
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
||||
// fmt.Println(fieldName);
|
||||
// fmt.Println(fieldName);
|
||||
fieldLen := len(fieldName)
|
||||
|
||||
|
||||
if _, ok := fieldValues[fieldName]; !ok {
|
||||
// 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)
|
||||
// fmt.Println("xx: " + fieldName)
|
||||
fieldValue := result.FieldByName(fieldName)
|
||||
// fmt.Println(fieldValue)
|
||||
// fmt.Println(fieldValue)
|
||||
if !fieldValue.IsValid() {
|
||||
continue
|
||||
}
|
||||
@@ -111,14 +111,14 @@ files[0][HasBody]:[true]]
|
||||
}
|
||||
var boundVal reflect.Value
|
||||
// 没有name前缀
|
||||
if(noPrefix) {
|
||||
if noPrefix {
|
||||
// life
|
||||
// fmt.Println("<<")
|
||||
// fmt.Println(strings.Title(key[:fieldLen]));
|
||||
// fmt.Println("<<")
|
||||
// fmt.Println(strings.Title(key[:fieldLen]));
|
||||
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
||||
} else {
|
||||
// fmt.Println("final")
|
||||
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
|
||||
// fmt.Println("final")
|
||||
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
|
||||
if nameIsSlice {
|
||||
fieldLen += 1
|
||||
}
|
||||
@@ -150,7 +150,7 @@ func init() {
|
||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = 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(info.NoteOrContent{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
// "os"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@@ -40,8 +40,8 @@ type RenderTemplateResult struct {
|
||||
Template *template.Template
|
||||
PathContent map[string]string
|
||||
RenderArgs map[string]interface{}
|
||||
|
||||
IsPreview bool // 是否是预览
|
||||
|
||||
IsPreview bool // 是否是预览
|
||||
CurBlogTpl *BlogTpl
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response,
|
||||
Line: line,
|
||||
SourceLines: templateContent,
|
||||
}
|
||||
|
||||
|
||||
// 这里, 错误!!
|
||||
// 这里应该导向到本主题的错误页面
|
||||
resp.Status = 500
|
||||
@@ -117,7 +117,7 @@ func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||
r.render(req, resp, out) // 这里!!!
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Render the template into a temporary buffer, to see if there was an error
|
||||
// rendering the template. If not, then copy it into the response buffer.
|
||||
// Otherwise, template render errors may result in unpredictable HTML (and
|
||||
@@ -139,7 +139,7 @@ func Init() {
|
||||
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
|
||||
fileStr := string(fileBytes)
|
||||
path := "blog/" + path
|
||||
// path := path
|
||||
// path := path
|
||||
BlogTplObject.PathContent[path] = fileStr
|
||||
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
||||
// 都不会为空的
|
||||
if basePath == "" {
|
||||
path := "blog/" + name
|
||||
// path := name
|
||||
// path := name
|
||||
t := BlogTplObject.Template.Lookup(path)
|
||||
r = &RenderTemplateResult{
|
||||
Template: t,
|
||||
@@ -181,7 +181,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
||||
files := ListDir(basePath)
|
||||
for _, t := range files {
|
||||
if !strings.Contains(t, ".html") {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
|
||||
if err != nil {
|
||||
@@ -194,7 +194,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
||||
|
||||
// 如果本主题下没有, 则用系统的
|
||||
t := newBlogTplObject.Template.Lookup(name)
|
||||
|
||||
|
||||
if t == nil {
|
||||
path := "blog/" + name
|
||||
t = BlogTplObject.Template.Lookup(path)
|
||||
@@ -203,23 +203,21 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
||||
Template: t,
|
||||
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
||||
RenderArgs: args,
|
||||
CurBlogTpl: newBlogTplObject,
|
||||
IsPreview: isPreview,
|
||||
CurBlogTpl: newBlogTplObject,
|
||||
IsPreview: isPreview,
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
//
|
||||
|
||||
|
||||
type ErrorResult struct {
|
||||
RenderArgs map[string]interface{}
|
||||
Error error
|
||||
IsPreview bool
|
||||
IsPreview bool
|
||||
CurBlogTpl *BlogTpl
|
||||
}
|
||||
|
||||
@@ -240,7 +238,7 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||
var err error
|
||||
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
|
||||
err = nil
|
||||
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
|
||||
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
|
||||
|
||||
// This func shows a plaintext error message, in case the template rendering
|
||||
// doesn't work.
|
||||
@@ -297,4 +295,4 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||
b.WriteTo(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,399 +1,401 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"math/rand"
|
||||
crand "crypto/rand"
|
||||
"time"
|
||||
"strconv"
|
||||
)
|
||||
const (
|
||||
stdWidth = 100
|
||||
stdHeight = 40
|
||||
maxSkew = 2
|
||||
crand "crypto/rand"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
fontWidth = 5
|
||||
fontHeight = 8
|
||||
blackChar = 1
|
||||
stdWidth = 100
|
||||
stdHeight = 40
|
||||
maxSkew = 2
|
||||
)
|
||||
|
||||
|
||||
const (
|
||||
fontWidth = 5
|
||||
fontHeight = 8
|
||||
blackChar = 1
|
||||
)
|
||||
|
||||
var font = [][]byte{
|
||||
{ // 0
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 1
|
||||
0, 0, 1, 0, 0,
|
||||
0, 1, 1, 0, 0,
|
||||
1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
},
|
||||
{ // 2
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 1,
|
||||
0, 1, 1, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
},
|
||||
{ // 3
|
||||
1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 4
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
},
|
||||
{ // 5
|
||||
1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 6
|
||||
0, 0, 1, 1, 1,
|
||||
0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 7
|
||||
1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
},
|
||||
{ // 8
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 9
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 0
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 1
|
||||
0, 0, 1, 0, 0,
|
||||
0, 1, 1, 0, 0,
|
||||
1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
},
|
||||
{ // 2
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 1,
|
||||
0, 1, 1, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
},
|
||||
{ // 3
|
||||
1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 4
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 0, 1, 0,
|
||||
},
|
||||
{ // 5
|
||||
1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 6
|
||||
0, 0, 1, 1, 1,
|
||||
0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 7
|
||||
1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0,
|
||||
},
|
||||
{ // 8
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0,
|
||||
},
|
||||
{ // 9
|
||||
0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
type Image struct {
|
||||
*image.NRGBA
|
||||
color *color.NRGBA
|
||||
width int //a digit width
|
||||
height int //a digit height
|
||||
dotsize int
|
||||
*image.NRGBA
|
||||
color *color.NRGBA
|
||||
width int //a digit width
|
||||
height int //a digit height
|
||||
dotsize int
|
||||
}
|
||||
func init(){
|
||||
rand.Seed(int64(time.Second))
|
||||
|
||||
func init() {
|
||||
rand.Seed(int64(time.Second))
|
||||
}
|
||||
|
||||
|
||||
func NewImage(digits []byte, width, height int) *Image {
|
||||
img := new(Image)
|
||||
r := image.Rect(img.width, img.height, stdWidth, stdHeight)
|
||||
img.NRGBA = image.NewNRGBA(r)
|
||||
|
||||
img.color = &color.NRGBA{
|
||||
uint8(rand.Intn(129)),
|
||||
uint8(rand.Intn(129)),
|
||||
uint8(rand.Intn(129)),
|
||||
0xFF,
|
||||
}
|
||||
// Draw background (10 random circles of random brightness)
|
||||
img.calculateSizes(width, height, len(digits))
|
||||
img.fillWithCircles(10, img.dotsize)
|
||||
|
||||
maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
|
||||
maxy := height - img.height - img.dotsize*2
|
||||
|
||||
x := rnd(img.dotsize*2, maxx)
|
||||
y := rnd(img.dotsize*2, maxy)
|
||||
|
||||
// Draw digits.
|
||||
for _, n := range digits {
|
||||
img.drawDigit(font[n], x, y)
|
||||
x += img.width + img.dotsize
|
||||
}
|
||||
|
||||
// Draw strike-through line.
|
||||
// 中间线不要
|
||||
//img.strikeThrough()
|
||||
|
||||
return img
|
||||
img := new(Image)
|
||||
r := image.Rect(img.width, img.height, stdWidth, stdHeight)
|
||||
img.NRGBA = image.NewNRGBA(r)
|
||||
|
||||
img.color = &color.NRGBA{
|
||||
uint8(rand.Intn(129)),
|
||||
uint8(rand.Intn(129)),
|
||||
uint8(rand.Intn(129)),
|
||||
0xFF,
|
||||
}
|
||||
// Draw background (10 random circles of random brightness)
|
||||
img.calculateSizes(width, height, len(digits))
|
||||
img.fillWithCircles(10, img.dotsize)
|
||||
|
||||
maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
|
||||
maxy := height - img.height - img.dotsize*2
|
||||
|
||||
x := rnd(img.dotsize*2, maxx)
|
||||
y := rnd(img.dotsize*2, maxy)
|
||||
|
||||
// Draw digits.
|
||||
for _, n := range digits {
|
||||
img.drawDigit(font[n], x, y)
|
||||
x += img.width + img.dotsize
|
||||
}
|
||||
|
||||
// Draw strike-through line.
|
||||
// 中间线不要
|
||||
//img.strikeThrough()
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) WriteTo(w io.Writer) (int64, error) {
|
||||
return 0, png.Encode(w, img)
|
||||
return 0, png.Encode(w, img)
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) calculateSizes(width, height, ncount int) {
|
||||
|
||||
// Goal: fit all digits inside the image.
|
||||
var border int
|
||||
if width > height {
|
||||
border = height / 5
|
||||
} else {
|
||||
border = width / 5
|
||||
}
|
||||
// Convert everything to floats for calculations.
|
||||
w := float64(width - border*2) //268
|
||||
h := float64(height - border*2) //48
|
||||
// fw takes into account 1-dot spacing between digits.
|
||||
|
||||
fw := float64(fontWidth) + 1 //6
|
||||
|
||||
fh := float64(fontHeight) //8
|
||||
nc := float64(ncount) //7
|
||||
|
||||
// Calculate the width of a single digit taking into account only the
|
||||
// width of the image.
|
||||
nw := w / nc //38
|
||||
// Calculate the height of a digit from this width.
|
||||
nh := nw * fh / fw //51
|
||||
|
||||
// Digit too high?
|
||||
|
||||
if nh > h {
|
||||
// Fit digits based on height.
|
||||
nh = h //nh = 44
|
||||
nw = fw / fh * nh
|
||||
}
|
||||
// Calculate dot size.
|
||||
img.dotsize = int(nh / fh)
|
||||
// Save everything, making the actual width smaller by 1 dot to account
|
||||
// for spacing between digits.
|
||||
img.width = int(nw)
|
||||
img.height = int(nh) - img.dotsize
|
||||
|
||||
// Goal: fit all digits inside the image.
|
||||
var border int
|
||||
if width > height {
|
||||
border = height / 5
|
||||
} else {
|
||||
border = width / 5
|
||||
}
|
||||
// Convert everything to floats for calculations.
|
||||
w := float64(width - border*2) //268
|
||||
h := float64(height - border*2) //48
|
||||
// fw takes into account 1-dot spacing between digits.
|
||||
|
||||
fw := float64(fontWidth) + 1 //6
|
||||
|
||||
fh := float64(fontHeight) //8
|
||||
nc := float64(ncount) //7
|
||||
|
||||
// Calculate the width of a single digit taking into account only the
|
||||
// width of the image.
|
||||
nw := w / nc //38
|
||||
// Calculate the height of a digit from this width.
|
||||
nh := nw * fh / fw //51
|
||||
|
||||
// Digit too high?
|
||||
|
||||
if nh > h {
|
||||
// Fit digits based on height.
|
||||
nh = h //nh = 44
|
||||
nw = fw / fh * nh
|
||||
}
|
||||
// Calculate dot size.
|
||||
img.dotsize = int(nh / fh)
|
||||
// Save everything, making the actual width smaller by 1 dot to account
|
||||
// for spacing between digits.
|
||||
img.width = int(nw)
|
||||
img.height = int(nh) - img.dotsize
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) fillWithCircles(n, maxradius int) {
|
||||
color := img.color
|
||||
maxx := img.Bounds().Max.X
|
||||
maxy := img.Bounds().Max.Y
|
||||
for i := 0; i < n; i++ {
|
||||
setRandomBrightness(color, 255)
|
||||
r := rnd(1, maxradius)
|
||||
img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
|
||||
}
|
||||
color := img.color
|
||||
maxx := img.Bounds().Max.X
|
||||
maxy := img.Bounds().Max.Y
|
||||
for i := 0; i < n; i++ {
|
||||
setRandomBrightness(color, 255)
|
||||
r := rnd(1, maxradius)
|
||||
img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
|
||||
for x := fromX; x <= toX; x++ {
|
||||
img.Set(x, y, color)
|
||||
}
|
||||
for x := fromX; x <= toX; x++ {
|
||||
img.Set(x, y, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) drawCircle(color color.Color, x, y, radius int) {
|
||||
f := 1 - radius
|
||||
dfx := 1
|
||||
dfy := -2 * radius
|
||||
xx := 0
|
||||
yy := radius
|
||||
|
||||
img.Set(x, y+radius, color)
|
||||
img.Set(x, y-radius, color)
|
||||
img.drawHorizLine(color, x-radius, x+radius, y)
|
||||
|
||||
for xx < yy {
|
||||
if f >= 0 {
|
||||
yy--
|
||||
dfy += 2
|
||||
f += dfy
|
||||
}
|
||||
xx++
|
||||
dfx += 2
|
||||
f += dfx
|
||||
img.drawHorizLine(color, x-xx, x+xx, y+yy)
|
||||
img.drawHorizLine(color, x-xx, x+xx, y-yy)
|
||||
img.drawHorizLine(color, x-yy, x+yy, y+xx)
|
||||
img.drawHorizLine(color, x-yy, x+yy, y-xx)
|
||||
}
|
||||
f := 1 - radius
|
||||
dfx := 1
|
||||
dfy := -2 * radius
|
||||
xx := 0
|
||||
yy := radius
|
||||
|
||||
img.Set(x, y+radius, color)
|
||||
img.Set(x, y-radius, color)
|
||||
img.drawHorizLine(color, x-radius, x+radius, y)
|
||||
|
||||
for xx < yy {
|
||||
if f >= 0 {
|
||||
yy--
|
||||
dfy += 2
|
||||
f += dfy
|
||||
}
|
||||
xx++
|
||||
dfx += 2
|
||||
f += dfx
|
||||
img.drawHorizLine(color, x-xx, x+xx, y+yy)
|
||||
img.drawHorizLine(color, x-xx, x+xx, y-yy)
|
||||
img.drawHorizLine(color, x-yy, x+yy, y+xx)
|
||||
img.drawHorizLine(color, x-yy, x+yy, y-xx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) strikeThrough() {
|
||||
r := 0
|
||||
maxx := img.Bounds().Max.X
|
||||
maxy := img.Bounds().Max.Y
|
||||
y := rnd(maxy/3, maxy-maxy/3)
|
||||
for x := 0; x < maxx; x += r {
|
||||
r = rnd(1, img.dotsize/3)
|
||||
y += rnd(-img.dotsize/2, img.dotsize/2)
|
||||
if y <= 0 || y >= maxy {
|
||||
y = rnd(maxy/3, maxy-maxy/3)
|
||||
}
|
||||
img.drawCircle(img.color, x, y, r)
|
||||
}
|
||||
r := 0
|
||||
maxx := img.Bounds().Max.X
|
||||
maxy := img.Bounds().Max.Y
|
||||
y := rnd(maxy/3, maxy-maxy/3)
|
||||
for x := 0; x < maxx; x += r {
|
||||
r = rnd(1, img.dotsize/3)
|
||||
y += rnd(-img.dotsize/2, img.dotsize/2)
|
||||
if y <= 0 || y >= maxy {
|
||||
y = rnd(maxy/3, maxy-maxy/3)
|
||||
}
|
||||
img.drawCircle(img.color, x, y, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (img *Image) drawDigit(digit []byte, x, y int) {
|
||||
skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
|
||||
xs := float64(x)
|
||||
minr := img.dotsize / 2 // minumum radius
|
||||
maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
|
||||
y += rnd(-minr, minr)
|
||||
for yy := 0; yy < fontHeight; yy++ {
|
||||
for xx := 0; xx < fontWidth; xx++ {
|
||||
if digit[yy*fontWidth+xx] != blackChar {
|
||||
continue
|
||||
}
|
||||
// Introduce random variations.
|
||||
or := rnd(minr, maxr)
|
||||
ox := x + (xx * img.dotsize) + rnd(0, or/2)
|
||||
oy := y + (yy * img.dotsize) + rnd(0, or/2)
|
||||
|
||||
img.drawCircle(img.color, ox, oy, or)
|
||||
}
|
||||
xs += skf
|
||||
x = int(xs)
|
||||
}
|
||||
skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
|
||||
xs := float64(x)
|
||||
minr := img.dotsize / 2 // minumum radius
|
||||
maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
|
||||
y += rnd(-minr, minr)
|
||||
for yy := 0; yy < fontHeight; yy++ {
|
||||
for xx := 0; xx < fontWidth; xx++ {
|
||||
if digit[yy*fontWidth+xx] != blackChar {
|
||||
continue
|
||||
}
|
||||
// Introduce random variations.
|
||||
or := rnd(minr, maxr)
|
||||
ox := x + (xx * img.dotsize) + rnd(0, or/2)
|
||||
oy := y + (yy * img.dotsize) + rnd(0, or/2)
|
||||
|
||||
img.drawCircle(img.color, ox, oy, or)
|
||||
}
|
||||
xs += skf
|
||||
x = int(xs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func setRandomBrightness(c *color.NRGBA, max uint8) {
|
||||
minc := min3(c.R, c.G, c.B)
|
||||
maxc := max3(c.R, c.G, c.B)
|
||||
if maxc > max {
|
||||
return
|
||||
}
|
||||
n := rand.Intn(int(max-maxc)) - int(minc)
|
||||
c.R = uint8(int(c.R) + n)
|
||||
c.G = uint8(int(c.G) + n)
|
||||
c.B = uint8(int(c.B) + n)
|
||||
minc := min3(c.R, c.G, c.B)
|
||||
maxc := max3(c.R, c.G, c.B)
|
||||
if maxc > max {
|
||||
return
|
||||
}
|
||||
n := rand.Intn(int(max-maxc)) - int(minc)
|
||||
c.R = uint8(int(c.R) + n)
|
||||
c.G = uint8(int(c.G) + n)
|
||||
c.B = uint8(int(c.B) + n)
|
||||
}
|
||||
|
||||
|
||||
func min3(x, y, z uint8) (o uint8) {
|
||||
o = x
|
||||
if y < o {
|
||||
o = y
|
||||
}
|
||||
if z < o {
|
||||
o = z
|
||||
}
|
||||
return
|
||||
o = x
|
||||
if y < o {
|
||||
o = y
|
||||
}
|
||||
if z < o {
|
||||
o = z
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func max3(x, y, z uint8) (o uint8) {
|
||||
o = x
|
||||
if y > o {
|
||||
o = y
|
||||
}
|
||||
if z > o {
|
||||
o = z
|
||||
}
|
||||
return
|
||||
o = x
|
||||
if y > o {
|
||||
o = y
|
||||
}
|
||||
if z > o {
|
||||
o = z
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// rnd returns a random number in range [from, to].
|
||||
func rnd(from, to int) int {
|
||||
//println(to+1-from)
|
||||
return rand.Intn(to+1-from) + from
|
||||
//println(to+1-from)
|
||||
return rand.Intn(to+1-from) + from
|
||||
}
|
||||
|
||||
|
||||
const (
|
||||
// Standard length of uniuri string to achive ~95 bits of entropy.
|
||||
StdLen = 16
|
||||
// Length of uniurl string to achive ~119 bits of entropy, closest
|
||||
// to what can be losslessly converted to UUIDv4 (122 bits).
|
||||
UUIDLen = 20
|
||||
// Standard length of uniuri string to achive ~95 bits of entropy.
|
||||
StdLen = 16
|
||||
// Length of uniurl string to achive ~119 bits of entropy, closest
|
||||
// to what can be losslessly converted to UUIDv4 (122 bits).
|
||||
UUIDLen = 20
|
||||
)
|
||||
|
||||
|
||||
// Standard characters allowed in uniuri string.
|
||||
var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
|
||||
// New returns a new random string of the standard length, consisting of
|
||||
// standard characters.
|
||||
func New() string {
|
||||
return NewLenChars(StdLen, StdChars)
|
||||
return NewLenChars(StdLen, StdChars)
|
||||
}
|
||||
|
||||
|
||||
// NewLen returns a new random string of the provided length, consisting of
|
||||
// standard characters.
|
||||
func NewLen(length int) string {
|
||||
return NewLenChars(length, StdChars)
|
||||
return NewLenChars(length, StdChars)
|
||||
}
|
||||
|
||||
|
||||
// NewLenChars returns a new random string of the provided length, consisting
|
||||
// of the provided byte slice of allowed characters (maximum 256).
|
||||
func NewLenChars(length int, chars []byte) string {
|
||||
b := make([]byte, length)
|
||||
r := make([]byte, length+(length/4)) // storage for random bytes.
|
||||
clen := byte(len(chars))
|
||||
maxrb := byte(256 - (256 % len(chars)))
|
||||
i := 0
|
||||
for {
|
||||
if _, err := io.ReadFull(crand.Reader, r); err != nil {
|
||||
panic("error reading from random source: " + err.Error())
|
||||
}
|
||||
for _, c := range r {
|
||||
if c >= maxrb {
|
||||
// Skip this number to avoid modulo bias.
|
||||
continue
|
||||
}
|
||||
b[i] = chars[c%clen]
|
||||
i++
|
||||
if i == length {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
b := make([]byte, length)
|
||||
r := make([]byte, length+(length/4)) // storage for random bytes.
|
||||
clen := byte(len(chars))
|
||||
maxrb := byte(256 - (256 % len(chars)))
|
||||
i := 0
|
||||
for {
|
||||
if _, err := io.ReadFull(crand.Reader, r); err != nil {
|
||||
panic("error reading from random source: " + err.Error())
|
||||
}
|
||||
for _, c := range r {
|
||||
if c >= maxrb {
|
||||
// Skip this number to avoid modulo bias.
|
||||
continue
|
||||
}
|
||||
b[i] = chars[c%clen]
|
||||
i++
|
||||
if i == length {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func Fetch() (*Image, string) {
|
||||
d := make([]byte, 4)
|
||||
s := NewLen(4)
|
||||
ss := ""
|
||||
d = []byte(s)
|
||||
for v := range d {
|
||||
d[v] %= 10
|
||||
ss += strconv.FormatInt(int64(d[v]), 32)
|
||||
}
|
||||
return NewImage(d, 100, 40), ss
|
||||
}
|
||||
d := make([]byte, 4)
|
||||
s := NewLen(4)
|
||||
ss := ""
|
||||
d = []byte(s)
|
||||
for v := range d {
|
||||
d[v] %= 10
|
||||
ss += strconv.FormatInt(int64(d[v]), 32)
|
||||
}
|
||||
return NewImage(d, 100, 40), ss
|
||||
}
|
||||
|
||||
26
app/lea/crypto.go
Normal file
26
app/lea/crypto.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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
|
||||
}
|
||||
@@ -24,29 +24,29 @@ import (
|
||||
type Html2Image struct {
|
||||
image *image.RGBA
|
||||
gc *draw2d.ImageGraphicContext
|
||||
|
||||
|
||||
// 试探
|
||||
gc2 *draw2d.ImageGraphicContext
|
||||
|
||||
|
||||
width float64 // 图片宽度
|
||||
height float64
|
||||
|
||||
|
||||
painWidth float64 // 画布宽度
|
||||
|
||||
|
||||
startX float64
|
||||
x float64
|
||||
y float64
|
||||
|
||||
|
||||
isFirstP bool // 是否是第一个段落?
|
||||
|
||||
|
||||
// 换行和段落的高度
|
||||
brY float64
|
||||
pY float64
|
||||
|
||||
|
||||
// 字体
|
||||
normalFontFamily draw2d.FontData
|
||||
boldFontFamily draw2d.FontData
|
||||
|
||||
|
||||
// preTag 之前的标签
|
||||
preTag *html.Node
|
||||
}
|
||||
@@ -58,23 +58,23 @@ func NewHtml2Image() *Html2Image {
|
||||
i, gc := h.InitGc(h.width, h.height)
|
||||
h.gc = gc;
|
||||
h.image = i
|
||||
|
||||
|
||||
// 试探
|
||||
_, h.gc2 = h.InitGc(h.width, 100)
|
||||
|
||||
h.startX = 10
|
||||
|
||||
|
||||
h.startX = 10
|
||||
|
||||
// 最初位置
|
||||
h.x = h.startX
|
||||
h.y = 80
|
||||
|
||||
|
||||
h.isFirstP = true
|
||||
|
||||
|
||||
h.normalFontFamily = draw2d.FontData{"xihei", 4, draw2d.FontStyleNormal};
|
||||
h.boldFontFamily = draw2d.FontData{"heiti", 5, draw2d.FontStyleNormal};
|
||||
|
||||
|
||||
h.SetNormalFont()
|
||||
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
@@ -86,12 +86,12 @@ func (this *Html2Image) InitGc(w, h float64) (* image.RGBA, *draw2d.ImageGraphic
|
||||
gc.SetFillColor(image.White)
|
||||
// fill the background
|
||||
// gc.Clear()
|
||||
|
||||
|
||||
draw2d.SetFontFolder(revel.BasePath + "/public/fonts/weibo")
|
||||
draw2d.Rect(gc, 0, 0, w, h) // 设置背景
|
||||
gc.FillStroke()
|
||||
gc.SetFillColor(image.Black)
|
||||
|
||||
|
||||
// 这个很耗时
|
||||
// gc.Translate(0, 0)
|
||||
return i, gc
|
||||
@@ -101,7 +101,7 @@ func (this *Html2Image) SaveToPngFile(filePath string) bool {
|
||||
// m := this.image;
|
||||
m := this.image.SubImage(image.Rect(0, 0, int(this.width), int(this.y + 20)))
|
||||
// 需要截断之
|
||||
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -124,14 +124,14 @@ func (this *Html2Image) SaveToPngFile(filePath string) bool {
|
||||
func (this *Html2Image) SetSmallFont() {
|
||||
this.gc.SetFontData(this.normalFontFamily)
|
||||
this.gc2.SetFontData(this.normalFontFamily)
|
||||
|
||||
|
||||
this.gc.SetFillColor(color.NRGBA{60, 60, 60, 255})
|
||||
this.gc.SetFontSize(12)
|
||||
this.gc2.SetFontSize(12)
|
||||
|
||||
|
||||
this.brY = 16
|
||||
this.pY = 30
|
||||
|
||||
|
||||
this.painWidth = this.width - 10
|
||||
}
|
||||
|
||||
@@ -139,13 +139,13 @@ func (this *Html2Image) SetNormalFont() {
|
||||
this.gc.SetFillColor(image.Black)
|
||||
this.gc.SetFontData(this.normalFontFamily)
|
||||
this.gc2.SetFontData(this.normalFontFamily)
|
||||
|
||||
|
||||
this.gc.SetFontSize(14)
|
||||
this.gc2.SetFontSize(14)
|
||||
|
||||
|
||||
this.brY = 20
|
||||
this.pY = 30
|
||||
|
||||
|
||||
this.painWidth = this.width - 10
|
||||
}
|
||||
func (this *Html2Image) SetAColor() {
|
||||
@@ -155,16 +155,16 @@ func (this *Html2Image) SetAColor() {
|
||||
// 标题
|
||||
func (this *Html2Image) SetTitleFont() {
|
||||
this.gc.SetFillColor(image.Black)
|
||||
|
||||
|
||||
this.gc.SetFontData(this.boldFontFamily)
|
||||
this.gc2.SetFontData(this.boldFontFamily)
|
||||
|
||||
|
||||
this.gc.SetFontSize(24)
|
||||
this.gc2.SetFontSize(24)
|
||||
|
||||
|
||||
this.brY = 30
|
||||
this.pY = 60
|
||||
|
||||
|
||||
this.painWidth = this.width - 100
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ func (this *Html2Image) SetHeadFont(h string) {
|
||||
|
||||
this.gc.SetFontData(this.boldFontFamily)
|
||||
this.gc2.SetFontData(this.boldFontFamily)
|
||||
|
||||
|
||||
this.painWidth = this.width - 50
|
||||
|
||||
|
||||
if h == "h1" {
|
||||
this.gc.SetFontSize(20)
|
||||
this.gc2.SetFontSize(20)
|
||||
@@ -229,7 +229,7 @@ func (this *Html2Image) IsOver(r []rune) bool {
|
||||
// 以下的方法可以极大节约时间
|
||||
// a, b, c, d := this.gc2.GetStringBounds(string(r))
|
||||
// width2 := c - a + 2
|
||||
|
||||
|
||||
// fmt.Println(width2)
|
||||
// fmt.Println(c - a)
|
||||
|
||||
@@ -268,7 +268,7 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
|
||||
this.InsertText(text, true, prefix)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
r := []rune(text)
|
||||
// 试探吧, 可能需要截取
|
||||
if !needTest || !this.IsOver(r) {
|
||||
@@ -316,17 +316,17 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
|
||||
end = i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 这一段写上
|
||||
// println("------>" + string(r[0:end]))
|
||||
|
||||
|
||||
// 这里, 判断后面一个是否是标点符号
|
||||
end = this.includePunctuation(r, end)
|
||||
this.InsertText(string(r[0:end]), false, prefix)
|
||||
this.NewBr()
|
||||
// 之后的
|
||||
this.InsertText(string(r[end:]), true, prefix)
|
||||
|
||||
|
||||
return;
|
||||
} else {
|
||||
// 没超出, 不用计算, 但出要看是否是结尾了
|
||||
@@ -351,17 +351,17 @@ func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
|
||||
end = maxRI + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 这一段写上
|
||||
// println("-e----->" + string(r[0:end]))
|
||||
|
||||
|
||||
// 这里, 判断后面一个是否是标点符号
|
||||
end = this.includePunctuation(r, end)
|
||||
this.InsertText(string(r[0:end]), false, prefix)
|
||||
this.NewBr()
|
||||
// 之后的
|
||||
this.InsertText(string(r[end:]), true, prefix)
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -376,9 +376,9 @@ func (this *Html2Image) SetBottom(username, url string) {
|
||||
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
|
||||
this.gc.SetLineWidth(2)
|
||||
this.gc.FillStroke()
|
||||
|
||||
|
||||
this.SetSmallFont()
|
||||
|
||||
|
||||
// 左侧写字
|
||||
this.NewP()
|
||||
this.InsertText("本文来自 " + username + " 的leanote笔记", true, " ")
|
||||
@@ -389,11 +389,11 @@ func (this *Html2Image) SetBottom(username, url string) {
|
||||
siteUrl = "http://leanote.com"
|
||||
}
|
||||
this.InsertA(siteUrl + "/blog/" + username, false)
|
||||
|
||||
|
||||
this.setLogo()
|
||||
// this.painWidth = this.width - 100
|
||||
// this.NewP()
|
||||
// this.InsertText("leanote, 不一样的笔记.", false, " ")
|
||||
// this.InsertText("leanote, 不一样的笔记.", false, " ")
|
||||
// this.NewBr()
|
||||
// this.InsertText("在这里你可以管理自己的知识", false, " ")
|
||||
// this.NewBr()
|
||||
@@ -401,7 +401,7 @@ func (this *Html2Image) SetBottom(username, url string) {
|
||||
// this.NewBr()
|
||||
// this.InsertText("并且还可以将笔记设为博客公开", false, " ")
|
||||
// this.InsertText(". 赶紧加入吧! leanote.com", false, "")
|
||||
//
|
||||
//
|
||||
// Logo
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ func (this *Html2Image) setImage(path string, x, y float64) {
|
||||
return;
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
||||
var m1 image.Image
|
||||
_, ext := lea.SplitFilename(path)
|
||||
if ext == ".png" {
|
||||
@@ -424,8 +424,8 @@ func (this *Html2Image) setImage(path string, x, y float64) {
|
||||
if err != nil {
|
||||
return
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.gc.Translate(x, y)
|
||||
this.gc.DrawImage(m1)
|
||||
this.gc.Translate(-x, -y)
|
||||
@@ -448,10 +448,10 @@ func (this *Html2Image) InsertA(text string, isNormal bool) {
|
||||
if text == "" {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
this.SetAColor()
|
||||
this.InsertText(text, true, "")
|
||||
|
||||
|
||||
// 还原
|
||||
if isNormal {
|
||||
this.SetNormalFont()
|
||||
@@ -464,17 +464,17 @@ func (this *Html2Image) InsertA(text string, isNormal bool) {
|
||||
func (this *Html2Image) InsertTitle(title string) {
|
||||
oldX := this.x
|
||||
oldY := this.y - 35
|
||||
|
||||
|
||||
// 插入之
|
||||
this.SetTitleFont()
|
||||
|
||||
|
||||
this.InsertText(title, true, " ")
|
||||
|
||||
|
||||
// 还原字体大小
|
||||
this.SetNormalFont()
|
||||
|
||||
|
||||
this.NewBr()
|
||||
|
||||
|
||||
this.gc.MoveTo(oldX, oldY)
|
||||
this.gc.LineTo(this.x, this.y - 10)
|
||||
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
|
||||
@@ -512,7 +512,7 @@ func (this *Html2Image) InsertCode(n *html.Node) {
|
||||
}
|
||||
}
|
||||
this.NewBr()
|
||||
|
||||
|
||||
this.gc.MoveTo(oldX, oldY)
|
||||
this.gc.LineTo(this.x, this.y - 20)
|
||||
this.gc.SetStrokeColor(color.NRGBA{0, 200, 0, 255})
|
||||
@@ -521,14 +521,14 @@ func (this *Html2Image) InsertCode(n *html.Node) {
|
||||
}
|
||||
|
||||
// 插入图片
|
||||
// 这个path应该是url,
|
||||
// 这个path应该是url,
|
||||
// http://abc.com/a.gif 需要先下载
|
||||
// 或 /upload/a.gif
|
||||
func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
if path == "" {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 是url, 那么取网络图片之
|
||||
var ok bool
|
||||
if strings.HasPrefix(path, "http") || strings.HasPrefix(path, "//") {
|
||||
@@ -539,7 +539,7 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
} else {
|
||||
path = revel.BasePath + "/public/" + path
|
||||
}
|
||||
|
||||
|
||||
// 需要转换, logo不需要转换
|
||||
if(needTrans) {
|
||||
painWidth := uint(this.painWidth - 10)
|
||||
@@ -557,7 +557,7 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
return;
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
||||
var m1 image.Image
|
||||
_, ext := lea.SplitFilename(path)
|
||||
if ext == ".png" {
|
||||
@@ -568,8 +568,8 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
if err != nil {
|
||||
return
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 如果之前是p, 那么不要有<br>
|
||||
if this.preTag.Data != "p" {
|
||||
this.NewBr()
|
||||
@@ -580,9 +580,9 @@ func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
this.gc.Translate(-this.x, -this.y) // 这个有用些
|
||||
this.y += float64(m1.Bounds().Dy()) - 20
|
||||
this.NewP()
|
||||
|
||||
|
||||
os.Remove(path)
|
||||
|
||||
|
||||
// 如果图片是文章第一个的话, 之后的需要p
|
||||
this.isFirstP = false
|
||||
}
|
||||
@@ -605,7 +605,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
this.preTag = n
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
// 标签
|
||||
if n.Type == html.ElementNode {
|
||||
if n.Data == "p" {
|
||||
@@ -616,7 +616,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 也是一个段落, 只是要缩进
|
||||
if n.Data == "ul" || n.Data == "ol" {
|
||||
this.NewP()
|
||||
@@ -637,7 +637,7 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
} else {
|
||||
f(c, n, "")
|
||||
}
|
||||
|
||||
|
||||
if c.Type == html.ElementNode {
|
||||
if c.Data == "br" || c.Data == "p" {
|
||||
needPrefix = true
|
||||
@@ -650,19 +650,19 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
this.NewBr()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 标题
|
||||
if n.Data == "h1" || n.Data == "h2" || n.Data == "h3" || n.Data == "h4" {
|
||||
this.InsertHead(n)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if n.Data == "pre" {
|
||||
// 把之后的全拿过来
|
||||
this.InsertCode(n)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 图片
|
||||
// 得到src
|
||||
if n.Data == "img" {
|
||||
@@ -680,22 +680,22 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 链接
|
||||
// 如果链接里只有文本, 那么单独处理, 如果还有其它的, 不作链接处理
|
||||
if n.Data == "a" {
|
||||
if n.FirstChild == n.LastChild {
|
||||
this.InsertA(n.FirstChild.Data, true)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 空行
|
||||
if n.Data == "br" { // || n.Data == "div"
|
||||
this.NewBr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 是文本, 输出之
|
||||
if n.Type == html.TextNode {
|
||||
data := strings.TrimSpace(n.Data);
|
||||
@@ -705,36 +705,36 @@ func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 其余的
|
||||
|
||||
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c, n, prefix)
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
f(doc, nil, "")
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 主函数
|
||||
func ToImage(uid, username, noteId, title, htmlStr, toPath string) (ok bool) {
|
||||
h := NewHtml2Image()
|
||||
|
||||
|
||||
// 标题
|
||||
h.InsertTitle(title)
|
||||
|
||||
|
||||
// 主体
|
||||
ok = h.InsertBody(htmlStr)
|
||||
if(!ok) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 页眉与页脚
|
||||
h.SetBottom(username, "")
|
||||
|
||||
|
||||
// 保存成png图片
|
||||
ok = h.SaveToPngFile(toPath)
|
||||
return
|
||||
@@ -757,4 +757,4 @@ func TestFillString() {
|
||||
|
||||
func ToImage(uid, username, noteId, title, htmlStr, toPath string) (ok bool) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,3 @@ import (
|
||||
func Html2Image(userInfo info.User, note info.Note, content, toPath string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
223
app/lea/i18n/i18n.go
Normal file
223
app/lea/i18n/i18n.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/revel"
|
||||
"github.com/robfig/config"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CurrentLocaleRenderArg = "currentLocale" // The key for the current locale render arg value
|
||||
|
||||
messageFilesDirectory = "messages"
|
||||
messageFilePattern = `^\w+\.conf$`
|
||||
unknownValueFormat = "??? %s ???"
|
||||
defaultLanguageOption = "i18n.default_language"
|
||||
localeCookieConfigKey = "i18n.cookie"
|
||||
)
|
||||
|
||||
var (
|
||||
// All currently loaded message configs.
|
||||
// en-us, zh-cn, zh-hk ->
|
||||
messages map[string]*config.Config
|
||||
)
|
||||
|
||||
func GetAllLangMessages() map[string]*config.Config {
|
||||
return messages
|
||||
}
|
||||
|
||||
func HasLang(lang string) bool {
|
||||
_, ok := messages[lang]
|
||||
return ok
|
||||
}
|
||||
|
||||
func GetDefaultLang() string {
|
||||
lang, _ := revel.Config.String(defaultLanguageOption)
|
||||
return lang
|
||||
}
|
||||
|
||||
// Return all currently loaded message languages.
|
||||
func MessageLanguages() []string {
|
||||
languages := make([]string, len(messages))
|
||||
i := 0
|
||||
for language, _ := range messages {
|
||||
languages[i] = language
|
||||
i++
|
||||
}
|
||||
return languages
|
||||
}
|
||||
|
||||
// Perform a message look-up for the given locale and message using the given arguments.
|
||||
//
|
||||
// When either an unknown locale or message is detected, a specially formatted string is returned.
|
||||
func Message(locale, message string, args ...interface{}) string {
|
||||
language, region := parseLocale(locale)
|
||||
|
||||
langAndRegion := language + "-" + region
|
||||
// revel.TRACE.Println(langAndRegion + " 怎么回事")
|
||||
|
||||
messageConfig, knownLanguage := messages[langAndRegion]
|
||||
if !knownLanguage {
|
||||
// revel.TRACE.Printf("Unsupported language for locale '%s' and message '%s', trying default language", locale, message)
|
||||
|
||||
if defaultLanguage, found := revel.Config.String(defaultLanguageOption); found {
|
||||
// revel.TRACE.Printf("Using default language '%s'", defaultLanguage)
|
||||
|
||||
messageConfig, knownLanguage = messages[defaultLanguage]
|
||||
if !knownLanguage {
|
||||
// WARN.Printf("Unsupported default language for locale '%s' and message '%s'", defaultLanguage, message)
|
||||
return fmt.Sprintf(unknownValueFormat, message)
|
||||
}
|
||||
} else {
|
||||
// WARN.Printf("Unable to find default language option (%s); messages for unsupported locales will never be translated", defaultLanguageOption)
|
||||
return fmt.Sprintf(unknownValueFormat, message)
|
||||
}
|
||||
}
|
||||
|
||||
// This works because unlike the goconfig documentation suggests it will actually
|
||||
// try to resolve message in DEFAULT if it did not find it in the given section.
|
||||
value, error := messageConfig.String(region, message)
|
||||
if error != nil {
|
||||
// WARN.Printf("Unknown message '%s' for locale '%s'", message, locale)
|
||||
return fmt.Sprintf(unknownValueFormat, message)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
// revel.TRACE.Printf("Arguments detected, formatting '%s' with %v", value, args)
|
||||
value = fmt.Sprintf(value, args...)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func parseLocale(locale string) (language, region string) {
|
||||
if strings.Contains(locale, "-") {
|
||||
languageAndRegion := strings.Split(locale, "-")
|
||||
return languageAndRegion[0], languageAndRegion[1]
|
||||
}
|
||||
|
||||
return locale, ""
|
||||
}
|
||||
|
||||
// Recursively read and cache all available messages from all message files on the given path.
|
||||
func loadMessages(path string) {
|
||||
messages = make(map[string]*config.Config)
|
||||
|
||||
if error := filepath.Walk(path, loadEachMessageLang); error != nil && !os.IsNotExist(error) {
|
||||
// ERROR.Println("Error reading messages files:", error)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载每一个文件夹
|
||||
func loadEachMessageLang(parentPath string, parentInfo os.FileInfo, osError error) (err error) {
|
||||
if !parentInfo.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := filepath.Walk(parentPath, func(path string, info os.FileInfo, osError error) error {
|
||||
return loadMessageFile(parentInfo.Name(), path, info, osError)
|
||||
|
||||
}); err != nil && !os.IsNotExist(err) {
|
||||
// ERROR.Println("Error reading messages files:", error)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Load a single message file
|
||||
func loadMessageFile(locale string, path string, info os.FileInfo, osError error) error {
|
||||
if osError != nil {
|
||||
return osError
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(messageFilePattern, info.Name()); matched {
|
||||
if config, error := parseMessagesFile(path); error != nil {
|
||||
return error
|
||||
} else {
|
||||
// locale := parseLocaleFromFileName(info.Name())
|
||||
// revel.TRACE.Print(locale + "----locale")
|
||||
|
||||
// If we have already parsed a message file for this locale, merge both
|
||||
if _, exists := messages[locale]; exists {
|
||||
messages[locale].Merge(config)
|
||||
revel.TRACE.Printf("Successfully merged messages for locale '%s'", locale)
|
||||
} else {
|
||||
messages[locale] = config
|
||||
}
|
||||
|
||||
revel.TRACE.Println("Successfully loaded messages from file", info.Name())
|
||||
}
|
||||
} else {
|
||||
revel.TRACE.Printf("Ignoring file %s because it did not have a valid extension", info.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseMessagesFile(path string) (messageConfig *config.Config, error error) {
|
||||
messageConfig, error = config.ReadDefault(path)
|
||||
return
|
||||
}
|
||||
|
||||
func parseLocaleFromFileName(file string) string {
|
||||
extension := filepath.Ext(file)[1:]
|
||||
return strings.ToLower(extension)
|
||||
}
|
||||
|
||||
func init() {
|
||||
revel.OnAppStart(func() {
|
||||
loadMessages(filepath.Join(revel.BasePath, messageFilesDirectory))
|
||||
})
|
||||
}
|
||||
|
||||
func I18nFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
if foundCookie, cookieValue := hasLocaleCookie(c.Request); foundCookie {
|
||||
revel.TRACE.Printf("Found locale cookie value: %s", cookieValue)
|
||||
setCurrentLocaleControllerArguments(c, cookieValue)
|
||||
} else if foundHeader, headerValue := hasAcceptLanguageHeader(c.Request); foundHeader {
|
||||
revel.TRACE.Printf("Found Accept-Language header value: %s", headerValue)
|
||||
setCurrentLocaleControllerArguments(c, headerValue)
|
||||
} else {
|
||||
revel.TRACE.Println("Unable to find locale in cookie or header, using empty string")
|
||||
setCurrentLocaleControllerArguments(c, "")
|
||||
}
|
||||
fc[0](c, fc[1:])
|
||||
}
|
||||
|
||||
// Set the current locale controller argument (CurrentLocaleControllerArg) with the given locale.
|
||||
func setCurrentLocaleControllerArguments(c *revel.Controller, locale string) {
|
||||
c.Request.Locale = locale
|
||||
c.RenderArgs[CurrentLocaleRenderArg] = locale
|
||||
}
|
||||
|
||||
// Determine whether the given request has valid Accept-Language value.
|
||||
//
|
||||
// Assumes that the accept languages stored in the request are sorted according to quality, with top
|
||||
// quality first in the slice.
|
||||
func hasAcceptLanguageHeader(request *revel.Request) (bool, string) {
|
||||
if request.AcceptLanguages != nil && len(request.AcceptLanguages) > 0 {
|
||||
return true, request.AcceptLanguages[0].Language
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// Determine whether the given request has a valid language cookie value.
|
||||
func hasLocaleCookie(request *revel.Request) (bool, string) {
|
||||
if request != nil && request.Cookies() != nil {
|
||||
name := revel.Config.StringDefault(localeCookieConfigKey, revel.CookiePrefix+"_LANG")
|
||||
if cookie, error := request.Cookie(name); error == nil {
|
||||
return true, cookie.Value
|
||||
} else {
|
||||
revel.TRACE.Printf("Unable to read locale cookie with name '%s': %s", name, error.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"os"
|
||||
// "path/filepath"
|
||||
"strings"
|
||||
// "path/filepath"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
)
|
||||
|
||||
// net的util
|
||||
@@ -16,33 +17,33 @@ import (
|
||||
// 返回文件的完整目录
|
||||
func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) {
|
||||
if url == "" {
|
||||
return;
|
||||
return
|
||||
}
|
||||
content, err := GetContent(url)
|
||||
if err != nil {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
length = int64(len(content))
|
||||
|
||||
|
||||
// a.html?a=a11&xxx
|
||||
url = trimQueryParams(url)
|
||||
_, ext := SplitFilename(url)
|
||||
if toPath == "" {
|
||||
toPath = "/tmp"
|
||||
}
|
||||
// dir := filepath.Dir(toPath)
|
||||
// dir := filepath.Dir(toPath)
|
||||
newFilename = NewGuid() + ext
|
||||
fullPath := toPath + "/" + newFilename
|
||||
|
||||
|
||||
// 写到文件中
|
||||
file, err := os.Create(fullPath)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file.Write(content)
|
||||
|
||||
|
||||
path = fullPath
|
||||
ok = true
|
||||
return
|
||||
@@ -53,43 +54,43 @@ func GetContent(url string) (content []byte, err error) {
|
||||
var resp *http.Response
|
||||
resp, err = http.Get(url)
|
||||
Log(err)
|
||||
if(resp != nil && resp.Body != nil) {
|
||||
if resp != nil && resp.Body != nil {
|
||||
defer resp.Body.Close()
|
||||
} else {
|
||||
}
|
||||
if resp == nil || resp.Body == nil || err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
buf, err = ioutil.ReadAll(resp.Body)
|
||||
if(err != nil) {
|
||||
Log(err)
|
||||
if resp == nil || resp.Body == nil || err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
|
||||
content = buf;
|
||||
err = nil
|
||||
return
|
||||
|
||||
var buf []byte
|
||||
buf, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
content = buf
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
// 将url ?, #后面的字符串去掉
|
||||
func trimQueryParams(url string) string {
|
||||
pos := strings.Index(url, "?");
|
||||
pos := strings.Index(url, "?")
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
url = Substr(url, 0, pos)
|
||||
}
|
||||
|
||||
pos = strings.Index(url, "#");
|
||||
|
||||
pos = strings.Index(url, "#")
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
url = Substr(url, 0, pos)
|
||||
}
|
||||
|
||||
pos = strings.Index(url, "!");
|
||||
|
||||
pos = strings.Index(url, "!")
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
url = Substr(url, 0, pos)
|
||||
}
|
||||
return url;
|
||||
return url
|
||||
}
|
||||
|
||||
// 通过domain得到ip
|
||||
@@ -99,4 +100,4 @@ func GetIpFromDomain(domain string) string {
|
||||
return ip[0].String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/revel/revel"
|
||||
// "github.com/leanote/leanote/app/service"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
@@ -11,10 +11,11 @@ import (
|
||||
// overwite revel RouterFilter
|
||||
// /api/user/Info => ApiUser.Info()
|
||||
var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"}
|
||||
|
||||
func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
// 补全controller部分
|
||||
path := c.Request.Request.URL.Path
|
||||
|
||||
|
||||
// Figure out the Controller/Action
|
||||
var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)
|
||||
if route == nil {
|
||||
@@ -27,25 +28,29 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
c.Result = c.NotFound("(intentionally)")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//----------
|
||||
// life start
|
||||
/*
|
||||
type URL struct {
|
||||
Scheme string
|
||||
Opaque string // encoded opaque data
|
||||
User *Userinfo // username and password information
|
||||
Host string // host or host:port
|
||||
Path string
|
||||
RawQuery string // encoded query values, without '?'
|
||||
Fragment string // fragment for references, without '#'
|
||||
}
|
||||
type URL struct {
|
||||
Scheme string
|
||||
Opaque string // encoded opaque data
|
||||
User *Userinfo // username and password information
|
||||
Host string // host or host:port
|
||||
Path string
|
||||
RawQuery string // encoded query values, without '?'
|
||||
Fragment string // fragment for references, without '#'
|
||||
}
|
||||
*/
|
||||
if route.ControllerName != "Static" {
|
||||
|
||||
// 检查mongodb 是否lost
|
||||
db.CheckMongoSessionLost()
|
||||
|
||||
// api设置
|
||||
// leanote.com/api/user/get => ApiUser::Get
|
||||
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
||||
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
|
||||
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api") {
|
||||
route.ControllerName = "Api" + route.ControllerName
|
||||
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
|
||||
// member设置
|
||||
@@ -53,7 +58,7 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
}
|
||||
// end
|
||||
}
|
||||
|
||||
|
||||
// Set the action.
|
||||
if err := c.SetAction(route.ControllerName, route.MethodName); err != nil {
|
||||
c.Result = c.NotFound(err.Error())
|
||||
@@ -80,4 +85,3 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
|
||||
fc[0](c, fc[1:])
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
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)
|
||||
}
|
||||
@@ -2,10 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
// "time"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -30,10 +31,10 @@ import (
|
||||
*/
|
||||
|
||||
//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/object_id"}
|
||||
|
||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
||||
|
||||
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 cmdPath = "/usr/local/bin/uglifyjs"
|
||||
@@ -53,26 +54,26 @@ func compressJs(filename string) {
|
||||
to := base + filename + "-min.js"
|
||||
cmd := exec.Command(cmdPath, source, "-o", to)
|
||||
_, err := cmd.CombinedOutput()
|
||||
fmt.Println(source);
|
||||
fmt.Println(source)
|
||||
cmdError(err)
|
||||
}
|
||||
|
||||
|
||||
func combineJs() {
|
||||
// 生成一个总文件
|
||||
cmd := exec.Command("rm", base + "js/all.js")
|
||||
cmd := exec.Command("rm", base+"js/all.js")
|
||||
_, err := cmd.CombinedOutput()
|
||||
cmdError(err)
|
||||
|
||||
|
||||
for _, js := range jss {
|
||||
to := base + js + "-min.js"
|
||||
fmt.Println(to)
|
||||
compressJs(js)
|
||||
|
||||
|
||||
// 每个压缩后的文件放入之
|
||||
cmd2 := exec.Command("/bin/sh", "-c", "cat " + to + " >> " + base + "js/all.js")
|
||||
cmd2 := exec.Command("/bin/sh", "-c", "cat "+to+" >> "+base+"js/all.js")
|
||||
_, err := cmd2.CombinedOutput()
|
||||
cmdError(err)
|
||||
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> " + base + "js/all.js")
|
||||
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> "+base+"js/all.js")
|
||||
_, err = cmd2.CombinedOutput()
|
||||
cmdError(err)
|
||||
}
|
||||
@@ -81,82 +82,77 @@ func combineJs() {
|
||||
// 改note-dev->note
|
||||
func dev() {
|
||||
// 即替换note.js->note-min.js
|
||||
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
|
||||
"tinymce.js": "tinymce.min.js",
|
||||
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
|
||||
"note.js": "note-min.js",
|
||||
"app.js": "app-min.js",
|
||||
"page.js": "page-min.js",
|
||||
"common.js": "common-min.js",
|
||||
"notebook.js": "notebook-min.js",
|
||||
"share.js": "share-min.js",
|
||||
"tag.js": "tag-min.js",
|
||||
"main.js": "main-min.js",
|
||||
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||
"editor/editor.js": "editor/editor-min.js",
|
||||
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
|
||||
"tinymce.js": "tinymce.min.js",
|
||||
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
|
||||
"note.js": "note-min.js",
|
||||
"app.js": "app-min.js",
|
||||
"page.js": "page-min.js",
|
||||
"common.js": "common-min.js",
|
||||
"notebook.js": "notebook-min.js",
|
||||
"share.js": "share-min.js",
|
||||
"tag.js": "tag-min.js",
|
||||
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||
"editor/editor.js": "editor/editor-min.js",
|
||||
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
||||
"console.log(o);": "",
|
||||
}
|
||||
"console.log(o);": "",
|
||||
}
|
||||
path := base1 + "/src/views/note/note-dev.html"
|
||||
target := base1 + "/src/views/note/note.html"
|
||||
|
||||
|
||||
bs, _ := ioutil.ReadFile(path)
|
||||
content := string(bs)
|
||||
print(content)
|
||||
for key, value := range m {
|
||||
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)
|
||||
}
|
||||
|
||||
// 压缩js成一块
|
||||
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]"
|
||||
// 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")
|
||||
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||
|
||||
// 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("/bin/sh", "-c", "grunt minify")
|
||||
cmd.Dir = base + "/tinymce_4.1.9"
|
||||
|
||||
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")
|
||||
cmd2.CombinedOutput()
|
||||
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()
|
||||
fmt.Println(string(c))
|
||||
|
||||
c, _ = cmd.CombinedOutput()
|
||||
fmt.Println(string(c))
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 压缩tinymce
|
||||
tinymce()
|
||||
|
||||
dev();
|
||||
|
||||
// tinymce()
|
||||
|
||||
dev()
|
||||
|
||||
// 其它零散的需要压缩的js
|
||||
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",
|
||||
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
||||
"js/jquery.ztree.all-3.5",
|
||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _, js := range otherJss {
|
||||
compressJs(js)
|
||||
}
|
||||
|
||||
|
||||
// 先压缩后合并
|
||||
combineJs()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
@@ -30,9 +30,9 @@ func (this *AlbumService) GetAlbums(userId string) []info.Album {
|
||||
// delete album
|
||||
// presupposition: has no images under this ablum
|
||||
func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) {
|
||||
if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId),
|
||||
if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
}) == 0 {
|
||||
}) == 0 {
|
||||
return db.DeleteByIdAndUserId(db.Albums, albumId, userId), ""
|
||||
}
|
||||
return false, "has images"
|
||||
@@ -41,4 +41,4 @@ func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) {
|
||||
// update album name
|
||||
func (this *AlbumService) UpdateAlbum(albumId, userId, name string) bool {
|
||||
return db.UpdateByIdAndUserIdField(db.Albums, albumId, userId, "Name", name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ type AttachService struct {
|
||||
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
|
||||
attach.CreatedTime = time.Now()
|
||||
ok = db.Insert(db.Attachs, attach)
|
||||
|
||||
|
||||
note := noteService.GetNoteById(attach.NoteId.Hex())
|
||||
|
||||
|
||||
// api调用时, 添加attach之前是没有note的
|
||||
var userId string
|
||||
if note.NoteId != "" {
|
||||
@@ -35,13 +35,13 @@ func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool,
|
||||
// 更新笔记的attachs num
|
||||
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||
}
|
||||
|
||||
|
||||
if !fromApi {
|
||||
// 增长note's usn
|
||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 更新笔记的附件个数
|
||||
@@ -49,13 +49,13 @@ func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool,
|
||||
func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int) bool {
|
||||
num := db.Count(db.Attachs, bson.M{"NoteId": noteId})
|
||||
/*
|
||||
note := info.Note{}
|
||||
note = noteService.GetNoteById(noteId.Hex())
|
||||
note.AttachNum += addNum
|
||||
if note.AttachNum < 0 {
|
||||
note.AttachNum = 0
|
||||
}
|
||||
Log(note.AttachNum)
|
||||
note := info.Note{}
|
||||
note = noteService.GetNoteById(noteId.Hex())
|
||||
note.AttachNum += addNum
|
||||
if note.AttachNum < 0 {
|
||||
note.AttachNum = 0
|
||||
}
|
||||
Log(note.AttachNum)
|
||||
*/
|
||||
return db.UpdateByQField(db.Notes, bson.M{"_id": noteId}, "AttachNum", num)
|
||||
}
|
||||
@@ -63,11 +63,20 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
|
||||
// list attachs
|
||||
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||
attachs := []info.Attach{}
|
||||
// 判断是否有权限为笔记添加附件
|
||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
|
||||
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
||||
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
return attachs
|
||||
}
|
||||
|
||||
// 笔记是否是自己的
|
||||
note := noteService.GetNoteByIdAndUserId(noteId, userId)
|
||||
if note.NoteId == "" {
|
||||
return attachs
|
||||
}
|
||||
|
||||
// TODO 这里, 优化权限控制
|
||||
|
||||
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
||||
|
||||
return attachs
|
||||
@@ -110,16 +119,17 @@ func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
||||
}
|
||||
|
||||
// delete attach
|
||||
// 删除附件为什么要incrNoteUsn ? 因为可能没有内容要修改的
|
||||
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
|
||||
attach := info.Attach{}
|
||||
db.Get(db.Attachs, attachId, &attach)
|
||||
|
||||
if(attach.AttachId != "") {
|
||||
|
||||
if attach.AttachId != "" {
|
||||
// 判断是否有权限为笔记添加附件
|
||||
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
|
||||
return false, "No Perm"
|
||||
}
|
||||
|
||||
|
||||
if db.Delete(db.Attachs, bson.M{"_id": bson.ObjectIdHex(attachId)}) {
|
||||
this.updateNoteAttachNum(attach.NoteId, -1)
|
||||
attach.Path = strings.TrimLeft(attach.Path, "/")
|
||||
@@ -128,7 +138,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
||||
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size)
|
||||
// 修改note Usn
|
||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
||||
|
||||
|
||||
return true, "delete file success"
|
||||
}
|
||||
return false, "delete file error"
|
||||
|
||||
@@ -2,26 +2,31 @@ package service
|
||||
|
||||
import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/db"
|
||||
// "github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/revel/revel"
|
||||
"strings"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/revel/revel"
|
||||
"errors"
|
||||
"fmt"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 登录与权限
|
||||
// 登录与权限 Login & Register
|
||||
|
||||
type AuthService struct {
|
||||
}
|
||||
|
||||
// pwd已md5了
|
||||
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||
// 使用bcrypt认证或者Md5认证
|
||||
// Use bcrypt (Md5 depreciated)
|
||||
func (this *AuthService) Login(emailOrUsername, pwd string) (info.User, error) {
|
||||
emailOrUsername = strings.Trim(emailOrUsername, " ")
|
||||
// pwd = strings.Trim(pwd, " ")
|
||||
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||
return userInfo
|
||||
// pwd = strings.Trim(pwd, " ")
|
||||
userInfo := userService.GetUserInfoByName(emailOrUsername)
|
||||
if userInfo.UserId == "" || !ComparePwd(pwd, userInfo.Pwd) {
|
||||
return userInfo, errors.New("wrong username or password")
|
||||
}
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
// 注册
|
||||
@@ -40,71 +45,74 @@ func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string)
|
||||
if userService.IsExistsUser(email) {
|
||||
return false, "userHasBeenRegistered-" + email
|
||||
}
|
||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||
passwd := GenPwd(pwd)
|
||||
if passwd == "" {
|
||||
return false, "GenerateHash error"
|
||||
}
|
||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: passwd}
|
||||
if fromUserId != "" && IsObjectId(fromUserId) {
|
||||
user.FromUserId = bson.ObjectIdHex(fromUserId)
|
||||
}
|
||||
LogJ(user)
|
||||
return this.register(user)
|
||||
}
|
||||
|
||||
func (this *AuthService) register(user info.User) (bool, string) {
|
||||
if userService.AddUser(user) {
|
||||
// 添加笔记本, 生活, 学习, 工作
|
||||
userId := user.UserId.Hex();
|
||||
userId := user.UserId.Hex()
|
||||
notebook := info.Notebook{
|
||||
Seq: -1,
|
||||
Seq: -1,
|
||||
UserId: user.UserId}
|
||||
title2Id := map[string]bson.ObjectId{"life": bson.NewObjectId(), "study": bson.NewObjectId(), "work": bson.NewObjectId()}
|
||||
for title, objectId := range title2Id {
|
||||
notebook.Title = title
|
||||
notebook.NotebookId = objectId
|
||||
notebook.UserId = user.UserId
|
||||
notebookService.AddNotebook(notebook);
|
||||
notebookService.AddNotebook(notebook)
|
||||
}
|
||||
|
||||
|
||||
// 添加leanote -> 该用户的共享
|
||||
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
||||
if(registerSharedUserId != "") {
|
||||
if registerSharedUserId != "" {
|
||||
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
|
||||
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
|
||||
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
|
||||
|
||||
|
||||
// 添加共享笔记本
|
||||
for _, notebook := range registerSharedNotebooks {
|
||||
perm, _ := strconv.Atoi(notebook["perm"])
|
||||
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId);
|
||||
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId)
|
||||
}
|
||||
|
||||
|
||||
// 添加共享笔记
|
||||
for _, note := range registerSharedNotes {
|
||||
perm, _ := strconv.Atoi(note["perm"])
|
||||
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId);
|
||||
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId)
|
||||
}
|
||||
|
||||
|
||||
// 复制笔记
|
||||
for _, noteId := range registerCopyNoteIds {
|
||||
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
||||
// Log(noteId)
|
||||
// Log("Copy")
|
||||
// LogJ(note)
|
||||
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex())
|
||||
// Log(noteId)
|
||||
// Log("Copy")
|
||||
// LogJ(note)
|
||||
noteUpdate := bson.M{"IsBlog": false} // 不要是博客
|
||||
noteService.UpdateNote(user.UserId.Hex(), note.NoteId.Hex(), noteUpdate, -1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------
|
||||
// 添加一条userBlog
|
||||
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
||||
Title: user.Username + " 's Blog",
|
||||
SubTitle: "Love Leanote!",
|
||||
AboutMe: "Hello, I am (^_^)",
|
||||
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
||||
Title: user.Username + " 's Blog",
|
||||
SubTitle: "Love Leanote!",
|
||||
AboutMe: "Hello, I am (^_^)",
|
||||
CanComment: true,
|
||||
})
|
||||
})
|
||||
// 添加一个单页面
|
||||
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
|
||||
}
|
||||
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
@@ -115,7 +123,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
||||
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
|
||||
username = thirdType + "-" + thirdUsername
|
||||
i := 1
|
||||
for ;; {
|
||||
for {
|
||||
if !userService.IsExistsUserByUsername(username) {
|
||||
return
|
||||
}
|
||||
@@ -131,11 +139,11 @@ func (this *AuthService) ThirdRegister(thirdType, thirdUserId, thirdUsername str
|
||||
}
|
||||
|
||||
username := this.getUsername(thirdType, thirdUsername)
|
||||
userInfo = info.User{UserId: bson.NewObjectId(),
|
||||
Username: username,
|
||||
ThirdUserId: thirdUserId,
|
||||
userInfo = info.User{UserId: bson.NewObjectId(),
|
||||
Username: username,
|
||||
ThirdUserId: thirdUserId,
|
||||
ThirdUsername: thirdUsername,
|
||||
}
|
||||
}
|
||||
_, _ = this.register(userInfo)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,7 +45,9 @@ func (this *BlogService) GetBlogByIdAndUrlTitle(userId string, noteIdOrUrlTitle
|
||||
return this.GetBlog(noteIdOrUrlTitle)
|
||||
}
|
||||
note := info.Note{}
|
||||
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle), "IsBlog": true, "IsTrash": false}, ¬e)
|
||||
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle),
|
||||
"IsBlog": true,
|
||||
"IsTrash": false, "IsDeleted": false}, ¬e)
|
||||
return this.GetBlogItem(note)
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||
}
|
||||
func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
||||
if note.NoteId == "" || !note.IsBlog {
|
||||
return
|
||||
return info.BlogItem{}
|
||||
}
|
||||
|
||||
// 内容
|
||||
@@ -131,7 +133,8 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
||||
func (this *BlogService) GetBlogTags(userId string) []info.TagCount {
|
||||
// 得到所有博客
|
||||
tagCounts := []info.TagCount{}
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}
|
||||
// tag不能为空
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "Tag": bson.M{"$ne": ""}}
|
||||
db.TagCounts.Find(query).Sort("-Count").All(&tagCounts)
|
||||
return tagCounts
|
||||
}
|
||||
@@ -142,7 +145,7 @@ func (this *BlogService) ReCountBlogTags(userId string) bool {
|
||||
// 得到所有博客
|
||||
notes := []info.Note{}
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true}
|
||||
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsDeleted": false, "IsBlog": true}
|
||||
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es)
|
||||
|
||||
db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true})
|
||||
@@ -184,7 +187,7 @@ Posts: []
|
||||
*/
|
||||
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);
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false}
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false, "IsDeleted": false}
|
||||
if notebookId != "" {
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||
}
|
||||
@@ -291,9 +294,10 @@ func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumb
|
||||
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"IsBlog": true,
|
||||
"Tags": bson.M{"$all": tags}}
|
||||
"IsTrash": false,
|
||||
"IsDeleted": false,
|
||||
"IsBlog": true,
|
||||
"Tags": bson.M{"$all": tags}}
|
||||
|
||||
q := db.Notes.Find(query)
|
||||
|
||||
@@ -366,10 +370,10 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
|
||||
if !isAsc {
|
||||
// 降序
|
||||
/*
|
||||
------- pre
|
||||
----- now
|
||||
--- next
|
||||
--
|
||||
------- pre
|
||||
----- now
|
||||
--- next
|
||||
--
|
||||
*/
|
||||
// 上一篇时间要比它大, 找最小的
|
||||
sortFieldT1 = bson.M{"$gte": baseTime} // 为什么要相等, 因为将notebook发布成博客, 会统一修改note的publicTime, 此时所有notes都一样
|
||||
@@ -393,12 +397,14 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
|
||||
sortFieldR2 = sorterField
|
||||
}
|
||||
|
||||
// 1
|
||||
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
|
||||
note := info.Note{}
|
||||
query := bson.M{"UserId": userIdO,
|
||||
"IsTrash": false,
|
||||
"IsBlog": true,
|
||||
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
|
||||
query := bson.M{"UserId": userIdO,
|
||||
"IsTrash": false,
|
||||
"IsDeleted": false,
|
||||
"IsBlog": true,
|
||||
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
|
||||
sorterField: sortFieldT1,
|
||||
}
|
||||
q := db.Notes.Find(query)
|
||||
@@ -415,7 +421,7 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
|
||||
// Log(sortFieldR2)
|
||||
q = db.Notes.Find(query)
|
||||
q.Sort(sortFieldR2).Limit(1).One(¬e2)
|
||||
|
||||
|
||||
return this.FixNote(note), this.FixNote(note2)
|
||||
}
|
||||
|
||||
@@ -430,7 +436,7 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
|
||||
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
|
||||
|
||||
// 不是trash的
|
||||
query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
|
||||
query := bson.M{"IsTrash": false, "IsDeleted": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
|
||||
if tag != "" {
|
||||
query["Tags"] = bson.M{"$in": []string{tag}}
|
||||
}
|
||||
@@ -496,6 +502,9 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
*/
|
||||
if len(note.Tags) == 1 && note.Tags[0] == "" {
|
||||
note.Tags = nil
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
|
||||
}
|
||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||
@@ -509,7 +518,7 @@ func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
|
||||
// Logo路径问题, 有些有http: 有些没有
|
||||
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
|
||||
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
|
||||
userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo
|
||||
userBlog.Logo = "/" + userBlog.Logo
|
||||
}
|
||||
|
||||
if userBlog.SortField == "" {
|
||||
@@ -664,19 +673,18 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
|
||||
|
||||
noteIdO := bson.ObjectIdHex(noteId)
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
var n int
|
||||
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
|
||||
n = 1
|
||||
// 添加之
|
||||
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
|
||||
isLike = true
|
||||
} else {
|
||||
// 已点过, 那么删除之
|
||||
n = -1
|
||||
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
|
||||
isLike = false
|
||||
}
|
||||
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
|
||||
|
||||
count := db.Count(db.BlogLikes, bson.M{"NoteId": noteIdO})
|
||||
ok = db.UpdateByQI(db.Notes, bson.M{"_id": noteIdO}, bson.M{"LikeNum": count})
|
||||
|
||||
return
|
||||
}
|
||||
@@ -910,7 +918,7 @@ func (this *BlogService) UpateCateUrlTitle(userId string, cateId, urlTitle strin
|
||||
"UrlTitle": "",
|
||||
})
|
||||
*/
|
||||
url = GetUrTitle(userId, urlTitle, "notebook")
|
||||
url = GetUrTitle(userId, urlTitle, "notebook", cateId)
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
@@ -926,7 +934,7 @@ func (this *BlogService) UpateBlogUrlTitle(userId string, noteId, urlTitle strin
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
|
||||
"UrlTitle": "",
|
||||
})
|
||||
url = GetUrTitle(userId, urlTitle, "note")
|
||||
url = GetUrTitle(userId, urlTitle, "note", noteId)
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
@@ -1027,7 +1035,7 @@ func (this *BlogService) UpdateSingleUrlTitle(userId, singleId, urlTitle string)
|
||||
"UrlTitle": "",
|
||||
})
|
||||
*/
|
||||
url = GetUrTitle(userId, urlTitle, "single")
|
||||
url = GetUrTitle(userId, urlTitle, "single", singleId)
|
||||
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
@@ -1061,7 +1069,7 @@ func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content stri
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Title: title,
|
||||
Content: content,
|
||||
UrlTitle: GetUrTitle(userId, title, "single"),
|
||||
UrlTitle: GetUrTitle(userId, title, "single", singleId),
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
page.UpdatedTime = page.CreatedTime
|
||||
@@ -1099,6 +1107,7 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool
|
||||
|
||||
// 得到用户的博客url
|
||||
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
||||
/*
|
||||
if userBlog != nil {
|
||||
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||
return configService.GetUserUrl(userBlog.Domain)
|
||||
@@ -1109,12 +1118,15 @@ func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string
|
||||
username = userBlog.UserId.Hex()
|
||||
}
|
||||
}
|
||||
*/
|
||||
return configService.GetBlogUrl() + "/" + username
|
||||
}
|
||||
|
||||
// 得到所有url
|
||||
func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.User) info.BlogUrls {
|
||||
var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl string
|
||||
|
||||
/*
|
||||
if userBlog.Domain != "" && configService.AllowCustomDomain() { // http://demo.com
|
||||
// ok
|
||||
indexUrl = configService.GetUserUrl(userBlog.Domain)
|
||||
@@ -1135,6 +1147,7 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
|
||||
tagsUrl = indexUrl + "/tags"
|
||||
tagPostsUrl = indexUrl + "/tag"
|
||||
} else {
|
||||
*/
|
||||
// ok
|
||||
blogUrl := configService.GetBlogUrl() // blog.leanote.com
|
||||
userIdOrEmail := ""
|
||||
@@ -1153,7 +1166,7 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
|
||||
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/username
|
||||
tagsUrl = blogUrl + "/tags/" + userIdOrEmail
|
||||
tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/username
|
||||
}
|
||||
// }
|
||||
|
||||
return info.BlogUrls{
|
||||
IndexUrl: indexUrl,
|
||||
@@ -1197,6 +1210,10 @@ func (this *BlogService) FixBlog(blog info.BlogItem) info.Post {
|
||||
LikeNum: blog.LikeNum,
|
||||
IsMarkdown: blog.IsMarkdown,
|
||||
}
|
||||
if blog2.Tags != nil && len(blog2.Tags) > 0 && blog2.Tags[0] != "" {
|
||||
} else {
|
||||
blog2.Tags = nil
|
||||
}
|
||||
return blog2
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/revel/revel"
|
||||
"time"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"os"
|
||||
"os/exec"
|
||||
"fmt"
|
||||
"strings"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 配置服务
|
||||
// 只是全局的, 用户的配置没有
|
||||
type ConfigService struct {
|
||||
adminUserId string
|
||||
siteUrl string
|
||||
adminUserId string
|
||||
siteUrl string
|
||||
adminUsername string
|
||||
// 全局的
|
||||
GlobalAllConfigs map[string]interface{}
|
||||
GlobalAllConfigs map[string]interface{}
|
||||
GlobalStringConfigs map[string]string
|
||||
GlobalArrayConfigs map[string][]string
|
||||
GlobalMapConfigs map[string]map[string]string
|
||||
GlobalArrayConfigs map[string][]string
|
||||
GlobalMapConfigs map[string]map[string]string
|
||||
GlobalArrMapConfigs map[string][]map[string]string
|
||||
}
|
||||
|
||||
// appStart时 将全局的配置从数据库中得到作为全局
|
||||
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalAllConfigs = map[string]interface{}{}
|
||||
@@ -34,22 +35,23 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalArrayConfigs = map[string][]string{}
|
||||
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||
|
||||
|
||||
this.adminUsername, _ = revel.Config.String("adminUsername")
|
||||
if this.adminUsername == "" {
|
||||
this.adminUsername = "admin"
|
||||
}
|
||||
this.siteUrl, _ = revel.Config.String("site.url")
|
||||
|
||||
|
||||
userInfo := userService.GetUserInfoByAny(this.adminUsername)
|
||||
if userInfo.UserId == "" {
|
||||
return false
|
||||
}
|
||||
this.adminUserId = userInfo.UserId.Hex()
|
||||
|
||||
|
||||
configs := []info.Config{}
|
||||
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||
|
||||
// db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||
db.ListByQ(db.Configs, bson.M{}, &configs)
|
||||
|
||||
for _, config := range configs {
|
||||
if config.IsArr {
|
||||
this.GlobalArrayConfigs[config.Key] = config.ValueArr
|
||||
@@ -65,12 +67,22 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalAllConfigs[config.Key] = config.ValueStr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// site URL
|
||||
if s, ok := this.GlobalStringConfigs["siteUrl"]; !ok || s != "" {
|
||||
this.GlobalStringConfigs["siteUrl"] = this.siteUrl
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetSiteUrl() string {
|
||||
return this.siteUrl;
|
||||
s := this.GetGlobalStringConfig("siteUrl")
|
||||
if s != "" {
|
||||
return s
|
||||
}
|
||||
|
||||
return this.siteUrl
|
||||
}
|
||||
func (this *ConfigService) GetAdminUsername() string {
|
||||
return this.adminUsername
|
||||
@@ -84,15 +96,15 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
|
||||
// 判断是否存在
|
||||
if _, ok := this.GlobalAllConfigs[key]; !ok {
|
||||
// 需要添加
|
||||
config := info.Config{ConfigId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Key: key,
|
||||
IsArr: isArr,
|
||||
IsMap: isMap,
|
||||
IsArrMap: isArrMap,
|
||||
config := info.Config{ConfigId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId), // 没用
|
||||
Key: key,
|
||||
IsArr: isArr,
|
||||
IsMap: isMap,
|
||||
IsArrMap: isArrMap,
|
||||
UpdatedTime: time.Now(),
|
||||
}
|
||||
if(isArr) {
|
||||
if isArr {
|
||||
v, _ := value.([]string)
|
||||
config.ValueArr = v
|
||||
this.GlobalArrayConfigs[key] = v
|
||||
@@ -113,7 +125,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
|
||||
} else {
|
||||
i := bson.M{"UpdatedTime": time.Now()}
|
||||
this.GlobalAllConfigs[key] = value
|
||||
if(isArr) {
|
||||
if isArr {
|
||||
v, _ := value.([]string)
|
||||
i["ValueArr"] = v
|
||||
this.GlobalArrayConfigs[key] = v
|
||||
@@ -130,7 +142,8 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
|
||||
i["ValueStr"] = v
|
||||
this.GlobalStringConfigs[key] = v
|
||||
}
|
||||
return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
|
||||
// return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
|
||||
return db.UpdateByQMap(db.Configs, bson.M{"Key": key}, i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,25 +190,26 @@ func (this *ConfigService) GetGlobalArrMapConfig(key string) []map[string]string
|
||||
func (this *ConfigService) IsOpenRegister() bool {
|
||||
return this.GetGlobalStringConfig("openRegister") != ""
|
||||
}
|
||||
|
||||
//-------
|
||||
// 修改共享笔记的配置
|
||||
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) (ok bool, msg string) {
|
||||
|
||||
defer func() {
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
msg = fmt.Sprint(err)
|
||||
}
|
||||
}();
|
||||
|
||||
}()
|
||||
|
||||
// 用户是否存在?
|
||||
if registerSharedUserId == "" {
|
||||
ok = true
|
||||
msg = "share userId is blank, So it share nothing to register"
|
||||
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
|
||||
return
|
||||
return
|
||||
} else {
|
||||
user := userService.GetUserInfo(registerSharedUserId)
|
||||
if user.UserId == "" {
|
||||
@@ -206,7 +220,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
notebooks := []map[string]string{}
|
||||
// 共享笔记本
|
||||
if len(registerSharedNotebookIds) > 0 {
|
||||
@@ -222,7 +236,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
msg = "The user has no such notebook: " + notebookId
|
||||
return
|
||||
} else {
|
||||
perm := "0";
|
||||
perm := "0"
|
||||
if registerSharedNotebookPerms[i] == 1 {
|
||||
perm = "1"
|
||||
}
|
||||
@@ -231,7 +245,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks)
|
||||
|
||||
|
||||
notes := []map[string]string{}
|
||||
// 共享笔记
|
||||
if len(registerSharedNoteIds) > 0 {
|
||||
@@ -247,7 +261,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
msg = "The user has no such note: " + noteId
|
||||
return
|
||||
} else {
|
||||
perm := "0";
|
||||
perm := "0"
|
||||
if registerSharedNotePerms[i] == 1 {
|
||||
perm = "1"
|
||||
}
|
||||
@@ -256,7 +270,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
|
||||
|
||||
|
||||
// 复制
|
||||
noteIds := []string{}
|
||||
if len(registerCopyNoteIds) > 0 {
|
||||
@@ -277,7 +291,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds)
|
||||
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
@@ -298,7 +312,7 @@ func (this *ConfigService) getBackupDirname() string {
|
||||
}
|
||||
func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
|
||||
binPath := configService.GetGlobalStringConfig("mongodumpPath")
|
||||
config := revel.Config;
|
||||
config := revel.Config
|
||||
dbname, _ := config.String("db.dbname")
|
||||
host, _ := revel.Config.String("db.host")
|
||||
port, _ := revel.Config.String("db.port")
|
||||
@@ -318,20 +332,21 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||
Log(binPath);
|
||||
Log(binPath)
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
ok = false
|
||||
Log("error:......")
|
||||
Log(string(b))
|
||||
return
|
||||
}
|
||||
Log("error:......")
|
||||
Log(string(b))
|
||||
return
|
||||
}
|
||||
ok = configService.AddBackup(dir, remark)
|
||||
return ok, msg
|
||||
return ok, msg
|
||||
}
|
||||
|
||||
// 还原
|
||||
func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
||||
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||
@@ -339,22 +354,22 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
||||
var backup map[string]string
|
||||
for i, backup = range backups {
|
||||
if backup["createdTime"] == createdTime {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(backups) {
|
||||
return false, "Backup Not Found"
|
||||
}
|
||||
|
||||
|
||||
// 先备份当前
|
||||
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"] )
|
||||
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"])
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/
|
||||
binPath := configService.GetGlobalStringConfig("mongorestorePath")
|
||||
config := revel.Config;
|
||||
config := revel.Config
|
||||
dbname, _ := config.String("db.dbname")
|
||||
host, _ := revel.Config.String("db.host")
|
||||
port, _ := revel.Config.String("db.port")
|
||||
@@ -365,26 +380,26 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
||||
if username != "" {
|
||||
binPath += " -u " + username + " -p " + password
|
||||
}
|
||||
|
||||
|
||||
path := backup["path"] + "/" + dbname
|
||||
// 判断路径是否存在
|
||||
if !IsDirExists(path) {
|
||||
return false, path + " Is Not Exists"
|
||||
}
|
||||
|
||||
|
||||
binPath += " " + path
|
||||
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||
Log(binPath);
|
||||
Log(binPath)
|
||||
b, err := cmd.Output()
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
ok = false
|
||||
Log("error:......")
|
||||
Log(string(b))
|
||||
return
|
||||
}
|
||||
|
||||
Log("error:......")
|
||||
Log(string(b))
|
||||
return
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
|
||||
@@ -393,22 +408,22 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
|
||||
var backup map[string]string
|
||||
for i, backup = range backups {
|
||||
if backup["createdTime"] == createdTime {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(backups) {
|
||||
return false, "Backup Not Found"
|
||||
}
|
||||
|
||||
|
||||
// 删除文件夹之
|
||||
err := os.RemoveAll(backups[i]["path"])
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("%v", err)
|
||||
}
|
||||
|
||||
|
||||
// 删除之
|
||||
backups = append(backups[0:i], backups[i+1:]...)
|
||||
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
@@ -419,14 +434,14 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
|
||||
var backup map[string]string
|
||||
for i, backup = range backups {
|
||||
if backup["createdTime"] == createdTime {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(backups) {
|
||||
return false, "Backup Not Found"
|
||||
}
|
||||
backup["remark"] = remark;
|
||||
|
||||
backup["remark"] = remark
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
@@ -438,7 +453,7 @@ func (this *ConfigService) GetBackup(createdTime string) (map[string]string, boo
|
||||
var backup map[string]string
|
||||
for i, backup = range backups {
|
||||
if backup["createdTime"] == createdTime {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(backups) {
|
||||
@@ -455,13 +470,16 @@ var port string
|
||||
|
||||
func init() {
|
||||
revel.OnAppStart(func() {
|
||||
port = strconv.Itoa(revel.HttpPort)
|
||||
if port != "80" {
|
||||
port = ":" + port
|
||||
} else {
|
||||
port = "";
|
||||
}
|
||||
|
||||
/*
|
||||
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
|
||||
port = strconv.Itoa(revel.HttpPort)
|
||||
if port != "80" {
|
||||
port = ":" + port
|
||||
} else {
|
||||
port = "";
|
||||
}
|
||||
*/
|
||||
|
||||
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
||||
if strings.HasPrefix(siteUrl, "http://") {
|
||||
defaultDomain = siteUrl[len("http://"):]
|
||||
@@ -469,53 +487,51 @@ func init() {
|
||||
defaultDomain = siteUrl[len("https://"):]
|
||||
schema = "https://"
|
||||
}
|
||||
|
||||
// port localhost:9000
|
||||
ports := strings.Split(defaultDomain, ":")
|
||||
if len(ports) == 2 {
|
||||
port = ports[1]
|
||||
}
|
||||
if port == "80" {
|
||||
port = ""
|
||||
} else {
|
||||
port = ":" + port
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetSchema() string {
|
||||
return schema;
|
||||
return schema
|
||||
}
|
||||
|
||||
// 默认
|
||||
func (this *ConfigService) GetDefaultDomain() string {
|
||||
return defaultDomain
|
||||
}
|
||||
// 包含http://
|
||||
func (this *ConfigService) GetDefaultUrl() string {
|
||||
return schema + defaultDomain
|
||||
}
|
||||
|
||||
// note
|
||||
func (this *ConfigService) GetNoteDomain() string {
|
||||
subDomain := this.GetGlobalStringConfig("noteSubDomain");
|
||||
if subDomain != "" {
|
||||
return subDomain + port
|
||||
}
|
||||
return this.GetDefaultDomain() + "/note"
|
||||
return "/note"
|
||||
}
|
||||
func (this *ConfigService) GetNoteUrl() string {
|
||||
return schema + this.GetNoteDomain();
|
||||
return this.GetNoteDomain()
|
||||
}
|
||||
|
||||
// blog
|
||||
func (this *ConfigService) GetBlogDomain() string {
|
||||
subDomain := this.GetGlobalStringConfig("blogSubDomain");
|
||||
if subDomain != "" {
|
||||
return subDomain + port
|
||||
}
|
||||
return this.GetDefaultDomain() + "/blog"
|
||||
return "/blog"
|
||||
}
|
||||
func (this *ConfigService) GetBlogUrl() string {
|
||||
return schema + this.GetBlogDomain();
|
||||
return this.GetBlogDomain()
|
||||
}
|
||||
|
||||
// lea
|
||||
func (this *ConfigService) GetLeaDomain() string {
|
||||
subDomain := this.GetGlobalStringConfig("leaSubDomain");
|
||||
if subDomain != "" {
|
||||
return subDomain + port
|
||||
}
|
||||
return this.GetDefaultDomain() + "/lea"
|
||||
return "/lea"
|
||||
}
|
||||
func (this *ConfigService) GetLeaUrl() string {
|
||||
return schema + this.GetLeaDomain();
|
||||
return schema + this.GetLeaDomain()
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetUserUrl(domain string) string {
|
||||
@@ -529,6 +545,7 @@ func (this *ConfigService) GetUserSubUrl(subDomain string) string {
|
||||
func (this *ConfigService) AllowCustomDomain() bool {
|
||||
return configService.GetGlobalStringConfig("allowCustomDomain") != ""
|
||||
}
|
||||
|
||||
// 是否是好的自定义域名
|
||||
func (this *ConfigService) IsGoodCustomDomain(domain string) bool {
|
||||
blacks := this.GetGlobalArrayConfig("blackCustomDomains")
|
||||
@@ -553,20 +570,29 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
|
||||
// 上传大小
|
||||
func (this *ConfigService) GetUploadSize(key string) float64 {
|
||||
f, _ := strconv.ParseFloat(this.GetGlobalStringConfig(key), 64)
|
||||
return f;
|
||||
return f
|
||||
}
|
||||
func (this *ConfigService) GetInt64(key string) int64 {
|
||||
f, _ := strconv.ParseInt(this.GetGlobalStringConfig(key), 10, 64)
|
||||
return f
|
||||
}
|
||||
func (this *ConfigService) GetInt32(key string) int32 {
|
||||
f, _ := strconv.ParseInt(this.GetGlobalStringConfig(key), 10, 32)
|
||||
return int32(f)
|
||||
}
|
||||
func (this *ConfigService) GetUploadSizeLimit() map[string]float64 {
|
||||
return map[string]float64{
|
||||
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
|
||||
"uploadBlogLogoSize":this.GetUploadSize("uploadBlogLogoSize"),
|
||||
"uploadAttachSize":this.GetUploadSize("uploadAttachSize"),
|
||||
"uploadAvatarSize":this.GetUploadSize("uploadAvatarSize"),
|
||||
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
|
||||
"uploadBlogLogoSize": this.GetUploadSize("uploadBlogLogoSize"),
|
||||
"uploadAttachSize": this.GetUploadSize("uploadAttachSize"),
|
||||
"uploadAvatarSize": this.GetUploadSize("uploadAvatarSize"),
|
||||
}
|
||||
}
|
||||
|
||||
// 为用户得到全局的配置
|
||||
// NoteController调用
|
||||
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
|
||||
uploadSizeConfigs := this.GetUploadSizeLimit();
|
||||
uploadSizeConfigs := this.GetUploadSizeLimit()
|
||||
config := map[string]interface{}{}
|
||||
for k, v := range uploadSizeConfigs {
|
||||
config[k] = v
|
||||
@@ -580,5 +606,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetVersion() string {
|
||||
return "1.0-beta.4"
|
||||
return "2.3"
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"strings"
|
||||
"html/template"
|
||||
"net/smtp"
|
||||
"strconv"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 发送邮件
|
||||
@@ -20,7 +22,7 @@ type EmailService struct {
|
||||
tpls map[string]*template.Template
|
||||
}
|
||||
|
||||
func NewEmailService() (*EmailService) {
|
||||
func NewEmailService() *EmailService {
|
||||
return &EmailService{tpls: map[string]*template.Template{}}
|
||||
}
|
||||
|
||||
@@ -29,42 +31,111 @@ var host = ""
|
||||
var emailPort = ""
|
||||
var username = ""
|
||||
var password = ""
|
||||
var ssl = false
|
||||
|
||||
func InitEmailFromDb() {
|
||||
host = configService.GetGlobalStringConfig("emailHost")
|
||||
emailPort = configService.GetGlobalStringConfig("emailPort")
|
||||
username = configService.GetGlobalStringConfig("emailUsername")
|
||||
password = configService.GetGlobalStringConfig("emailPassword")
|
||||
if configService.GetGlobalStringConfig("emailSSL") == "1" {
|
||||
ssl = true
|
||||
}
|
||||
}
|
||||
|
||||
//return a smtp client
|
||||
func dial(addr string) (*smtp.Client, error) {
|
||||
conn, err := tls.Dial("tcp", addr, nil)
|
||||
if err != nil {
|
||||
LogW("Dialing Error:", err)
|
||||
return nil, err
|
||||
}
|
||||
//分解主机端口字符串
|
||||
host, _, _ := net.SplitHostPort(addr)
|
||||
return smtp.NewClient(conn, host)
|
||||
}
|
||||
|
||||
func SendEmailWithSSL (auth smtp.Auth, to []string, msg []byte) (err error) {
|
||||
//create smtp client
|
||||
c, err := dial(host + ":" + emailPort)
|
||||
if err != nil {
|
||||
LogW("Create smpt client error:", err)
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if auth != nil {
|
||||
if ok, _ := c.Extension("AUTH"); ok {
|
||||
if err = c.Auth(auth); err != nil {
|
||||
LogW("Error during AUTH", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = c.Mail(username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, addr := range to {
|
||||
if err = c.Rcpt(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w, err := c.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Quit()
|
||||
}
|
||||
|
||||
func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string) {
|
||||
InitEmailFromDb()
|
||||
|
||||
|
||||
if host == "" || emailPort == "" || username == "" || password == "" {
|
||||
return
|
||||
return
|
||||
}
|
||||
hp := strings.Split(host, ":")
|
||||
auth := smtp.PlainAuth("", username, password, hp[0])
|
||||
|
||||
|
||||
var content_type string
|
||||
|
||||
|
||||
mailtype := "html"
|
||||
if mailtype == "html" {
|
||||
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
|
||||
} else{
|
||||
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
|
||||
} else {
|
||||
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
||||
}
|
||||
|
||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||
|
||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||
send_to := strings.Split(to, ";")
|
||||
err := smtp.SendMail(host+":"+emailPort, auth, username, send_to, msg)
|
||||
|
||||
|
||||
var err error
|
||||
if ssl {
|
||||
err = SendEmailWithSSL(auth, send_to, msg)
|
||||
} else {
|
||||
Log("no ssl")
|
||||
err = smtp.SendMail(host + ":" + emailPort, auth, username, send_to, msg)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
e = fmt.Sprint(err)
|
||||
return
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
// AddUser调用
|
||||
@@ -74,20 +145,20 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
|
||||
if token == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateRegister");
|
||||
|
||||
if(tpl == "") {
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject")
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateRegister")
|
||||
|
||||
if tpl == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
"user": map[string]interface{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
"username": userInfo.Username,
|
||||
},
|
||||
}
|
||||
@@ -97,7 +168,7 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// 发送邮件
|
||||
ok, _ = this.SendEmail(email, subject, tpl)
|
||||
return ok
|
||||
@@ -113,66 +184,66 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
|
||||
}
|
||||
|
||||
token := tokenService.NewToken(userInfo.UserId.Hex(), email, info.TokenUpdateEmail)
|
||||
|
||||
|
||||
if token == "" {
|
||||
return
|
||||
}
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
|
||||
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject")
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail")
|
||||
|
||||
// 发送邮件
|
||||
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
"newEmail": email,
|
||||
"user": map[string]interface{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
"username": userInfo.Username,
|
||||
},
|
||||
}
|
||||
|
||||
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||
if !ok {
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 发送邮件
|
||||
ok, msg = this.SendEmail(email, subject, tpl)
|
||||
return
|
||||
}
|
||||
|
||||
func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) {
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject")
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword")
|
||||
|
||||
// 发送邮件
|
||||
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
|
||||
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
||||
|
||||
|
||||
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||
if !ok {
|
||||
return
|
||||
return
|
||||
}
|
||||
// 发送邮件
|
||||
ok, msg = this.SendEmail(email, subject, tpl)
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
// 发送邀请链接
|
||||
func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool {
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject")
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateInvite")
|
||||
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
|
||||
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
|
||||
"content": content,
|
||||
"content": content,
|
||||
"user": map[string]interface{}{
|
||||
"username": userInfo.Username,
|
||||
"email": userInfo.Email,
|
||||
"email": userInfo.Email,
|
||||
},
|
||||
}
|
||||
var ok bool
|
||||
@@ -187,32 +258,32 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str
|
||||
|
||||
// 发送评论
|
||||
func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComment, userId, content string) bool {
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateComment");
|
||||
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject")
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateComment")
|
||||
|
||||
// title := "评论提醒"
|
||||
|
||||
|
||||
/*
|
||||
toUserId := note.UserId.Hex()
|
||||
// title := "评论提醒"
|
||||
|
||||
// 表示回复回复的内容, 那么发送给之前回复的
|
||||
if comment.CommentId != "" {
|
||||
toUserId = comment.UserId.Hex()
|
||||
}
|
||||
toUserInfo := userService.GetUserInfo(toUserId)
|
||||
sendUserInfo := userService.GetUserInfo(userId)
|
||||
|
||||
subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
|
||||
if comment.CommentId != "" {
|
||||
subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
|
||||
if userId == note.UserId.Hex() {
|
||||
subject += "(作者)";
|
||||
toUserId := note.UserId.Hex()
|
||||
// title := "评论提醒"
|
||||
|
||||
// 表示回复回复的内容, 那么发送给之前回复的
|
||||
if comment.CommentId != "" {
|
||||
toUserId = comment.UserId.Hex()
|
||||
}
|
||||
toUserInfo := userService.GetUserInfo(toUserId)
|
||||
sendUserInfo := userService.GetUserInfo(userId)
|
||||
|
||||
subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
|
||||
if comment.CommentId != "" {
|
||||
subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
|
||||
if userId == note.UserId.Hex() {
|
||||
subject += "(作者)";
|
||||
}
|
||||
subject += " 的评论";
|
||||
}
|
||||
subject += " 的评论";
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
toUserId := note.UserId.Hex()
|
||||
// 表示回复回复的内容, 那么发送给之前回复的
|
||||
if comment.CommentId != "" {
|
||||
@@ -220,28 +291,28 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
|
||||
}
|
||||
toUserInfo := userService.GetUserInfo(toUserId) // 被评论者
|
||||
sendUserInfo := userService.GetUserInfo(userId) // 评论者
|
||||
|
||||
// {siteUrl} {blogUrl}
|
||||
|
||||
// {siteUrl} {blogUrl}
|
||||
// {blog.id} {blog.title} {blog.url}
|
||||
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
||||
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
||||
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(),
|
||||
"blog": map[string]string{
|
||||
"id": note.NoteId.Hex(),
|
||||
"id": note.NoteId.Hex(),
|
||||
"title": note.Title,
|
||||
"url": configService.GetBlogUrl() + "/view/" + note.NoteId.Hex(),
|
||||
"url": configService.GetBlogUrl() + "/view/" + note.NoteId.Hex(),
|
||||
},
|
||||
"commentContent": content,
|
||||
// 评论者信息
|
||||
"commentUser": map[string]interface{}{"userId": sendUserInfo.UserId.Hex(),
|
||||
"username": sendUserInfo.Username,
|
||||
"email": sendUserInfo.Email,
|
||||
"commentUser": map[string]interface{}{"userId": sendUserInfo.UserId.Hex(),
|
||||
"username": sendUserInfo.Username,
|
||||
"email": sendUserInfo.Email,
|
||||
"isBlogAuthor": userId == note.UserId.Hex(),
|
||||
},
|
||||
// 被评论者信息
|
||||
"commentedUser": map[string]interface{}{"userId": toUserId,
|
||||
"username": toUserInfo.Username,
|
||||
"email": toUserInfo.Email,
|
||||
"username": toUserInfo.Username,
|
||||
"email": toUserInfo.Email,
|
||||
"isBlogAuthor": toUserId == note.UserId.Hex(),
|
||||
},
|
||||
}
|
||||
@@ -251,53 +322,52 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// 发送邮件
|
||||
ok, _ = this.SendEmail(toUserInfo.Email, subject, tpl)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
// 验证模板是否正确
|
||||
func (this *EmailService) ValidTpl(str string) (ok bool, msg string){
|
||||
defer func() {
|
||||
func (this *EmailService) ValidTpl(str string) (ok bool, msg string) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
msg = fmt.Sprint(err)
|
||||
}
|
||||
}();
|
||||
header := configService.GetGlobalStringConfig("emailTemplateHeader");
|
||||
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
|
||||
}()
|
||||
header := configService.GetGlobalStringConfig("emailTemplateHeader")
|
||||
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
|
||||
str = strings.Replace(str, "{{header}}", header, -1)
|
||||
str = strings.Replace(str, "{{footer}}", footer, -1)
|
||||
_, err := template.New("tpl name").Parse(str)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
msg = fmt.Sprint(err)
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// ok, msg, subject, tpl
|
||||
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template){
|
||||
defer func() {
|
||||
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
msg = fmt.Sprint(err)
|
||||
}
|
||||
}();
|
||||
|
||||
}()
|
||||
|
||||
var err error
|
||||
var has bool
|
||||
|
||||
|
||||
if tpl, has = this.tpls[str]; !has {
|
||||
tpl, err = template.New("tpl name").Parse(str)
|
||||
if err != nil {
|
||||
tpl, err = template.New("tpl name").Parse(str)
|
||||
if err != nil {
|
||||
msg = fmt.Sprint(err)
|
||||
return
|
||||
}
|
||||
this.tpls[str] = tpl
|
||||
return
|
||||
}
|
||||
this.tpls[str] = tpl
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
@@ -310,67 +380,67 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
|
||||
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容,
|
||||
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容,
|
||||
}
|
||||
}();
|
||||
|
||||
}()
|
||||
|
||||
var tpl *template.Template
|
||||
|
||||
values["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
|
||||
values["siteUrl"] = configService.GetSiteUrl()
|
||||
|
||||
// subject
|
||||
if subject != "" {
|
||||
ok, msg, tpl = this.getTpl(subject)
|
||||
if(!ok) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
err := tpl.Execute(&buffer, values)
|
||||
if err != nil {
|
||||
err := tpl.Execute(&buffer, values)
|
||||
if err != nil {
|
||||
msg = fmt.Sprint(err)
|
||||
return
|
||||
}
|
||||
o = buffer.String()
|
||||
} else {
|
||||
o = ""
|
||||
}
|
||||
|
||||
// content
|
||||
header := configService.GetGlobalStringConfig("emailTemplateHeader");
|
||||
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
|
||||
}
|
||||
o = buffer.String()
|
||||
} else {
|
||||
o = ""
|
||||
}
|
||||
|
||||
// content
|
||||
header := configService.GetGlobalStringConfig("emailTemplateHeader")
|
||||
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
|
||||
body = strings.Replace(body, "{{header}}", header, -1)
|
||||
body = strings.Replace(body, "{{footer}}", footer, -1)
|
||||
values["subject"] = o
|
||||
ok, msg, tpl = this.getTpl(body)
|
||||
if(!ok) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var buffer2 bytes.Buffer
|
||||
err := tpl.Execute(&buffer2, values)
|
||||
if err != nil {
|
||||
err := tpl.Execute(&buffer2, values)
|
||||
if err != nil {
|
||||
msg = fmt.Sprint(err)
|
||||
return
|
||||
}
|
||||
b = buffer2.String()
|
||||
|
||||
return
|
||||
}
|
||||
b = buffer2.String()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 发送email给用户
|
||||
// 需要记录
|
||||
func (this *EmailService) SendEmailToUsers(users []info.User, subject, body string) (ok bool, msg string) {
|
||||
if(users == nil || len(users) == 0) {
|
||||
if users == nil || len(users) == 0 {
|
||||
msg = "no users"
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 尝试renderHtml
|
||||
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
|
||||
if(!ok) {
|
||||
if !ok {
|
||||
Log(msg)
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
go func() {
|
||||
for _, user := range users {
|
||||
LogJ(user)
|
||||
@@ -381,8 +451,8 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
|
||||
ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m)
|
||||
ok = ok2
|
||||
msg = msg2
|
||||
if(ok2) {
|
||||
sendOk, msg := this.SendEmail(user.Email, subject2, body2);
|
||||
if ok2 {
|
||||
sendOk, msg := this.SendEmail(user.Email, subject2, body2)
|
||||
this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下
|
||||
// 记录到Email Log
|
||||
if sendOk {
|
||||
@@ -395,47 +465,47 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (this *EmailService) SendEmailToEmails(emails []string, subject, body string) (ok bool, msg string) {
|
||||
if(emails == nil || len(emails) == 0) {
|
||||
if emails == nil || len(emails) == 0 {
|
||||
msg = "no emails"
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 尝试renderHtml
|
||||
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
|
||||
if(!ok) {
|
||||
if !ok {
|
||||
Log(msg)
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
// go func() {
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue
|
||||
}
|
||||
m := map[string]interface{}{}
|
||||
m["email"] = email
|
||||
ok, msg, subject, body = this.renderEmail(subject, body, m)
|
||||
if(ok) {
|
||||
sendOk, msg := this.SendEmail(email, subject, body);
|
||||
this.AddEmailLog(email, subject, body, sendOk, msg)
|
||||
// 记录到Email Log
|
||||
if sendOk {
|
||||
Log("ok " + email)
|
||||
} else {
|
||||
Log("no " + email)
|
||||
}
|
||||
} else {
|
||||
Log(msg);
|
||||
}
|
||||
|
||||
// go func() {
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue
|
||||
}
|
||||
// }()
|
||||
|
||||
return
|
||||
m := map[string]interface{}{}
|
||||
m["email"] = email
|
||||
ok, msg, subject, body = this.renderEmail(subject, body, m)
|
||||
if ok {
|
||||
sendOk, msg := this.SendEmail(email, subject, body)
|
||||
this.AddEmailLog(email, subject, body, sendOk, msg)
|
||||
// 记录到Email Log
|
||||
if sendOk {
|
||||
Log("ok " + email)
|
||||
} else {
|
||||
Log("no " + email)
|
||||
}
|
||||
} else {
|
||||
Log(msg)
|
||||
}
|
||||
}
|
||||
// }()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 添加邮件日志
|
||||
@@ -443,6 +513,7 @@ func (this *EmailService) AddEmailLog(email, subject, body string, ok bool, msg
|
||||
log := info.EmailLog{LogId: bson.NewObjectId(), Email: email, Subject: subject, Body: body, Ok: ok, Msg: msg, CreatedTime: time.Now()}
|
||||
db.Insert(db.EmailLogs, log)
|
||||
}
|
||||
|
||||
// 展示邮件日志
|
||||
|
||||
func (this *EmailService) DeleteEmails(ids []string) bool {
|
||||
@@ -451,7 +522,7 @@ func (this *EmailService) DeleteEmails(ids []string) bool {
|
||||
idsO[i] = bson.ObjectIdHex(id)
|
||||
}
|
||||
db.DeleteAll(db.EmailLogs, bson.M{"_id": bson.M{"$in": idsO}})
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField string, isAsc bool, email string) (page info.Page, emailLogs []info.EmailLog) {
|
||||
@@ -461,7 +532,7 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
|
||||
if email != "" {
|
||||
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
|
||||
}
|
||||
q := db.EmailLogs.Find(query);
|
||||
q := db.EmailLogs.Find(query)
|
||||
// 总记录数
|
||||
count, _ := q.Count()
|
||||
// 列表
|
||||
@@ -471,4 +542,4 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
|
||||
All(&emailLogs)
|
||||
page = info.NewPage(pageNumber, pageSize, count, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||
@@ -26,7 +30,7 @@ func (this *FileService) AddImage(image info.File, albumId, userId string, needC
|
||||
image.IsDefaultAlbum = true
|
||||
}
|
||||
image.UserId = bson.ObjectIdHex(userId)
|
||||
|
||||
|
||||
ok = db.Insert(db.Files, image)
|
||||
return
|
||||
}
|
||||
@@ -36,28 +40,28 @@ func (this *FileService) AddImage(image info.File, albumId, userId string, needC
|
||||
func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNumber, pageSize int) info.Page {
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
|
||||
files := []info.File{}
|
||||
|
||||
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
|
||||
if albumId != "" {
|
||||
q["AlbumId"] = bson.ObjectIdHex(albumId);
|
||||
q["AlbumId"] = bson.ObjectIdHex(albumId)
|
||||
} else {
|
||||
q["IsDefaultAlbum"] = true
|
||||
}
|
||||
if key != "" {
|
||||
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
|
||||
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
|
||||
}
|
||||
|
||||
// LogJ(q)
|
||||
|
||||
count := db.Count(db.Files, q);
|
||||
|
||||
|
||||
// LogJ(q)
|
||||
|
||||
count := db.Count(db.Files, q)
|
||||
|
||||
db.Files.
|
||||
Find(q).
|
||||
Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(&files)
|
||||
|
||||
|
||||
return info.Page{Count: count, List: files}
|
||||
}
|
||||
|
||||
@@ -71,12 +75,12 @@ func (this *FileService) GetAllImageNamesMap(userId string) (m map[string]bool)
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
||||
files := []info.File{}
|
||||
db.ListByQWithFields(db.Files, q, []string{"Name"}, &files)
|
||||
|
||||
|
||||
m = make(map[string]bool)
|
||||
if len(files) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
for _, file := range files {
|
||||
m[file.Name] = true
|
||||
}
|
||||
@@ -87,8 +91,8 @@ func (this *FileService) GetAllImageNamesMap(userId string) (m map[string]bool)
|
||||
func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
|
||||
file := info.File{}
|
||||
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
|
||||
|
||||
if(file.FileId != "") {
|
||||
|
||||
if file.FileId != "" {
|
||||
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
|
||||
// delete image
|
||||
// TODO
|
||||
@@ -115,6 +119,53 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
||||
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的访问权限
|
||||
@@ -122,63 +173,63 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
if fileId == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
file := info.File{}
|
||||
db.Get(db.Files, fileId, &file)
|
||||
path := file.Path
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// 1. 判断权限
|
||||
|
||||
|
||||
// 是否是我的文件
|
||||
if userId != "" && file.UserId.Hex() == userId {
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
// 得到使用过该fileId的所有笔记NoteId
|
||||
// 这些笔记是否有public的, 若有则ok
|
||||
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||
|
||||
|
||||
noteIds := noteImageService.GetNoteIds(fileId)
|
||||
if noteIds != nil && len(noteIds) > 0 {
|
||||
// 这些笔记是否有public的
|
||||
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
||||
for _, noteId := range noteIds {
|
||||
note := noteService.GetNoteById(noteId.Hex())
|
||||
if shareService.HasReadPerm(note.UserId.Hex(), userId, noteId.Hex()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// 若有共享给我的笔记?
|
||||
// 对该笔记可读?
|
||||
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
|
||||
return path
|
||||
}
|
||||
|
||||
// 笔记本是否共享给我?
|
||||
// 通过笔记得到笔记本
|
||||
notes := []info.Note{}
|
||||
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, ¬es)
|
||||
if notes != nil && len(notes) > 0 {
|
||||
notebookIds := make([]bson.ObjectId, len(notes))
|
||||
for i := 0; i < len(notes); i++ {
|
||||
notebookIds[i] = notes[i].NotebookId
|
||||
}
|
||||
|
||||
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
/*
|
||||
// 若有共享给我的笔记?
|
||||
// 对该笔记可读?
|
||||
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
|
||||
return path
|
||||
}
|
||||
|
||||
// 笔记本是否共享给我?
|
||||
// 通过笔记得到笔记本
|
||||
notes := []info.Note{}
|
||||
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, ¬es)
|
||||
if notes != nil && len(notes) > 0 {
|
||||
notebookIds := make([]bson.ObjectId, len(notes))
|
||||
for i := 0; i < len(notes); i++ {
|
||||
notebookIds[i] = notes[i].NotebookId
|
||||
}
|
||||
|
||||
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
|
||||
if file.FromFileId != "" {
|
||||
fromFile := info.File{}
|
||||
@@ -187,54 +238,56 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
return fromFile.Path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// 复制共享的笔记时, 复制其中的图片到我本地
|
||||
// 复制图片
|
||||
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
||||
// 是否已经复制过了
|
||||
file2 := info.File{}
|
||||
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
|
||||
if file2.FileId != "" {
|
||||
return true, file2.FileId.Hex();
|
||||
return true, file2.FileId.Hex()
|
||||
}
|
||||
|
||||
// 复制之
|
||||
|
||||
file := info.File{}
|
||||
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
|
||||
|
||||
|
||||
if file.FileId == "" || file.UserId.Hex() != userId {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
|
||||
_, ext := SplitFilename(file.Name)
|
||||
newFilename := NewGuid() + ext
|
||||
|
||||
dir := "files/" + toUserId + "/images"
|
||||
guid := NewGuid()
|
||||
newFilename := guid + ext
|
||||
|
||||
// TODO 统一目录格式
|
||||
// dir := "files/" + toUserId + "/images"
|
||||
dir := "files/" + GetRandomFilePath(toUserId, guid) + "/images"
|
||||
filePath := dir + "/" + newFilename
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
err := os.MkdirAll(revel.BasePath+dir, 0755)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
|
||||
|
||||
_, err = CopyFile(revel.BasePath+"/"+file.Path, revel.BasePath+"/"+filePath)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return false, ""
|
||||
}
|
||||
|
||||
|
||||
fileInfo := info.File{Name: newFilename,
|
||||
Title: file.Title,
|
||||
Path: filePath,
|
||||
Size: file.Size,
|
||||
Title: file.Title,
|
||||
Path: filePath,
|
||||
Size: file.Size,
|
||||
FromFileId: file.FileId}
|
||||
id := bson.NewObjectId();
|
||||
id := bson.NewObjectId()
|
||||
fileInfo.FileId = id
|
||||
fileId = id.Hex()
|
||||
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
|
||||
|
||||
|
||||
if Ok {
|
||||
return Ok, id.Hex()
|
||||
}
|
||||
@@ -245,7 +298,7 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
|
||||
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
||||
// 如果有问题会panic
|
||||
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
// "strings"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
// 用户组, 用户组用户管理
|
||||
@@ -16,37 +16,53 @@ type GroupService struct {
|
||||
|
||||
// 添加分组
|
||||
func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
|
||||
group := info.Group {
|
||||
GroupId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Title: title,
|
||||
group := info.Group{
|
||||
GroupId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Title: title,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.Groups, group), group
|
||||
}
|
||||
|
||||
// 删除分组
|
||||
// 判断是否有好友
|
||||
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
|
||||
/*
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
|
||||
return false, "groupHasUsers"
|
||||
}
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
|
||||
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)})
|
||||
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
||||
|
||||
|
||||
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
||||
}
|
||||
|
||||
// 修改group标题
|
||||
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
||||
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
||||
}
|
||||
|
||||
// 得到用户的所有分组(包括下的所有用户)
|
||||
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||
// 得到分组s
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||
func (this *GroupService) GetGroupsAndUsers(userId string) []info.Group {
|
||||
/*
|
||||
// 得到我的分组
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||
*/
|
||||
// 我的分组, 及我所属的分组
|
||||
groups := this.GetGroupsContainOf(userId)
|
||||
|
||||
// 得到其下的用户
|
||||
for i, group := range groups {
|
||||
group.Users = this.GetUsers(group.GroupId.Hex())
|
||||
@@ -54,41 +70,65 @@ func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
// 仅仅得到所有分组
|
||||
func (this *GroupService) GetGroups(userId string) ([]info.Group) {
|
||||
func (this *GroupService) GetGroups(userId string) []info.Group {
|
||||
// 得到分组s
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
// 得到我的和我所属组的ids
|
||||
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) []bson.ObjectId {
|
||||
// 所属组
|
||||
groupIds := this.GetBelongToGroupIds(userId)
|
||||
|
||||
// 获取包含此用户的组对象数组
|
||||
func (this *GroupService) GetGroupsContainOf(userId string) []info.Group {
|
||||
groupIds := this.GetGroupIdsContainOf(userId)
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"_id": bson.M{"$in": groupIds}}, &groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
// 获取包含此用户的组Id数组
|
||||
func (this *GroupService) GetGroupIdsContainOf(userId string) []bson.ObjectId {
|
||||
groupUsers := []info.GroupUser{}
|
||||
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
|
||||
if len(groupUsers) == 0 {
|
||||
return nil
|
||||
m := map[bson.ObjectId]bool{}
|
||||
for _, groupId := range groupIds {
|
||||
m[groupId] = true
|
||||
}
|
||||
|
||||
groupIds := make([]bson.ObjectId, len(groupUsers))
|
||||
for i, each := range groupUsers {
|
||||
groupIds[i] = each.GroupId
|
||||
// 我的组
|
||||
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用
|
||||
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||
func (this *GroupService) GetGroup(userId, groupId string) info.Group {
|
||||
// 得到分组s
|
||||
group := info.Group{}
|
||||
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
|
||||
@@ -96,7 +136,7 @@ func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||
}
|
||||
|
||||
// 得到某分组下的用户
|
||||
func (this *GroupService) GetUsers(groupId string) ([]info.User) {
|
||||
func (this *GroupService) GetUsers(groupId string) []info.User {
|
||||
// 得到UserIds
|
||||
groupUsers := []info.GroupUser{}
|
||||
db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers)
|
||||
@@ -112,7 +152,7 @@ func (this *GroupService) GetUsers(groupId string) ([]info.User) {
|
||||
}
|
||||
|
||||
// 得到我所属的所有分组ids
|
||||
func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
||||
func (this *GroupService) GetBelongToGroupIds(userId string) []bson.ObjectId {
|
||||
// 得到UserIds
|
||||
groupUsers := []info.GroupUser{}
|
||||
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
|
||||
@@ -128,37 +168,58 @@ func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
||||
|
||||
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
||||
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
||||
}
|
||||
// 为group添加用户
|
||||
// 用户是否已存在?
|
||||
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbidden"
|
||||
}
|
||||
|
||||
// 是否已存在
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||
return false, "hasUsers"
|
||||
}
|
||||
|
||||
return db.Insert(db.GroupUsers, info.GroupUser{
|
||||
GroupUserId: bson.NewObjectId(),
|
||||
GroupId: bson.ObjectIdHex(groupId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
CreatedTime: time.Now(),
|
||||
}), ""
|
||||
}
|
||||
// 删除用户
|
||||
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbidden"
|
||||
}
|
||||
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||
}
|
||||
|
||||
// 判断组中是否包含指定用户
|
||||
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添加用户
|
||||
// 用户是否已存在?
|
||||
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
/*
|
||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
||||
return false, "forbiddenNotMyGroup"
|
||||
}
|
||||
*/
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbiddenNotMyGroup"
|
||||
}
|
||||
|
||||
// 是否已存在
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||
return false, "userExistsInGroup"
|
||||
}
|
||||
|
||||
return db.Insert(db.GroupUsers, info.GroupUser{
|
||||
GroupUserId: bson.NewObjectId(),
|
||||
GroupId: bson.ObjectIdHex(groupId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
CreatedTime: time.Now(),
|
||||
}), ""
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
/*
|
||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
||||
return false, "forbiddenNotMyGroup"
|
||||
}
|
||||
*/
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbiddenNotMyGroup"
|
||||
}
|
||||
|
||||
// 删除该用户分享到本组的笔记本, 笔记
|
||||
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId)
|
||||
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId)
|
||||
|
||||
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
// "time"
|
||||
)
|
||||
|
||||
// 历史记录
|
||||
@@ -22,7 +22,7 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
|
||||
if eachHistory.Content == "" {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 先查是否存在历史记录, 没有则添加之
|
||||
history := info.NoteContentHistory{}
|
||||
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &history)
|
||||
@@ -38,8 +38,8 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
|
||||
}
|
||||
newHistory := []info.EachHistory{eachHistory}
|
||||
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
|
||||
history.Histories = newHistory
|
||||
|
||||
history.Histories = newHistory
|
||||
|
||||
// 更新之
|
||||
db.UpdateByIdAndUserId(db.NoteContentHistories, noteId, userId, history)
|
||||
}
|
||||
@@ -48,13 +48,13 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
|
||||
|
||||
// 新建历史
|
||||
func (this *NoteContentHistoryService) newHistory(noteId, userId string, eachHistory info.EachHistory) {
|
||||
history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Histories: []info.EachHistory{eachHistory},
|
||||
}
|
||||
|
||||
|
||||
// 保存之
|
||||
db.Insert(db.NoteContentHistories, history)
|
||||
db.Insert(db.NoteContentHistories, history)
|
||||
}
|
||||
|
||||
// 列表展示
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"regexp"
|
||||
// "time"
|
||||
// "time"
|
||||
)
|
||||
|
||||
type NoteImageService struct {
|
||||
}
|
||||
|
||||
// 通过id, userId得到noteIds
|
||||
func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
||||
func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId {
|
||||
noteImages := []info.NoteImage{}
|
||||
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, ¬eImages)
|
||||
|
||||
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, ¬eImages)
|
||||
|
||||
if noteImages != nil && len(noteImages) > 0 {
|
||||
noteIds := make([]bson.ObjectId, len(noteImages))
|
||||
cnt := len(noteImages)
|
||||
@@ -25,7 +25,7 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
||||
}
|
||||
return noteIds
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -67,23 +67,19 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
|
||||
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
|
||||
/* 弃用之
|
||||
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
|
||||
noteImages := []info.NoteImage{}
|
||||
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, ¬eImages)
|
||||
|
||||
if len(noteImages) == 0 {
|
||||
return content;
|
||||
}
|
||||
|
||||
// <img src="/file/outputImage?fileId=12323232" />
|
||||
// 把fileId=1232替换成新的
|
||||
replaceMap := map[string]string{}
|
||||
for _, noteImage := range noteImages {
|
||||
imageId := noteImage.ImageId.Hex()
|
||||
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
|
||||
@@ -91,37 +87,61 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
|
||||
replaceMap[imageId] = newImageId
|
||||
}
|
||||
}
|
||||
|
||||
if len(replaceMap) > 0 {
|
||||
// 替换之
|
||||
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||
content = reg.ReplaceAllStringFunc(content, func(each string) string {
|
||||
// each=outputImage?fileId=541bd2f599c37b4f3r000003
|
||||
fileId := each[len(each)-24:] // 得到后24位, 也即id
|
||||
if replaceFileId, ok := replaceMap[fileId]; ok {
|
||||
*/
|
||||
|
||||
// 因为很多图片上传就会删除, 所以直接从内容中查看图片id进行复制
|
||||
|
||||
// <img src="/file/outputImage?fileId=12323232" />
|
||||
// 把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 {
|
||||
// each = outputImage?fileId=541bd2f599c37b4f3r000003
|
||||
// each = getImage?fileId=541bd2f599c37b4f3r000003
|
||||
|
||||
fileId := each[len(each)-24:] // 得到后24位, 也即id
|
||||
|
||||
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 each
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
return "getImage?fileId=" + replaceFileId
|
||||
}
|
||||
return each
|
||||
})
|
||||
|
||||
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 {
|
||||
@@ -130,11 +150,11 @@ func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[st
|
||||
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 {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user