Compare commits

..
1 Commits
Author SHA1 Message Date
life c26d25deab api init 2014-10-25 01:09:37 +08:00
3025 changed files with 181205 additions and 290064 deletions

No files matched your search

+4 -3
View File
@@ -2,12 +2,14 @@
pkg pkg
bin2 bin2
bin/i18n bin/i18n
bin/leanote* bin/leanote-linux
bin/leanote-mac
bin/release bin/release
bin/test.sh
bin/tmp bin/tmp
bin/test bin/test
bin/src bin/src
conf/app.conf
conf/routes
public/upload public/upload
app/routes/routes.go app/routes/routes.go
app/tmp/main.go app/tmp/main.go
@@ -16,4 +18,3 @@ app/tmp/main.go
.project .project
public/config.codekit public/config.codekit
files files
/node_modules
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>leanote-public</name> <name>leanote2</name>
<comment>leanote, your own cloud note!</comment> <comment>leanote, your own cloud note!</comment>
<projects> <projects>
</projects> </projects>
-35
View File
@@ -1,35 +0,0 @@
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
View File
@@ -1,409 +0,0 @@
var gulp = require('gulp');
var clean = require('gulp-clean');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var minifyHtml = require("gulp-minify-html");
var concat = require('gulp-concat');
var replace = require('gulp-replace');
var inject = require('gulp-inject');
var gulpSequence = require('gulp-sequence');
var fs = require('fs');
var leanoteBase = './';
var base = leanoteBase + '/public'; // public base
var noteDev = leanoteBase + '/app/views/note/note-dev.html';
var noteProBase = leanoteBase + '/app/views/note';
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']);
+3 -3
View File
@@ -1,6 +1,6 @@
LEANOTE - NOT JUST A NOTEPAD! leanote - you own cloud note!
Copyright 2014-2015 by the contributors Copyright 2014 by the contributors
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
Leanote is licensed under the GPL v2. leanote is licensed under the GPL v2.
life(life@leanote.com, lifephp@gmail.com) life(life@leanote.com, lifephp@gmail.com)
+141 -136
View File
@@ -1,189 +1,194 @@
# Leanote [中文](https://github.com/leanote/leanote#1-介绍)
[![Build Status](https://travis-ci.org/leanote/leanote.svg)](https://travis-ci.org/leanote/leanote)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## 1. Introduction ## 1. Introduction
Leanote, not just a notepad! Leanote, note just a notebook!
![leanote.png](leanote.png "")
**Highlighted Features** **Some Features**
* 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: Manage your knowledge in leanote. leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
* Knowledge management: The flexible and versatile notebook-note-tagging system of Leanote makes it an ideal tool for knowledge management. * 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.
* Sharing: Share your knowledge, thoughts and experiences with friends via Leanote. Invite your friends to join your notepad in the cloud. * Cooperation: Collaborate with friends to improve your skills.
* Cooperating: Collaborate with colleagues to improve skills, fertilize ideas and brainstorm on the fly. * Blog: Publish your knowledge and make leanote your blog.
* Blogging: Publish your work and make Leanote your personal blog.
**Other Features** ## 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:
* Markdown syntax support * 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
* Distraction-free writing mode * We like markdown, but Evernote does not support it.
* `Vim` and `Emacs` editing mode * 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!
* 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 get Leanote ## 3. How to install leanote
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-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.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
More information about how to install Leanote please see: ### 3.2. Install MongoDB
* Leanote binary installation tutorial: Leanote is written in go using [revel](https://revel.github.io/) and [MongoDB](https://www.mongodb.org). Thus, you need to first install MongoDB.
* [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))
## 4. Documentation For more tips please have a look at [our wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
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. ### 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)
## 5. How to develop Leanote ## 5. Contributors
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
this project. Your help is much appreciated.
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). ## 6. Contributing
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
## 6. Contributions ## Discussion
* [leanote bbs](http://bbs.leanote.com)
Like or dislike Leanote, please leave your comments and suggestions to help us improve it. * [leanote google group](https://groups.google.com/forum/#!forum/leanote)
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. * QQ Group: 158716820
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
----------------------------------------------------------------------- -----------------------------------------------------------------------
# Leanote
## 1. 介绍 ## 1. 介绍
Leanote, 不只是笔记! Leanote, 不只是笔记!
**特性** **特性**
* 高效笔记:Leanote 有易操作的界面, 包含一款富文本编辑器和Markdown编辑器,让您的笔记记录更轻松和高效。对高阶用户,我们还提供`Vim` 和`Emacs` 编辑模式,助推你的写作速度更上层楼。 * 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
* 知识管理: Leanote 灵活而强大的“笔记本-笔记-标签”系统,让它成为你个人知识管理的利器。 * 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
* 分享: 你可以通过Leanote同好友分享知识、想法和经历, 邀请好友加入你的笔记簿,通过云端交流信息。 * 协作: 在分享的同时也可以与好友一起协作知识.
* 协作: Leanote协助你与同事之间相互协作,激荡新思路,随时随地头脑风暴。 * 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
* 博客: Leanote也可以作为你的个人博客, 把你的知识传播的更远!
**其它特性** ## 2. 为什么我们要创建leanote?
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
* 支持Markdown编辑 * evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
* 写作模式 * 我们是markdown的爱好者, 可是evernote竟然没有.
* `Vim` 及 `Emacs` 编辑模式 * 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
* 支持PDF导出
* 支持批量操作
* 博客自定义主题, 实现高度定制化
## 2. 为什么我们要创建Leanote?
我们都曾是`Evernote`的忠实粉丝, 一直以来`Evernote`都是我们日常知识管理的有效工具。于是我们决定重新创造一款工具,提供`Evernote`所能提供的功能,同时弥补`Evernote`的不足,比如:
* 功能更强的文本编辑器:`Evernote`的编辑器不能满足我们的需求, 不能实现文档导航、不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放等。
* `Evernote` 不支持所有人都喜爱的markdown语法,于是我们为Leanote配备了一款可以实时渲染的markdown编辑器。
* 如果你是一名开发者,觉得手指怀念`Vim` 或 `Emacs` 了,那么我们还提供给你`Vim` 和 `Emacs` 写作模式,配合*markdown*的格式编辑,写作的时候再也不用去碰鼠标了。
* 知识积累和知识分享同样重要,因此大家都有自己的笔记账号和社交账号。但为什么这两者不能合二为一呢? Leanote 做到了将二者无缝衔接。
* 一套完整的、全平台覆盖的软件套装,包括了web、桌面、安卓、IOS设备,而且全部开源!
* 还有... * 还有...
## 3. 获取Leanote ## 3.安装leanote
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
Leanote云笔记产品包括: Leanote Web & Server(即本仓库), 桌面客户端, IOS, android. 4端全部开源! 这里详细整理了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)
如果想试用我们的产品,欢迎在 https://leanote.com 上注册, Leanote团队为你提供稳定可靠的服务。 ### 3.1. 下载leanote
担心服务厂商如何处理你的个人数据吗?你可以下载Leanote安装在自己的服务器上, 通过Leanote客户端连接与自建服务同步数据。
这里详细整理了Leanote二进版和Leanote开发版的安装教程, 请移步至: Leanote V1.0-beta 已发布, 二进制文件(暂时没有windows版的):
* Leanote二进制详细安装教程: * Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
* [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) * MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
* [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. 相关文档 ### 3.2. 安装 MongodbDB
更多详细的安装说明、问题处理和配置说明文档,请查看 [wiki](https://github.com/leanote/leanote/wiki)。 Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
## 5. 如何对Leanote进行二次开发 安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
如果您有兴趣基于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)。 ### 3.3. 导入初始数据
## 6. 贡献者 MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
在此对向Leanote贡献力量的[贡献者们](https://github.com/leanote/leanote/graphs/contributors) 表示感谢。Leanote因有你们而更完美! ```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
## 7. 加入我们 初始数据包含两个用户:
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到Leanote。 ```
user2 username: admin, password: abc123 (管理员, 重要!)
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
```
有任何问题或建议, 请先搜索[issue](https://github.com/leanote/leanote/issues)区是否已经有解决方法。如果没有,欢迎提交新issue。 ### 3.4. 配置
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善Leanote。 修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
## 8. 捐赠 ``mongodb`` **必须配置!**
如果您喜欢我们的产品,请考虑支持我们, [捐赠Leanote](http://leanote.org/#donate)。 ```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
感谢[这些捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持! ``app.secret`` **重要**
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
## 9. 其它相关项目 更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
* [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), 开发阶段
欢迎加入我们! ### 3.5. 运行leanote
## 联系&加入我们 ```
* Email: leanote@leanote.com $> cd PATH_TO_LEANOTE/bin
* [Leanote 社区](http://bbs.leanote.com) $> sudo sh run.sh
* [QQ群](http://leanote.leanote.com/post/Leanote-groups) ```
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
## 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 社区](http://bbs.leanote.com)
* QQ群: 158716820
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
-19
View File
@@ -1,19 +0,0 @@
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 -7
View File
@@ -14,17 +14,12 @@ type Album struct {
BaseController BaseController
} }
// 图片管理, iframe
func (c Album) Index() revel.Result {
c.SetLocale()
return c.RenderTemplate("album/index.html")
}
// all albums by userId // all albums by userId
func (c Album) GetAlbums() revel.Result { func (c Album) GetAlbums() revel.Result {
re := albumService.GetAlbums(c.GetUserId()) re := albumService.GetAlbums(c.GetUserId())
return c.RenderJson(re) return c.RenderJson(re)
} }
func (c Album) DeleteAlbum(albumId string) revel.Result { func (c Album) DeleteAlbum(albumId string) revel.Result {
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId) re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
return c.RenderJson(info.Re{Ok: re, Msg: msg}) return c.RenderJson(info.Re{Ok: re, Msg: msg})
@@ -39,7 +34,7 @@ func (c Album) AddAlbum(name string) revel.Result {
UserId: c.GetObjectUserId()} UserId: c.GetObjectUserId()}
re := albumService.AddAlbum(album) re := albumService.AddAlbum(album)
if re { if(re) {
return c.RenderJson(album) return c.RenderJson(album)
} else { } else {
return c.RenderJson(false) return c.RenderJson(false)
+17 -34
View File
@@ -3,17 +3,16 @@ package controllers
import ( import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
"archive/tar"
"compress/gzip"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"io" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"io/ioutil" "io/ioutil"
"os" "os"
"strings" "strings"
"time" "time"
"io"
"archive/tar"
"compress/gzip"
) )
// 附件 // 附件
@@ -57,19 +56,13 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
return re return re
} }
// > 5M? // > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize") if(len(data) > 5 * 1024 * 1024) {
if maxFileSize <= 0 { resultMsg = "File is bigger than 5M"
maxFileSize = 1000
}
if float64(len(data)) > maxFileSize*float64(1024*1024) {
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
return re return re
} }
// 生成上传路径 // 生成上传路径
// filePath := "files/" + c.GetUserId() + "/attachs" filePath := "files/" + c.GetUserId() + "/attachs"
newGuid := NewGuid()
filePath := "files/" + GetRandomFilePath(c.GetUserId(), newGuid) + "/attachs"
dir := revel.BasePath + "/" + filePath dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755) err = os.MkdirAll(dir, 0755)
if err != nil { if err != nil {
@@ -78,8 +71,8 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
// 生成新的文件名 // 生成新的文件名
filename := handel.Filename filename := handel.Filename
_, ext := SplitFilename(filename) // .doc _, ext := SplitFilename(filename) // .doc
filename = newGuid + ext filename = NewGuid() + ext
toPath := dir + "/" + filename toPath := dir + "/" + filename;
err = ioutil.WriteFile(toPath, data, 0777) err = ioutil.WriteFile(toPath, data, 0777)
if err != nil { if err != nil {
return re return re
@@ -99,18 +92,14 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
Type: fileType, Type: fileType,
Size: filesize} Size: filesize}
id := bson.NewObjectId() id := bson.NewObjectId();
fileInfo.AttachId = id fileInfo.AttachId = id
fileId = id.Hex() fileId = id.Hex()
Ok, resultMsg = attachService.AddAttach(fileInfo, false) Ok = attachService.AddAttach(fileInfo)
if resultMsg != "" {
resultMsg = c.Message(resultMsg)
}
fileInfo.Path = "" // 不要返回 fileInfo.Path = ""; // 不要返回
if Ok {
resultMsg = "success" resultMsg = "success"
}
return re return re
} }
@@ -132,7 +121,7 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
// 下载附件 // 下载附件
// 权限判断 // 权限判断
func (c Attach) Download(attachId 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 path := attach.Path
if path == "" { if path == "" {
return c.RenderText("") return c.RenderText("")
@@ -167,16 +156,10 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
filename = "all.tar.gz" filename = "all.tar.gz"
} }
dir := revel.BasePath + "/files/attach_all"
if !MkdirAll(dir) {
return c.RenderText("error")
}
// file write // file write
fw, err := os.Create(dir + "/" + filename) fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil { if err != nil {
return c.RenderText("error") return c.RenderText("")
} }
// defer fw.Close() // 不需要关闭, 还要读取给用户下载 // defer fw.Close() // 不需要关闭, 还要读取给用户下载
+22 -40
View File
@@ -1,10 +1,9 @@
package controllers package controllers
import ( import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
// "strconv" // "strconv"
) )
@@ -42,14 +41,14 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
sessionId := c.Session.Id() sessionId := c.Session.Id()
var msg = "" var msg = ""
userInfo, err := authService.Login(email, pwd) userInfo := authService.Login(email, pwd)
if err != nil { if userInfo.Email != "" {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
} else {
c.SetSession(userInfo) c.SetSession(userInfo)
sessionService.ClearLoginTimes(sessionId) sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.Re{Ok: true}) return c.RenderJson(info.Re{Ok: true})
} else {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
} }
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)}) return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
@@ -62,21 +61,20 @@ func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha { if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
msg = "captchaError" msg = "captchaError"
} else { } else {
userInfo, err := authService.Login(email, pwd) userInfo := authService.Login(email, pwd)
if err != nil { if userInfo.Email != "" {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
sessionService.IncrLoginTimes(sessionId)
} else {
c.SetSession(userInfo) c.SetSession(userInfo)
sessionService.ClearLoginTimes(sessionId) sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.Re{Ok: true}) return c.RenderJson(info.Re{Ok: true})
} else {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
sessionService.IncrLoginTimes(sessionId)
} }
} }
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 { func (c Auth) Logout() revel.Result {
sessionId := c.Session.Id() sessionId := c.Session.Id()
@@ -87,51 +85,39 @@ func (c Auth) Logout() revel.Result {
// 体验一下 // 体验一下
func (c Auth) Demo() revel.Result { func (c Auth) Demo() revel.Result {
email := configService.GetGlobalStringConfig("demoUsername") c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
pwd := configService.GetGlobalStringConfig("demoPassword")
userInfo, err := authService.Login(email, pwd)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
} else {
c.SetSession(userInfo)
return c.Redirect("/note") return c.Redirect("/note")
} }
return nil
}
//-------- //--------
// 注册 // 注册
func (c Auth) Register(from, iu string) revel.Result { func (c Auth) Register(from string) revel.Result {
if !configService.IsOpenRegister() { if !configService.IsOpenRegister() {
return c.Redirect("/index") return c.Redirect("/index")
} }
c.SetLocale() c.SetLocale()
c.RenderArgs["from"] = from c.RenderArgs["from"] = from
c.RenderArgs["iu"] = iu
c.RenderArgs["title"] = c.Message("register") c.RenderArgs["title"] = c.Message("register")
c.RenderArgs["subTitle"] = c.Message("register") c.RenderArgs["subTitle"] = c.Message("register")
return c.RenderTemplate("home/register.html") return c.RenderTemplate("home/register.html")
} }
func (c Auth) DoRegister(email, pwd, iu string) revel.Result { func (c Auth) DoRegister(email, pwd string) revel.Result {
if !configService.IsOpenRegister() { if !configService.IsOpenRegister() {
return c.Redirect("/index") return c.Redirect("/index")
} }
re := info.NewRe() re := info.NewRe();
if re.Ok, re.Msg = Vd("email", email); !re.Ok { 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 { 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) re.Ok, re.Msg = authService.Register(email, pwd)
// 注册成功, 则立即登录之 // 注册成功, 则立即登录之
if re.Ok { if re.Ok {
@@ -144,7 +130,6 @@ func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
//-------- //--------
// 找回密码 // 找回密码
func (c Auth) FindPassword() revel.Result { func (c Auth) FindPassword() revel.Result {
c.SetLocale()
c.RenderArgs["title"] = c.Message("findPassword") c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword") c.RenderArgs["subTitle"] = c.Message("findPassword")
return c.RenderTemplate("home/find_password.html") return c.RenderTemplate("home/find_password.html")
@@ -155,16 +140,14 @@ func (c Auth) DoFindPassword(email string) revel.Result {
re.Ok = true re.Ok = true
return c.RenderJson(re) return c.RenderJson(re)
} }
// 点击链接后, 先验证之 // 点击链接后, 先验证之
func (c Auth) FindPassword2(token string) revel.Result { func (c Auth) FindPassword2(token string) revel.Result {
c.SetLocale()
c.RenderArgs["title"] = c.Message("findPassword") c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword") c.RenderArgs["subTitle"] = c.Message("findPassword")
if token == "" { if token == "" {
return c.RenderTemplate("find_password2_timeout.html") return c.RenderTemplate("find_password2_timeout.html")
} }
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd) ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
if !ok { if !ok {
return c.RenderTemplate("home/find_password2_timeout.html") return c.RenderTemplate("home/find_password2_timeout.html")
} }
@@ -175,13 +158,12 @@ func (c Auth) FindPassword2(token string) revel.Result {
return c.RenderTemplate("home/find_password2.html") return c.RenderTemplate("home/find_password2.html")
} }
// 找回密码修改密码 // 找回密码修改密码
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result { 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 { if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re) return c.RenderRe(re);
} }
// 修改之 // 修改之
+18 -43
View File
@@ -1,18 +1,17 @@
package controllers package controllers
import ( import (
"encoding/json"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/revel/revel" "github.com/revel/revel"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"encoding/json"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
// "io/ioutil" // "io/ioutil"
// "fmt" // "fmt"
"bytes"
"math" "math"
"strconv" "strconv"
"strings" "strings"
"bytes"
) )
// 公用Controller, 其它Controller继承它 // 公用Controller, 其它Controller继承它
@@ -20,11 +19,6 @@ type BaseController struct {
*revel.Controller *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 { func (c BaseController) GetUserId() string {
if userId, ok := c.Session["UserId"]; ok { if userId, ok := c.Session["UserId"]; ok {
return userId return userId
@@ -62,7 +56,7 @@ func (c BaseController) GetUsername() string {
// 得到用户信息 // 得到用户信息
func (c BaseController) GetUserInfo() info.User { func (c BaseController) GetUserInfo() info.User {
if userId, ok := c.Session["UserId"]; ok && userId != "" { if userId, ok := c.Session["UserId"]; ok && userId != "" {
return userService.GetUserInfo(userId) return userService.GetUserInfo(userId);
/* /*
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"]) notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"]) noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
@@ -90,13 +84,6 @@ func (c BaseController) GetUserInfo() info.User {
return info.User{} return info.User{}
} }
func (c BaseController) GetUserAndBlogUrl() info.UserAndBlogUrl {
if userId, ok := c.Session["UserId"]; ok && userId != "" {
return userService.GetUserAndBlogUrl(userId)
}
return info.UserAndBlogUrl{}
}
// 这里的session都是cookie中的, 与数据库session无关 // 这里的session都是cookie中的, 与数据库session无关
func (c BaseController) GetSession(key string) string { func (c BaseController) GetSession(key string) string {
v, ok := c.Session[key] v, ok := c.Session[key]
@@ -163,9 +150,9 @@ func (c BaseController) GetPage() int {
// 判断是否含有某参数 // 判断是否含有某参数
func (c BaseController) Has(key string) bool { func (c BaseController) Has(key string) bool {
if _, ok := c.Params.Values[key]; ok { if _, ok := c.Params.Values[key]; ok {
return true return true;
} }
return false return false;
} }
/* /*
@@ -180,27 +167,23 @@ func (c BaseController) GetTotalPage(page, count int) int {
//------------- //-------------
func (c BaseController) E404() revel.Result { func (c BaseController) E404() revel.Result {
c.RenderArgs["title"] = "404" c.RenderArgs["title"] = "404";
return c.NotFound("", nil) return c.NotFound("", nil)
} }
// 设置本地 // 设置本地
func (c BaseController) SetLocale() string { func (c BaseController) SetLocale() string {
locale := string(c.Request.Locale) // zh-CN 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 lang := locale
if !i18n.HasLang(locale) { if strings.Contains(locale, "-") {
lang = i18n.GetDefaultLang() pos := strings.Index(locale, "-")
lang = locale[0:pos]
} }
c.RenderArgs["locale"] = lang if lang != "zh" && lang != "en" {
c.RenderArgs["siteUrl"] = configService.GetSiteUrl() lang = "en";
}
c.RenderArgs["locale"] = lang;
c.RenderArgs["siteUrl"] = siteUrl;
c.RenderArgs["blogUrl"] = configService.GetBlogUrl() c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
c.RenderArgs["leaUrl"] = configService.GetLeaUrl() c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
@@ -210,13 +193,9 @@ func (c BaseController) SetLocale() string {
} }
// 设置userInfo // 设置userInfo
func (c BaseController) SetUserInfo() info.User { func (c BaseController) SetUserInfo() {
userInfo := c.GetUserInfo() userInfo := c.GetUserInfo()
c.RenderArgs["userInfo"] = userInfo c.RenderArgs["userInfo"] = userInfo
if userInfo.Username == configService.GetAdminUsername() {
c.RenderArgs["isAdmin"] = true
}
return userInfo
} }
// life // life
@@ -235,16 +214,15 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
var buffer bytes.Buffer var buffer bytes.Buffer
tpl.Template.Render(&buffer, c.RenderArgs) tpl.Template.Render(&buffer, c.RenderArgs)
return buffer.String() return buffer.String();
} }
// json, result // json, result
// 为了msg // 为了msg
// msg-v1-v2-v3 // msg-v1-v2-v3
func (c BaseController) RenderRe(re info.Re) revel.Result { func (c BaseController) RenderRe(re info.Re) revel.Result {
oldMsg := re.Msg
if re.Msg != "" { if re.Msg != "" {
if strings.Contains(re.Msg, "-") { if(strings.Contains(re.Msg, "-")) {
msgAndValues := strings.Split(re.Msg, "-") msgAndValues := strings.Split(re.Msg, "-")
if len(msgAndValues) == 2 { if len(msgAndValues) == 2 {
re.Msg = c.Message(msgAndValues[0], msgAndValues[1]) re.Msg = c.Message(msgAndValues[0], msgAndValues[1])
@@ -260,8 +238,5 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
re.Msg = c.Message(re.Msg) re.Msg = c.Message(re.Msg)
} }
} }
if strings.HasPrefix(re.Msg, "???") {
re.Msg = oldMsg
}
return c.RenderJson(re) return c.RenderJson(re)
} }
File diff suppressed because it is too large. Load diff
-1
View File
@@ -22,7 +22,6 @@ type Captcha struct {
} }
type Ca string type Ca string
func (r Ca) Apply(req *revel.Request, resp *revel.Response) { func (r Ca) Apply(req *revel.Request, resp *revel.Response) {
resp.WriteHeader(http.StatusOK, "image/png") resp.WriteHeader(http.StatusOK, "image/png")
} }
+105 -65
View File
@@ -3,14 +3,13 @@ package controllers
import ( import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
"fmt" "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/netutil" "github.com/leanote/leanote/app/lea/netutil"
"gopkg.in/mgo.v2/bson" "github.com/leanote/leanote/app/info"
"io/ioutil" "io/ioutil"
"os" "os"
// "strconv" "strconv"
"strings" "strings"
) )
@@ -22,7 +21,7 @@ type File struct {
// 上传的是博客logo // 上传的是博客logo
// TODO logo不要设置权限, 另外的目录 // TODO logo不要设置权限, 另外的目录
func (c File) UploadBlogLogo() revel.Result { func (c File) UploadBlogLogo() revel.Result {
re := c.uploadImage("blogLogo", "") re := c.uploadImage("logo", "");
c.RenderArgs["fileUrlPath"] = re.Id c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code c.RenderArgs["resultCode"] = re.Code
@@ -34,9 +33,8 @@ func (c File) UploadBlogLogo() revel.Result {
// 拖拉上传, pasteImage // 拖拉上传, pasteImage
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中 // noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
func (c File) PasteImage(noteId string) revel.Result { func (c File) PasteImage(noteId string) revel.Result {
re := c.uploadImage("pasteImage", "") re := c.uploadImage("pasteImage", "");
if noteId != "" {
userId := c.GetUserId() userId := c.GetUserId()
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
if note.UserId != "" { if note.UserId != "" {
@@ -52,14 +50,13 @@ func (c File) PasteImage(noteId string) revel.Result {
} }
} }
} }
}
return c.RenderJson(re) return c.RenderJson(re)
} }
// 头像设置 // 头像设置
func (c File) UploadAvatar() revel.Result { func (c File) UploadAvatar() revel.Result {
re := c.uploadImage("logo", "") re := c.uploadImage("logo", "");
c.RenderArgs["fileUrlPath"] = re.Id c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code c.RenderArgs["resultCode"] = re.Code
@@ -68,7 +65,7 @@ func (c File) UploadAvatar() revel.Result {
if re.Ok { if re.Ok {
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id) re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
if re.Ok { if re.Ok {
c.UpdateSession("Logo", re.Id) c.UpdateSession("Logo", re.Id);
} }
} }
@@ -77,7 +74,7 @@ func (c File) UploadAvatar() revel.Result {
// leaui image plugin upload image // leaui image plugin upload image
func (c File) UploadImageLeaui(albumId string) revel.Result { func (c File) UploadImageLeaui(albumId string) revel.Result {
re := c.uploadImage("", albumId) re := c.uploadImage("", albumId);
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -87,7 +84,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
var fileUrlPath = "" var fileUrlPath = ""
var fileId = "" var fileId = ""
var resultCode = 0 // 1表示正常 var resultCode = 0 // 1表示正常
var resultMsg = "error" // 错误信息 var resultMsg = "内部错误" // 错误信息
var Ok = false var Ok = false
defer func() { defer func() {
@@ -102,19 +99,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
return re return re
} }
defer file.Close() defer file.Close()
// 生成上传路径 // 生成上传路径
newGuid := NewGuid() if(from == "logo") {
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
userId := c.GetUserId()
if from == "logo" || from == "blogLogo" {
fileUrlPath = "public/upload/" + Digest3(userId) + "/" + userId + "/images/logo"
} else { } else {
// fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images" fileUrlPath = "files/" + c.GetUserId() + "/images"
fileUrlPath = "files/" + GetRandomFilePath(userId, newGuid) + "/images"
} }
dir := revel.BasePath + "/" + fileUrlPath dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755) err = os.MkdirAll(dir, 0755)
if err != nil { if err != nil {
@@ -123,45 +113,32 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
// 生成新的文件名 // 生成新的文件名
filename := handel.Filename filename := handel.Filename
var ext string var ext string;
if from == "pasteImage" { if from == "pasteImage" {
handel.Filename = c.Message("unTitled") ext = ".png"; // TODO 可能不是png类型
ext = ".png" // TODO 可能不是png类型
} else { } else {
_, ext = SplitFilename(filename) _, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" { if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
resultMsg = "Please upload image" resultMsg = "不是图片"
return re return re
} }
} }
filename = newGuid + ext filename = NewGuid() + ext
data, err := ioutil.ReadAll(file) data, err := ioutil.ReadAll(file)
if err != nil { if err != nil {
LogJ(err) LogJ(err)
return re return re
} }
var maxFileSize float64
if from == "logo" {
maxFileSize = configService.GetUploadSize("uploadAvatarSize")
} else if from == "blogLogo" {
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize")
} else {
maxFileSize = configService.GetUploadSize("uploadImageSize")
}
if maxFileSize <= 0 {
maxFileSize = 1000
}
// > 2M? // > 2M?
if float64(len(data)) > maxFileSize*float64(1024*1024) { if(len(data) > 5 * 1024 * 1024) {
resultCode = 0 resultCode = 0
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize) resultMsg = "图片大于2M"
return re return re
} }
toPath := dir + "/" + filename toPath := dir + "/" + filename;
err = ioutil.WriteFile(toPath, data, 0777) err = ioutil.WriteFile(toPath, data, 0777)
if err != nil { if err != nil {
LogJ(err) LogJ(err)
@@ -173,7 +150,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
filesize := GetFilesize(toPathGif) filesize := GetFilesize(toPathGif)
fileUrlPath += "/" + filename fileUrlPath += "/" + filename
resultCode = 1 resultCode = 1
resultMsg = "Upload Success!" resultMsg = "上传成功!"
// File // File
fileInfo := info.File{Name: filename, fileInfo := info.File{Name: filename,
@@ -181,18 +158,16 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
Path: fileUrlPath, Path: fileUrlPath,
Size: filesize} Size: filesize}
id := bson.NewObjectId() id := bson.NewObjectId();
fileInfo.FileId = id fileInfo.FileId = id
fileId = id.Hex() fileId = id.Hex()
if(from == "logo") {
if from == "logo" || from == "blogLogo" { fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
fileId = fileUrlPath
} }
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage") Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
resultMsg = c.Message(resultMsg)
fileInfo.Path = "" // 不要返回 fileInfo.Path = ""; // 不要返回
re.Item = fileInfo re.Item = fileInfo
return re return re
@@ -216,12 +191,60 @@ func (c File) DeleteImage(fileId string) revel.Result {
return c.RenderJson(re) return c.RenderJson(re)
} }
// update image uploader to leaui image,
// scan all user's images and insert into db
func (c File) UpgradeLeauiImage() revel.Result {
re := info.NewRe()
if ok, _ := revel.Config.Bool("upgradeLeauiImage"); !ok {
re.Msg = "Not allowed"
return c.RenderJson(re)
}
uploadPath := revel.BasePath + "/public/upload";
userIds := ListDir(uploadPath)
if userIds == nil {
re.Msg = "no user"
return c.RenderJson(re)
}
msg := "";
for _, userId := range userIds {
dirPath := uploadPath + "/" + userId + "/images"
images := ListDir(dirPath)
if images == nil {
msg += userId + " no images "
continue;
}
hadImages := fileService.GetAllImageNamesMap(userId)
i := 0
for _, filename := range images {
if _, ok := hadImages[filename]; !ok {
fileUrlPath := "/upload/" + userId + "/images/" + filename
fileInfo := info.File{Name: filename,
Title: filename,
Path: fileUrlPath,
Size: GetFilesize(dirPath + "/" + filename)}
fileService.AddImage(fileInfo, "", userId)
i++
}
}
msg += userId + ": " + strconv.Itoa(len(images)) + " -- " + strconv.Itoa(i) + " images "
}
re.Msg = msg
return c.RenderJson(re)
}
//----------- //-----------
// 输出image // 输出image
// 权限判断 // 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result { func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId) // 得到路径 path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
if path == "" { if path == "" {
return c.RenderText("") return c.RenderText("")
} }
@@ -231,24 +254,19 @@ func (c File) OutputImage(noteId, fileId string) revel.Result {
} }
// 协作时复制图片到owner // 协作时复制图片到owner
// 需要计算对方大小
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result { func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId) re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re) return c.RenderJson(re)
} }
// 复制外网的图片 // 复制外网的图片, 成公共图片 放在/upload下
// 都要好好的计算大小
func (c File) CopyHttpImage(src string) revel.Result { func (c File) CopyHttpImage(src string) revel.Result {
re := info.NewRe() re := info.NewRe()
fileUrlPath := "upload/" + c.GetUserId() + "/images"
// 生成上传路径 dir := revel.BasePath + "/public/" + fileUrlPath
newGuid := NewGuid()
userId := c.GetUserId()
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err := os.MkdirAll(dir, 0755) err := os.MkdirAll(dir, 0755)
if err != nil { if err != nil {
return c.RenderJson(re) return c.RenderJson(re)
@@ -266,12 +284,34 @@ func (c File) CopyHttpImage(src string) revel.Result {
Path: fileUrlPath + "/" + filename, Path: fileUrlPath + "/" + filename,
Size: filesize} Size: filesize}
id := bson.NewObjectId() id := bson.NewObjectId();
fileInfo.FileId = id fileInfo.FileId = id
re.Id = id.Hex() re.Id = id.Hex()
// re.Item = fileInfo.Path re.Item = fileInfo.Path
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true) re.Ok = fileService.AddImage(fileInfo, "", c.GetUserId())
return c.RenderJson(re) return c.RenderJson(re)
} }
//------------
// 过时 已弃用!
func (c File) UploadImage(renderHtml string) revel.Result {
if renderHtml == "" {
renderHtml = "file/image.html"
}
re := c.uploadImage("", "");
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
return c.RenderTemplate(renderHtml)
}
// 已弃用
func (c File) UploadImageJson(from, noteId string) revel.Result {
re := c.uploadImage(from, "");
return c.RenderJson(re)
}
+4 -12
View File
@@ -1,8 +1,8 @@
package controllers package controllers
import ( import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel" "github.com/revel/revel"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
) )
@@ -12,22 +12,14 @@ type Index struct {
BaseController BaseController
} }
func (c Index) Default() revel.Result {
if configService.HomePageIsAdminsBlog() {
blog := Blog{c.BaseController}
return blog.Index(configService.GetAdminUsername())
}
return c.Index()
}
// leanote展示页, 没有登录的, 或已登录明确要进该页的 // leanote展示页, 没有登录的, 或已登录明确要进该页的
func (c Index) Index() revel.Result { func (c Index) Index() revel.Result {
c.SetUserInfo() c.SetUserInfo()
c.RenderArgs["title"] = "leanote" c.RenderArgs["title"] = "leanote"
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"] c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
c.SetLocale() lang := c.SetLocale()
return c.RenderTemplate("home/index.html") return c.RenderTemplate("home/index_" + lang + ".html");
} }
// 建议 // 建议
@@ -38,7 +30,7 @@ func (c Index) Suggestion(addr, suggestion string) revel.Result {
// 发给我 // 发给我
go func() { 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) return c.RenderJson(re)
} }
+44
View File
@@ -0,0 +1,44 @@
package controllers
import (
"github.com/revel/revel"
// "github.com/leanote/leanote/app/info"
)
// 首页
type Mobile struct {
BaseController
}
// leanote展示页, 没有登录的, 或已登录明确要进该页的
func (c Mobile) Index() revel.Result {
c.SetLocale()
userInfo := c.GetUserInfo()
userId := userInfo.UserId.Hex()
// 没有登录
if userId == "" {
return c.RenderTemplate("mobile/login.html")
}
/*
// 已登录了, 那么得到所有信息
notebooks := notebookService.GetNotebooks(userId)
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
c.RenderArgs["notebooks"] = c.Json(notebooks)
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
*/
return c.RenderTemplate("mobile/angular.html");
}
func (c Mobile) Logout() revel.Result {
c.ClearSession()
return c.RenderTemplate("mobile/login.html");
}
+147 -275
View File
@@ -3,17 +3,13 @@ package controllers
import ( import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"os" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"os/exec" "os/exec"
"regexp"
"strings"
"time"
// "github.com/leanote/leanote/app/types" // "github.com/leanote/leanote/app/types"
// "io/ioutil" // "io/ioutil"
"fmt" // "fmt"
// "bytes" // "bytes"
// "os" // "os"
) )
@@ -25,9 +21,10 @@ type Note struct {
// 笔记首页, 判断是否已登录 // 笔记首页, 判断是否已登录
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中 // 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
// 否则, 转向登录页面 // 否则, 转向登录页面
func (c Note) Index(noteId, online string) revel.Result { func (c Note) Index() revel.Result {
c.SetLocale() c.SetLocale()
userInfo := c.GetUserAndBlogUrl()
userInfo := c.GetUserInfo()
userId := userInfo.UserId.Hex() userId := userInfo.UserId.Hex()
@@ -45,92 +42,31 @@ func (c Note) Index(noteId, online string) revel.Result {
// 还需要按时间排序(DESC)得到notes // 还需要按时间排序(DESC)得到notes
notes := []info.Note{} notes := []info.Note{}
noteContent := info.NoteContent{} noteContent := info.NoteContent{}
if len(notebooks) > 0 { if len(notebooks) > 0 {
// noteId是否存在 // _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), pageSize, defaultSortField, false, false);
// 是否传入了正确的noteId // 变成最新
hasRightNoteId := false _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
if IsObjectId(noteId) {
note := noteService.GetNoteById(noteId)
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
// 没有读写权限
} else {
hasRightNoteId = false
}
} else {
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false)
// 如果指定了某笔记, 则该笔记放在首位
lenNotes := len(notes)
if lenNotes > 1 {
notes2 := make([]info.Note, len(notes))
notes2[0] = note
i := 1
for _, note := range notes {
if note.NoteId.Hex() != noteId {
if i == lenNotes { // 防止越界
break
}
notes2[i] = note
i++
}
}
notes = notes2
}
}
}
// 得到最近的笔记
_, 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)
if len(notes) > 0 { if len(notes) > 0 {
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId) noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
} }
} }
}
// 当然, 还需要得到第一个notes的content // 当然, 还需要得到第一个notes的content
//... //...
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username
c.RenderArgs["userInfo"] = userInfo c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["notebooks"] = notebooks c.RenderArgs["userInfoJson"] = c.Json(userInfo)
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中 c.RenderArgs["notebooks"] = c.Json(notebooks)
c.RenderArgs["sharedUserInfos"] = sharedUserInfos c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
c.RenderArgs["notes"] = notes c.RenderArgs["notes"] = c.Json(notes)
c.RenderArgs["noteContentJson"] = noteContent c.RenderArgs["noteContentJson"] = c.Json(noteContent)
c.RenderArgs["noteContent"] = noteContent.Content c.RenderArgs["noteContent"] = noteContent.Content
c.RenderArgs["tags"] = tagService.GetTags(c.GetUserId()) c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser() 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") return c.RenderTemplate("note/note-dev.html")
} else { } else {
return c.RenderTemplate("note/note.html") return c.RenderTemplate("note/note.html")
@@ -141,13 +77,13 @@ func (c Note) Index(noteId, online string) revel.Result {
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中 // 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
// 否则, 转向登录页面 // 否则, 转向登录页面
func (c Note) ListNotes(notebookId string) revel.Result { func (c Note) ListNotes(notebookId string) revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false) _, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false);
return c.RenderJson(notes) return c.RenderJson(notes)
} }
// 得到trash // 得到trash
func (c Note) ListTrashNotes() revel.Result { func (c Note) ListTrashNotes() revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false) _, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false);
return c.RenderJson(notes) return c.RenderJson(notes)
} }
@@ -162,12 +98,30 @@ func (c Note) GetNoteContent(noteId string) revel.Result {
return c.RenderJson(noteContent) 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 // 这里不能用json, 要用post
func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result { func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
// 新添加note // 新添加note
if noteOrContent.IsNew { if noteOrContent.IsNew {
userId := c.GetObjectUserId() userId := c.GetObjectUserId();
// myUserId := userId myUserId := userId
// 为共享新建? // 为共享新建?
if noteOrContent.FromUserId != "" { if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId) userId = bson.ObjectIdHex(noteOrContent.FromUserId)
@@ -177,19 +131,19 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
NoteId: bson.ObjectIdHex(noteOrContent.NoteId), NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId), NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
Title: noteOrContent.Title, Title: noteOrContent.Title,
Tags: strings.Split(noteOrContent.Tags, ","), Tags: noteOrContent.Tags,
Desc: noteOrContent.Desc, Desc: noteOrContent.Desc,
ImgSrc: noteOrContent.ImgSrc, ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog, IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown, IsMarkdown: noteOrContent.IsMarkdown,
} };
noteContent := info.NoteContent{NoteId: note.NoteId, noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId, UserId: userId,
IsBlog: note.IsBlog, IsBlog: note.IsBlog,
Content: noteOrContent.Content, Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract} Abstract: noteOrContent.Abstract};
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId()) note = noteService.AddNoteAndContent(note, noteContent, myUserId)
return c.RenderJson(note) return c.RenderJson(note)
} }
@@ -199,102 +153,61 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
// Desc前台传来 // Desc前台传来
if c.Has("Desc") { if c.Has("Desc") {
needUpdateNote = true needUpdateNote = true
noteUpdate["Desc"] = noteOrContent.Desc noteUpdate["Desc"] = noteOrContent.Desc;
} }
if c.Has("ImgSrc") { if c.Has("ImgSrc") {
needUpdateNote = true needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc noteUpdate["ImgSrc"] = noteOrContent.ImgSrc;
} }
if c.Has("Title") { if c.Has("Title") {
needUpdateNote = true needUpdateNote = true
noteUpdate["Title"] = noteOrContent.Title noteUpdate["Title"] = noteOrContent.Title;
} }
if c.Has("Tags") { if c.Has("Tags[]") {
needUpdateNote = true needUpdateNote = true
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",") noteUpdate["Tags"] = noteOrContent.Tags;
} }
// web端不控制
if needUpdateNote { if needUpdateNote {
noteService.UpdateNote(c.GetUserId(), noteService.UpdateNote(noteOrContent.UserId, c.GetUserId(),
noteOrContent.NoteId, noteUpdate, -1) noteOrContent.NoteId, noteUpdate)
} }
//------------- //-------------
afterContentUsn := 0
contentOk := false
contentMsg := ""
if c.Has("Content") {
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.GetUserId(),
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract,
needUpdateNote, -1, time.Now())
}
Log(afterContentUsn) if c.Has("Content") {
Log(contentOk) noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
Log(contentMsg) noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
}
return c.RenderJson(true) return c.RenderJson(true)
} }
// 删除note/ 删除别人共享给我的笔记 // 删除note/ 删除别人共享给我的笔记
// userId 是note.UserId // userId 是note.UserId
func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result { func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
if !isShared { if(!isShared) {
for _, noteId := range noteIds { return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
trashService.DeleteNote(noteId, c.GetUserId())
}
return c.RenderJson(true)
} }
for _, noteId := range noteIds { return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
trashService.DeleteSharedNote(noteId, c.GetUserId())
} }
// 删除trash
return c.RenderJson(true)
}
// 删除trash, 已弃用, 用DeleteNote
func (c Note) DeleteTrash(noteId string) revel.Result { func (c Note) DeleteTrash(noteId string) revel.Result {
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId())) return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()));
} }
// 移动note // 移动note
func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result { func (c Note) MoveNote(noteId, notebookId string) revel.Result {
userId := c.GetUserId() return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
for _, noteId := range noteIds {
noteService.MoveNote(noteId, notebookId, userId)
} }
return c.RenderJson(true)
}
// 复制note // 复制note
func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result { func (c Note) CopyNote(noteId, notebookId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds)) return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopyNote(noteId, notebookId, userId)
} }
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJson(re)
}
// 复制别人共享的笔记给我 // 复制别人共享的笔记给我
func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) revel.Result { func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds)) return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopySharedNote(noteId, notebookId, fromUserId, userId)
}
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJson(re)
} }
//------------ //------------
@@ -304,105 +217,50 @@ func (c Note) SearchNote(key string) revel.Result {
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false) _, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
return c.RenderJson(blogs) return c.RenderJson(blogs)
} }
// 通过tags搜索 // 通过tags搜索
func (c Note) SearchNoteByTags(tags []string) revel.Result { func (c Note) SearchNoteByTags(tags []string) revel.Result {
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false) _, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
return c.RenderJson(blogs) return c.RenderJson(blogs)
} }
// 生成PDF //------------------
func (c Note) ToPdf(noteId, appKey string) revel.Result { // html2image
// 判断是否有权限生成
// 博客也可以调用
// 这是脚本调用, 没有cookie, 不执行权限控制, 通过传来的appKey判断
func (c Note) ToImage(noteId, appKey string) revel.Result {
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之 // 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
appKeyTrue, _ := revel.Config.String("app.secret") appKeyTrue, _ := revel.Config.String("app.secret")
if appKeyTrue != appKey { if appKeyTrue != appKey {
return c.RenderText("auth error") return c.RenderText("")
} }
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
if note.NoteId == "" { if note.NoteId == "" {
return c.RenderText("no note") return c.RenderText("")
} }
c.SetLocale()
noteUserId := note.UserId.Hex() noteUserId := note.UserId.Hex()
content := noteService.GetNoteContent(noteId, noteUserId) content := noteService.GetNoteContent(noteId, noteUserId)
userInfo := userService.GetUserInfo(noteUserId) userInfo := userService.GetUserInfo(noteUserId);
//------------------
// 将content的图片转换为base64
contentStr := content.Content
siteUrlPattern := configService.GetSiteUrl()
if strings.Contains(siteUrlPattern, "https") {
siteUrlPattern = strings.Replace(siteUrlPattern, "https", "https*", 1)
} else {
siteUrlPattern = strings.Replace(siteUrlPattern, "http", "https*", 1)
}
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 {
// ![enter image description here](url)
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 := "![](" + fileBase64 + ")"
contentStr = strings.Replace(contentStr, eachFind[0], allFixed, -1)
}
}
}
if note.Tags != nil && len(note.Tags) > 0 && note.Tags[0] != "" {
} else {
note.Tags = nil
}
c.RenderArgs["blog"] = note c.RenderArgs["blog"] = note
c.RenderArgs["content"] = contentStr c.RenderArgs["content"] = content.Content
c.RenderArgs["userInfo"] = userInfo c.RenderArgs["userInfo"] = userInfo
userBlog := blogService.GetUserBlog(noteUserId) userBlog := blogService.GetUserBlog(noteUserId)
c.RenderArgs["userBlog"] = userBlog c.RenderArgs["userBlog"] = userBlog
return c.RenderTemplate("file/pdf.html") return c.RenderTemplate("html2Image/index.html")
} }
// 导出成PDF func (c Note) Html2Image(noteId string) revel.Result {
func (c Note) ExportPdf(noteId string) revel.Result {
re := info.NewRe() re := info.NewRe()
userId := c.GetUserId() userId := c.GetUserId()
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
if note.NoteId == "" { if note.NoteId == "" {
re.Msg = "No Note" re.Msg = "No Note"
return c.RenderText("error") return c.RenderJson(re)
} }
noteUserId := note.UserId.Hex() noteUserId := note.UserId.Hex()
@@ -411,71 +269,85 @@ func (c Note) ExportPdf(noteId string) revel.Result {
// 是否是有权限协作的 // 是否是有权限协作的
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) { if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
re.Msg = "No Perm" re.Msg = "No Perm"
return c.RenderText("No Perm") return c.RenderJson(re)
} }
} }
// path 判断是否需要重新生成之 // path 判断是否需要重新生成之
guid := NewGuid() fileUrlPath := "/upload/" + noteUserId + "/images/weibo"
fileUrlPath := "files/export_pdf" dir := revel.BasePath + "/public/" + fileUrlPath
dir := revel.BasePath + "/" + fileUrlPath if !ClearDir(dir) {
if !MkdirAll(dir) { re.Msg = "No Dir"
return c.RenderText("error, no dir") return c.RenderJson(re)
} }
filename := guid + ".pdf"
filename := note.NoteId.Hex() + ".png";
path := dir + "/" + filename path := dir + "/" + filename
// leanote.com的secret // cookie
appKey, _ := revel.Config.String("app.secretLeanote") cookieName := revel.CookiePrefix + "_SESSION"
if appKey == "" { cookie, err := c.Request.Cookie(cookieName)
appKey, _ = revel.Config.String("app.secret") cookieStr := cookie.String()
cookieValue := ""
if err == nil && len(cookieStr) > len(cookieName) {
cookieValue = cookieStr[len(cookieName)+1:]
} }
appKey, _ := revel.Config.String("app.secret")
cookieDomain, _ := revel.Config.String("cookie.domain")
// 生成之 // 生成之
binPath := configService.GetGlobalStringConfig("exportPdfBinPath") url := siteUrl + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
// 默认路径 // /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
binPath := configService.GetGlobalStringConfig("toImageBinPath")
if binPath == "" { if binPath == "" {
binPath = "/usr/local/bin/wkhtmltopdf" return c.RenderJson(re);
} }
cc := binPath + " \"" + url + "\" \"" + path + "\" \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
// cc := binPath + " --no-stop-slow-scripts --javascript-delay 10000 \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
// cc := binPath + " \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
// 等待--window-status为done的状态
// http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html
// wkhtmltopdf参数大全
var cc string
if note.IsMarkdown {
cc = binPath + " --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) cmd := exec.Command("/bin/sh", "-c", cc)
_, err := cmd.Output() Log(cc);
if err != nil { b, err := cmd.Output()
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err)) if err == nil {
} re.Ok = true
file, err := os.Open(path) re.Id = fileUrlPath + "/" + filename
if err != nil {
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
}
// http://stackoverflow.com/questions/8588818/chrome-pdf-display-duplicate-headers-received-from-the-server
// filenameReturn = strings.Replace(filenameReturn, ",", "-", -1)
filenameReturn := note.Title
filenameReturn = FixFilename(filenameReturn)
if filenameReturn == "" {
filenameReturn = "Untitled.pdf"
} else { } else {
filenameReturn += ".pdf" re.Msg = string(b)
} Log("error:......")
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment Log(string(b))
} }
// 设置/取消Blog; 置顶 return c.RenderJson(re)
func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
for _, noteId := range noteIds { /*
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop) // 这里速度慢, 生成不完全(图片和内容都不全)
content := noteService.GetNoteContent(noteId, noteUserId)
userInfo := userService.GetUserInfo(noteUserId);
c.SetLocale()
c.RenderArgs["blog"] = note
c.RenderArgs["content"] = content.Content
c.RenderArgs["userInfo"] = userInfo
userBlog := blogService.GetUserBlog(noteUserId)
c.RenderArgs["userBlog"] = userBlog
html := c.RenderTemplateStr("html2Image/index.html") // Result类型的
contentFile := dir + "/html";
fout, err := os.Create(contentFile)
if err != nil {
return c.RenderJson(re)
} }
return c.RenderJson(true) fout.WriteString(html);
fout.Close()
cc := "/Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/c.js \"" + contentFile + "\" \"" + path + "\""
cmd := exec.Command("/bin/sh", "-c", cc)
b, err := cmd.Output()
if err == nil {
re.Ok = true
re.Id = fileUrlPath + "/" + filename
} else {
Log(string(b))
}
*/
} }
+7 -16
View File
@@ -1,9 +1,9 @@
package controllers package controllers
import ( import (
"github.com/revel/revel"
"encoding/json" "encoding/json"
"github.com/leanote/leanote/app/info" "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" // . "github.com/leanote/leanote/app/lea"
// "io/ioutil" // "io/ioutil"
@@ -34,19 +34,17 @@ func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.
Title: title, Title: title,
Seq: -1, Seq: -1,
UserId: c.GetObjectUserId()} UserId: c.GetObjectUserId()}
if parentNotebookId != "" { if(parentNotebookId != "") {
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId) notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
} }
re := notebookService.AddNotebook(notebook)
re, notebook := notebookService.AddNotebook(notebook) if(re) {
if re {
return c.RenderJson(notebook) return c.RenderJson(notebook)
} else { } else {
return c.RenderJson(false) return c.RenderJson(false)
} }
} }
// 修改标题 // 修改标题
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result { func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title)) return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
@@ -54,9 +52,9 @@ func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
// 排序 // 排序
// 无用 // 无用
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result { func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
// return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs)) return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
// } }
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下 // 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
type DragNotebooksInfo struct { type DragNotebooksInfo struct {
@@ -64,7 +62,6 @@ type DragNotebooksInfo struct {
ParentNotebookId string ParentNotebookId string
Siblings []string Siblings []string
} }
// 传过来的data是JSON.stringfy数据 // 传过来的data是JSON.stringfy数据
func (c Notebook) DragNotebooks(data string) revel.Result { func (c Notebook) DragNotebooks(data string) revel.Result {
info := DragNotebooksInfo{} info := DragNotebooksInfo{}
@@ -72,9 +69,3 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings)) return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
} }
// 设置notebook <-> blog
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
return c.RenderJson(re)
}
+70
View File
@@ -0,0 +1,70 @@
package controllers
import (
"code.google.com/p/goauth2/oauth"
"github.com/revel/revel"
"github.com/leanote/leanote/app/lea/netutil"
. "github.com/leanote/leanote/app/lea"
"encoding/json"
"fmt"
)
type Oauth struct {
BaseController
}
var oauthCfg = &oauth.Config{
ClientId: "3790fbf1fc14bc6c5d85",
ClientSecret: "e9dadfe601c7caa6df9b33db3e7539945c60dfa2",
AuthURL: "https://github.com/login/oauth/authorize",
TokenURL: "https://github.com/login/oauth/access_token",
RedirectURL: "http://leanote.com/oauth/githubCallback",
Scope: "user",
}
// 用户允许后, github返回到leanote
// 通过code得到token
// https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Foauth2callback&response_type=code&scope=user&state=
func (c Oauth) GithubCallback(code string) revel.Result {
t := &oauth.Transport{Config: oauthCfg}
// Exchange the received code for a token
tok, err := t.Exchange(code)
token := tok.AccessToken
if err != nil || token == "" {
c.RenderArgs["title"] = "error"
return c.RenderTemplate("oauth/oauth_callback_error.html")
}
// 得到用户信息
profileInfoURL := "https://api.github.com/user"
url := fmt.Sprintf("%s?access_token=%s", profileInfoURL, token)
content, err2 := netutil.GetContent(url)
if err2 != nil {
c.RenderArgs["title"] = "error"
return c.RenderTemplate("oauth/oauth_callback_error.html")
}
// 转成map
profileInfo := map[string]interface{}{}
Log(string(content))
err2 = json.Unmarshal(content, &profileInfo)
if err2 != nil {
c.RenderArgs["title"] = "error"
return c.RenderTemplate("oauth/oauth_callback_error.html")
}
usernameI := profileInfo["login"]
username, _ := usernameI.(string)
userId := username
// 注册
isExists, userInfo := authService.ThirdRegister("github", userId, username)
c.RenderArgs["isExists"] = isExists
c.RenderArgs["userInfo"] = userInfo
// 登录之
c.SetSession(userInfo)
return c.Redirect("/note")
}
-103
View File
@@ -1,103 +0,0 @@
package controllers
import (
"github.com/revel/revel"
// "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/types"
// "io/ioutil"
// "math"
// "os"
// "path"
)
type Preview struct {
Blog
}
// 得到要预览的主题绝对路径
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
if themeId != "" {
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了, 待优化, 有时会取不到
} else {
themeId = c.Session["themeId"] // 直接从session中获取
}
if themeId == "" {
return false
}
theme := themeService.GetTheme(c.GetUserId(), themeId)
c.RenderArgs["isPreview"] = true
c.RenderArgs["themeId"] = themeId
c.RenderArgs["themeInfoPreview"] = theme.Info
c.RenderArgs["themePath"] = theme.Path
if theme.Path == "" {
return false
}
return true
}
func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
if !c.getPreviewThemeAbsolutePath(themeId) {
return c.E404()
}
return c.Blog.Index(c.GetUserId())
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
}
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Tag(c.GetUserId(), tag)
}
func (c Preview) Tags(userIdOrEmail string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
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(""))
}
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(""))
}
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(""))
}
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(""))
}
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(""))
}
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(""))
}
+20 -70
View File
@@ -4,8 +4,8 @@ import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
// "gopkg.in/mgo.v2/bson" // "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/types" // "github.com/leanote/leanote/app/types"
// "io/ioutil" // "io/ioutil"
// "fmt" // "fmt"
@@ -19,13 +19,13 @@ type Share struct {
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result { func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails)) status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享 // 自己不能给自己添加共享
myEmail := c.GetEmail() myEmail := c.GetEmail();
for _, email := range emails { for _, email := range emails {
if email == "" { if email == "" {
continue continue;
} }
if myEmail != email { if(myEmail != email) {
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email) ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email);
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId} status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else { } else {
@@ -40,13 +40,13 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result { func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails)) status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享 // 自己不能给自己添加共享
myEmail := c.GetEmail() myEmail := c.GetEmail();
for _, email := range emails { for _, email := range emails {
if email == "" { if email == "" {
continue continue;
} }
if myEmail != email { if(myEmail != email) {
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email) ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email);
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId} status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else { } else {
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"} status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
@@ -62,11 +62,11 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
// 表示是默认笔记本, 不是某个特定notebook的共享 // 表示是默认笔记本, 不是某个特定notebook的共享
var notes []info.ShareNoteWithPerm var notes []info.ShareNoteWithPerm
if notebookId == "" { 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) return c.RenderJson(notes)
} else { } else {
// 有notebookId的 // 有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));
} }
} }
@@ -87,10 +87,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
noteShareUserInfos := shareService.ListNoteShareUserInfo(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["isNote"] = true
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex() c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
c.RenderArgs["title"] = note.Title c.RenderArgs["title"] = note.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html") return c.RenderTemplate("share/note_notebook_share_user_infos.html")
@@ -101,11 +99,8 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(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["isNote"] = false
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex() c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
c.RenderArgs["title"] = notebook.Title c.RenderArgs["title"] = notebook.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html") return c.RenderTemplate("share/note_notebook_share_user_infos.html")
@@ -114,79 +109,34 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
//------------ //------------
// 改变share note 权限 // 改变share note 权限
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result { 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 权限 // 改变share notebook 权限
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result { 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 // 删除share note
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result { 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 // 删除share notebook
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result { 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, 被共享方删除 // 删除share note, 被共享方删除
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result { 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, 被共享方删除 // 删除share notebook, 被共享方删除
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result { 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 // 删除fromUserId分享给我的所有note, notebook
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result { 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)
}
// 删除
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
re := info.NewRe()
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)
}
// 删除
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
re := info.NewRe()
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)
} }
-30
View File
@@ -1,30 +0,0 @@
package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// "os/exec"
)
type Tag struct {
BaseController
}
// 更新Tag
func (c Tag) UpdateTag(tag string) revel.Result {
ret := info.NewRe()
ret.Ok = true
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
return c.RenderJson(ret)
}
// 删除标签
func (c Tag) DeleteTag(tag string) revel.Result {
ret := info.Re{}
ret.Ok = true
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
return c.RenderJson(ret)
}
+61 -25
View File
@@ -4,8 +4,8 @@ import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
// "gopkg.in/mgo.v2/bson" // "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types" // "github.com/leanote/leanote/app/types"
// "io/ioutil" // "io/ioutil"
// "fmt" // "fmt"
@@ -29,59 +29,59 @@ func (c User) Account(tab int) revel.Result {
// 修改用户名, 需要重置session // 修改用户名, 需要重置session
func (c User) UpdateUsername(username string) revel.Result { func (c User) UpdateUsername(username string) revel.Result {
re := info.NewRe() re := info.NewRe();
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") { if(c.GetUsername() == "demo") {
re.Msg = "cannotUpdateDemo" re.Msg = "cannotUpdateDemo"
return c.RenderRe(re) return c.RenderRe(re);
} }
if re.Ok, re.Msg = Vd("username", username); !re.Ok { 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) re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
if re.Ok { if(re.Ok) {
c.UpdateSession("Username", username) c.UpdateSession("Username", username)
} }
return c.RenderRe(re) return c.RenderRe(re);
} }
// 修改密码 // 修改密码
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result { func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewRe() re := info.NewRe();
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") { if(c.GetUsername() == "demo") {
re.Msg = "cannotUpdateDemo" re.Msg = "cannotUpdateDemo"
return c.RenderRe(re) return c.RenderRe(re);
} }
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok { 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 { 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) 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 { func (c User) UpdateTheme(theme string) revel.Result {
re := info.NewRe() re := info.NewRe();
re.Ok = userService.UpdateTheme(c.GetUserId(), theme) re.Ok = userService.UpdateTheme(c.GetUserId(), theme)
if re.Ok { if re.Ok {
c.UpdateSession("Theme", theme) c.UpdateSession("Theme", theme)
} }
return c.RenderJson(re) return c.RenderJson(re);
} }
// 发送邀请链接 // 发送邀请链接
func (c User) SendRegisterEmail(content, toEmail string) revel.Result { func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
re := info.NewRe() re := info.NewRe()
if content == "" || !IsEmail(toEmail) { if content == "" || !IsEmail(toEmail) {
return c.RenderJson(re) return c.RenderJson(re);
} }
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content) re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
return c.RenderJson(re) return c.RenderJson(re);
} }
//--------------------------- //---------------------------
@@ -93,10 +93,25 @@ func (c User) ReSendActiveEmail() revel.Result {
return c.RenderJson(re) 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 { func (c User) UpdateEmail(token string) revel.Result {
c.SetUserInfo() c.SetUserInfo();
ok, msg, email := userService.UpdateEmail(token) ok, msg, email := userService.UpdateEmail(token)
@@ -115,13 +130,13 @@ func (c User) UpdateEmail(token string) revel.Result {
// 注册后激活邮箱 // 注册后激活邮箱
func (c User) ActiveEmail(token string) revel.Result { func (c User) ActiveEmail(token string) revel.Result {
c.SetUserInfo() c.SetUserInfo();
ok, msg, email := userService.ActiveEmail(token) ok, msg, email := userService.ActiveEmail(token)
// 需要修改session // 需要修改session
if ok { if ok {
c.UpdateSession("Verified", "1") c.UpdateSession("Verified", "1");
} }
c.RenderArgs["title"] = "验证邮箱" c.RenderArgs["title"] = "验证邮箱"
@@ -132,15 +147,36 @@ func (c User) ActiveEmail(token string) revel.Result {
return c.RenderTemplate("user/active_email.html") 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)
}
//----------------- //-----------------
// 用户偏爱 // 用户偏爱
func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int) revel.Result { func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth) re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth)
if re.Ok { if re.Ok {
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth)) c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth)) c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth)) c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth));
LogJ(c.Session) LogJ(c.Session)
} }
@@ -151,9 +187,9 @@ func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin) re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin)
if re.Ok { if re.Ok {
if leftIsMin { if leftIsMin {
c.UpdateSession("LeftIsMin", "1") c.UpdateSession("LeftIsMin", "1");
} else { } else {
c.UpdateSession("LeftIsMin", "0") c.UpdateSession("LeftIsMin", "0");
} }
} }
return c.RenderJson(re) return c.RenderJson(re)
+5 -5
View File
@@ -4,8 +4,8 @@ import (
// "github.com/revel/revel" // "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson" // "gopkg.in/mgo.v2/bson"
// "encoding/json" // "encoding/json"
"github.com/leanote/leanote/app/controllers"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/controllers"
// "io/ioutil" // "io/ioutil"
// "fmt" // "fmt"
// "math" // "math"
@@ -24,19 +24,19 @@ func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter
sorter := "" sorter := ""
c.Params.Bind(&sorter, "sorter") c.Params.Bind(&sorter, "sorter")
if sorter == "" { if sorter == "" {
return sorterField, isAsc return sorterField, isAsc;
} }
// sorter形式 email-up, email-down // sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-") s2 := strings.Split(sorter, "-")
if len(s2) != 2 { if len(s2) != 2 {
return sorterField, isAsc return sorterField, isAsc;
} }
// 必须是可用的sorter // 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 { if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) { if !InArray(okSorter, s2[0]) {
return sorterField, isAsc return sorterField, isAsc;
} }
} }
@@ -47,7 +47,7 @@ func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter
isAsc = false isAsc = false
} }
c.RenderArgs["sorter"] = sorter c.RenderArgs["sorter"] = sorter
return sorterField, isAsc return sorterField, isAsc;
} }
func (c AdminBaseController) updateConfig(keys []string) { func (c AdminBaseController) updateConfig(keys []string) {
+4 -4
View File
@@ -15,16 +15,16 @@ type AdminBlog struct {
// admin 主页 // admin 主页
func (c AdminBlog) Index(sorter, keywords string) revel.Result { func (c AdminBlog) Index(sorter, keywords string) revel.Result {
pageNumber := c.GetPage() pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"}) sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc) pageInfo, blogs := blogService.ListAllBlogs("", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
c.RenderArgs["pageInfo"] = pageInfo c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords 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 { func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok = blogService.SetRecommend(noteId, recommend) re.Ok = blogService.SetRecommend(noteId, recommend);
return c.RenderJson(re) return c.RenderJson(re)
} }
+4 -5
View File
@@ -18,10 +18,10 @@ func (c Admin) Index() revel.Result {
c.SetLocale() c.SetLocale()
c.RenderArgs["countUser"] = userService.CountUser() c.RenderArgs["countUser"] = userService.CountUser()
c.RenderArgs["countNote"] = noteService.CountNote("") c.RenderArgs["countNote"] = noteService.CountNote()
c.RenderArgs["countBlog"] = noteService.CountBlog("") c.RenderArgs["countBlog"] = noteService.CountBlog()
return c.RenderTemplate("admin/index.html") return c.RenderTemplate("admin/index.html");
} }
// 模板 // 模板
@@ -30,10 +30,9 @@ func (c Admin) T(t string) revel.Result {
c.RenderArgs["arr"] = configService.GlobalArrayConfigs c.RenderArgs["arr"] = configService.GlobalArrayConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs c.RenderArgs["map"] = configService.GlobalMapConfigs
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
c.RenderArgs["version"] = configService.GetVersion()
return c.RenderTemplate("admin/" + t + ".html") return c.RenderTemplate("admin/" + t + ".html")
} }
func (c Admin) GetView(view string) revel.Result { func (c Admin) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view) return c.RenderTemplate("admin/" + view);
} }
+5 -5
View File
@@ -1,13 +1,13 @@
package admin package admin
import ( import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"archive/tar" "archive/tar"
"compress/gzip" "compress/gzip"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"io"
"os" "os"
"io"
"time" "time"
) )
@@ -27,7 +27,7 @@ func (c AdminData) Index() revel.Result {
j++ j++
} }
c.RenderArgs["backups"] = backups2 c.RenderArgs["backups"] = backups2
return c.RenderTemplate("admin/data/index.html") return c.RenderTemplate("admin/data/index.html");
} }
func (c AdminData) Backup() revel.Result { func (c AdminData) Backup() revel.Result {
+22 -25
View File
@@ -1,11 +1,11 @@
package admin package admin
import ( import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
"strconv" . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"strings" "strings"
"strconv"
) )
// admin 首页 // admin 首页
@@ -25,7 +25,7 @@ func (c AdminEmail) Blog() revel.Result {
newTags := configService.GetGlobalArrayConfig("newTags") newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",") c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",") 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 { func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe() re := info.NewRe()
@@ -41,17 +41,14 @@ func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
func (c AdminEmail) Demo() revel.Result { func (c AdminEmail) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername") c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword") 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 { func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe() re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword) userInfo := authService.Login(demoUsername, demoPassword)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
}
if userInfo.UserId == "" { if userInfo.UserId == "" {
re.Msg = "The User is Not Exists" re.Msg = "The User is Not Exists";
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -66,7 +63,7 @@ func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
// 长微博的bin路径phantomJs // 长微博的bin路径phantomJs
func (c AdminEmail) ToImage() revel.Result { func (c AdminEmail) ToImage() revel.Result {
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath") 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 { func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
re := info.NewRe() re := info.NewRe()
@@ -74,13 +71,12 @@ func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
return c.RenderJson(re) return c.RenderJson(re)
} }
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emailSSL string) revel.Result { func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword string) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -133,13 +129,13 @@ func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmai
if saveAsOldEmail { if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails") oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails) configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
} }
sendEmails = strings.Replace(sendEmails, "\r", "", -1) sendEmails = strings.Replace(sendEmails, "\r", "", -1)
emails := strings.Split(sendEmails, "\n") 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) return c.RenderJson(re)
} }
@@ -157,7 +153,7 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
if saveAsOldEmail { if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails") oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails) configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
} }
emails = strings.Replace(emails, "\r", "", -1) emails = strings.Replace(emails, "\r", "", -1)
@@ -166,7 +162,8 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
users := userService.ListUserInfosByEmails(emailsArr) users := userService.ListUserInfosByEmails(emailsArr)
LogJ(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) return c.RenderJson(re)
} }
@@ -180,7 +177,7 @@ func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs 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 { func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilterBlackList, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
@@ -196,19 +193,19 @@ func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilter
if saveAsOldEmail { if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails") oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails) configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
} }
users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified) users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified)
if users == nil || len(users) == 0 { if(users == nil || len(users) == 0) {
re.Ok = false re.Ok = false
re.Msg = "no users" re.Msg = "no users"
return c.RenderJson(re) return c.RenderJson(re)
} }
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody) re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
if !re.Ok { if(!re.Ok) {
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -227,10 +224,10 @@ func (c AdminEmail) DeleteEmails(ids string) revel.Result {
func (c AdminEmail) List(sorter, keywords string) revel.Result { func (c AdminEmail) List(sorter, keywords string) revel.Result {
pageNumber := c.GetPage() pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"}) sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"});
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords) pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords);
c.RenderArgs["pageInfo"] = pageInfo c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["emails"] = emails c.RenderArgs["emails"] = emails
c.RenderArgs["keywords"] = keywords c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/email/list.html") return c.RenderTemplate("admin/email/list.html");
} }
+13 -36
View File
@@ -3,7 +3,6 @@ package admin
import ( import (
"github.com/revel/revel" "github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"fmt"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"strings" "strings"
) )
@@ -25,7 +24,7 @@ func (c AdminSetting) Blog() revel.Result {
newTags := configService.GetGlobalArrayConfig("newTags") newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",") c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",") 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 { func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe() re := info.NewRe()
@@ -42,7 +41,7 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result { registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result {
re := info.NewRe() 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) return c.RenderJson(re)
} }
@@ -51,18 +50,14 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
func (c AdminSetting) Demo() revel.Result { func (c AdminSetting) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername") c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword") 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 { func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe() re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword) userInfo := authService.Login(demoUsername, demoPassword)
if err != nil {
fmt.Println(err)
return c.RenderJson(info.Re{Ok: false})
}
if userInfo.UserId == "" { if userInfo.UserId == "" {
re.Msg = "The User is Not Exists" re.Msg = "The User is Not Exists";
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -73,15 +68,15 @@ func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
return c.RenderJson(re) return c.RenderJson(re)
} }
func (c AdminSetting) ExportPdf(path string) revel.Result { // ToImage
re := info.NewRe() // 长微博的bin路径phantomJs
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path) func (c AdminSetting) ToImage() revel.Result {
return c.RenderJson(re) c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
return c.RenderTemplate("admin/setting/toImage.html");
} }
func (c AdminSetting) DoToImage(toImageBinPath string) revel.Result {
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
return c.RenderJson(re) return c.RenderJson(re)
} }
@@ -94,7 +89,7 @@ func (c AdminSetting) SubDomain() revel.Result {
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain") c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain") 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 { func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, blackSubDomains, allowCustomDomain, blackCustomDomains string) revel.Result {
re := info.NewRe() re := info.NewRe()
@@ -115,15 +110,6 @@ func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
return c.RenderJson(re) return c.RenderJson(re)
} }
func (c AdminSetting) HomePage(homePage string) revel.Result {
re := info.NewRe()
if homePage == "0" {
homePage = ""
}
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
return c.RenderJson(re)
}
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result { func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
re := info.NewRe() re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath) re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
@@ -131,12 +117,3 @@ func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Resu
return c.RenderJson(re) return c.RenderJson(re)
} }
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadImageSize", fmt.Sprintf("%v", uploadImageSize))
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
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)
}
@@ -3,7 +3,7 @@ package admin
import ( import (
"github.com/revel/revel" "github.com/revel/revel"
// "encoding/json" // "encoding/json"
"github.com/leanote/leanote/app/info" // . "github.com/leanote/leanote/app/lea"
// "io/ioutil" // "io/ioutil"
) )
@@ -14,17 +14,5 @@ type AdminUpgrade struct {
func (c AdminUpgrade) UpgradeBlog() revel.Result { func (c AdminUpgrade) UpgradeBlog() revel.Result {
upgradeService.UpgradeBlog() upgradeService.UpgradeBlog()
return nil return nil;
}
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
re := info.NewRe()
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
return c.RenderJson(re)
}
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
re := info.NewRe()
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
return c.RenderJson(re)
} }
+6 -45
View File
@@ -1,10 +1,8 @@
package admin package admin
import ( import (
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
// "time" // . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
) )
// admin 首页 // admin 首页
@@ -15,53 +13,16 @@ type AdminUser struct {
// admin 主页 // admin 主页
var userPageSize = 10 var userPageSize = 10
func (c AdminUser) Index(sorter, keywords string) revel.Result {
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
pageNumber := c.GetPage() pageNumber := c.GetPage()
if userPageSize == 0 { sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
pageSize = userPageSize pageInfo, users := userService.ListUsers(pageNumber, userPageSize, 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["pageInfo"] = pageInfo
c.RenderArgs["users"] = users c.RenderArgs["users"] = users
c.RenderArgs["keywords"] = keywords c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/user/list.html") return c.RenderTemplate("admin/user/list.html");
} }
func (c AdminUser) Add() revel.Result { 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()
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 = authService.Register(email, pwd, "")
return c.RenderRe(re)
}
// 修改帐户
func (c AdminUser) ResetPwd(userId string) revel.Result {
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
return c.RenderTemplate("admin/user/reset_pwd.html")
}
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
re := info.NewRe()
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
}
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
return c.RenderRe(re)
} }
+4 -4
View File
@@ -1,8 +1,8 @@
package admin package admin
import ( import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service" "github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
// "strings" // "strings"
@@ -28,6 +28,7 @@ var configService *service.ConfigService
var emailService *service.EmailService var emailService *service.EmailService
var upgradeService *service.UpgradeService var upgradeService *service.UpgradeService
var adminUsername = "admin"
// 拦截器 // 拦截器
// 不需要拦截的url // 不需要拦截的url
// Index 除了Note之外都不需要 // Index 除了Note之外都不需要
@@ -56,7 +57,6 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"File": map[string]bool{"OutputImage": true, "OutputFile": true}, "File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true, "DownloadAll": true}, "Attach": map[string]bool{"Download": true, "DownloadAll": true},
} }
func needValidate(controller, method string) bool { func needValidate(controller, method string) bool {
// 在里面 // 在里面
if v, ok := commonUrl[controller]; ok { if v, ok := commonUrl[controller]; ok {
@@ -67,7 +67,7 @@ func needValidate(controller, method string) bool {
return true return true
} else { } else {
// controller不在这里的, 肯定要验证 // controller不在这里的, 肯定要验证
return true return true;
} }
} }
func AuthInterceptor(c *revel.Controller) revel.Result { func AuthInterceptor(c *revel.Controller) revel.Result {
@@ -83,7 +83,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
// 验证是否已登录 // 验证是否已登录
// 必须是管理员 // 必须是管理员
if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() { if username, ok := c.Session["Username"]; ok && username == adminUsername {
return nil // 已登录 return nil // 已登录
} }
-465
View File
@@ -1,465 +0,0 @@
# API 列表
## 前言
### api url
所有api的url前面带/api/, 如:
`/api/user/info?userId=xxxx&token=xxxx`
除了/auth/login, /auth/register外其它的都需要另外带参数token=xxxx
### 文件目录结构
* 所有API的Controller都在app/api文件夹下
* 文件命名: Api功能Controller.go, 如ApiUserController.go
* 结构体命名为 Api功能, 如ApiUser
* API公用Controller: ApiBaseController
* init.go 注入service和定义拦截器
### 流程
用户登录后返回一个token, 以后所有的请求都携带该token.
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
## 返回值结构
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
* 错误信息全部返回 {Ok: false, Msg: "相应的错误信息"}
* 正确信息返回分两种:
1. 一些操作型的api, 比如updateUsername, updateLogo之类的, 成功后返回 {Ok: true, Msg:""}
2. 一些获取型api, 如getNote, 全部返回真实的返回数据, 如返回笔记:
```
{
"NoteId": "54bdc7e305fcd13ea3000000",
"NotebookId": "54bdc65599c37b0da9000003",
"UserId": "54bdc65599c37b0da9000002",
"Title": "笔记标题",
"Desc": "",
"Tags": null,
"Abstract": "",
"Content": "",
"IsMarkdown": false,
"IsBlog": false,
"IsTrash": true,
"IsDeleted": false,
"Usn": 15,
"Files": [],
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
"PublicTime": "0001-01-01T00:00:00Z"
}
```
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
-----------------
## Auth 登录与注册
### /auth/login 登录
```
参数: email, pwd
Method: GET
返回:
错误: {"Ok":false, "Msg":"用户名或密码有误"}
正确: 比如:
{
"Ok":true,
"Token":"5500830738f41138e90003232",
"UserId":"52d26b4e99c37b609a000001",
"Email":"leanote@leanote.com",
"Username":"leanote"
}
```
登录成功后将使用token作为之后的请求
### /auth/logout 注销
```
参数: token
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: {Ok: true, Msg: ""}
```
### /auth/register 注册
```
参数: email, pwd
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: {Ok: true, Msg: ""}
```
## User 用户
### /user/info 获取用户信息
```
参数: userId
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: type.User
```
### /user/updateUsername 修改用户名
```
参数: username(新用户名)
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: {Ok: true, Msg: ""}
```
### /user/updatePwd 修改密码
```
参数: oldPwd(旧密码), pwd(新密码)
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: {Ok: true, Msg: ""}
```
### /user/updateLogo 修改头像
```
参数: file(文件)
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: {Ok: true, Msg: ""}
```
### /user/getSyncState 获取最新同步状态
```
参数: 无
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: {LastSyncUsn: 3232, LastSyncTime: "上次同步时间"(暂时无用)}
```
-----
## Notebook 笔记本
### /notebook/getSyncNotebooks 得到需要同步的笔记本
```
参数: afterUsn(int, 在此usn后的笔记本是需要同步的), maxEntry(int, 最大要同步的量)
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: [type.Notebook] 数组
```
### /notebook/getNotebooks 得到所有笔记本
```
无参数
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: [type.Notebook] 数组
```
### /notebook/addNotebook 添加笔记本
```
参数: title(string), parentNotebookId(string, 父notebookId, 可空), seq(int) 排列
Method: POST
返回:
错误: {Ok: false, Msg:""}
成功: type.Notebook
```
### /notebook/updateNotebook 修改笔记本
```
参数: notebookId, title, parentNotebookId, seq(int), usn(int)
Method: POST
返回:
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
成功: type.Notebook
```
### /notebook/deleteNotebook 删除笔记本
```
参数: notebookId, usn(int)
Method: GET
返回:
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
成功: {Ok: true}
```
----
## Note 笔记
### /note/getSyncNotes 获取需要同步的笔记
```
参数: afterUsn(int, 在此usn后的笔记是需要同步的), maxEntry(int, 最大要同步的量)
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: [type.Note] 数组, 笔记不包含Abstract和Content
```
### /note/getNotes 获得某笔记本下的笔记(无内容)
```
参数: notebookId
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: [type.Note] 数组, 笔记不包含Abstract和Content
```
### /note/getNoteAndContent 获得笔记与内容
```
参数: noteId
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: type.Note
```
### /note/getNoteContent 获得笔记内容
```
参数: noteId
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: type.NoteContent
```
### /note/addNote 添加笔记
```
参数: (注意首字大写)
NotebookId string 必传
Title string 必传
Tags []string 可选
Content string 必传
Abstract string 可选, 当是markdown笔记时必须传
IsMarkdown bool 可选
Files []type.NoteFiles 数组 可选
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: type.Note, 不包含Abstract, Content
```
** 关于笔记中的图片/附件**
客户端应该添加一个"图片/附件表"来存元数据, 图片应该要缓存到本地, 附件可在需要的时候再调用相应api获取.
Content中的数据, 图片,附件在Leanote的链接是, 所以, 不管你在本地的笔记中是以什么形式来保存图片,附件的链接的,请addNote和updateNote时务必将链接修改成leanote服务器上的链接.
http://leanote.com/api/file/getImage?fileId=xx
单个附件:
http://leanote.com/api/file/getAttach?fileId=xx
所有附件:
http://leanote.com/api/file/getAllAttachs?noteId=xxx
**注意:**
addNote时必须要把Files, 和相关的图片/附件一起传到服务器中
其中Files(文件的元数据)和其它字段以POST方式传出, 而真正数据则以http的multipart传入, 每个文件的name为"FileDatas[LocalFileId]"
图片在笔记内的链接必须为: http://leanote.com/api/file/getImage?fileId=LocalFileId或FileId
附件如果插入到了笔记内容内, 其链接必须为: http://leanote.com/api/file/getAttach?fileId=LocalFileId或FileId
其中, fileId为文件在本地的LocalFileId或服务器上的FileId
服务器端会生成FileId传给Client. Client在本地必须要建立LocalFileId与FileId的关联.
如果笔记内容传了, 且笔记内有图片, 则必须要传Files 文件元数据, 因为Server端还要对内容内的图片, 附件链接进行修改, 可能你传过去的是LocalFileId, 服务器端会将LocalFileId替换成FileId存到数据库中.
同样适用于 updateNote
http://leanote.com 不绝对, 因为用户可以自建服务, 所以在开发时需要可配置
### /note/updateNote 更新笔记
当更新了笔记某个属性时, 只要传某个属性就行, 其它不用传, 比如把笔记拉入了trash, 那么就传IsTrash: true
```
参数: (注意首字大写)
NoteId string 必传
Usn int 必传
NotebookId string 可选
Title string 可选
Tags []string 可选
Content string 可选
Abstract string 可选, 当是markdown笔记时必须传
IsMarkdown bool 可选
IsTrash bool 是否是trash 可选
Files []type.NoteFiles 数组 可选
Method: POST
返回:
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
成功: type.Note, 不包含Abstract和Content
```
### /note/deleteTrash 彻底删除笔记
```
参数: noteId, usn
Method: GET
返回:
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
成功: type.UpdateRet
```
-------
## Tag 标签
### /tag/getSyncTags 获取需要同步的标签
```
参数: afterUsn(int, 在此usn后的标签是需要同步的), maxEntry(int, 最大要同步的量)
Method: GET
返回:
错误: {Ok: false, Msg: ""}
成功: [type.Tag] 数组
```
### /tag/addTag 添加标签
```
参数: tag(string)
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: type.Tag
```
### /tag/deleteTag 删除标签
```
参数: tag(string)
Method: POST
返回:
错误: {Ok: false, Msg: ""}
成功: type.UpdateRet
```
### File 文件(获取图片, 附件)
### /file/getImage 获取图片
```
参数: fileId
Method: GET
返回:
错误: 非二进制文件数据
成功: 二进制文件
```
### /file/getAttach 获取附件
```
参数: fileId
Method: GET
返回:
错误: 非二进制文件数据
成功: 二进制文件
```
### /file/getAllAttachs 获取所有附件
```
参数: noteId
Method: GET
返回:
错误: 非二进制文件数据
成功: 二进制文件
```
--------
## 数据类型
### type.User 用户信息
```
User {
UserId string
Username string
Email string
Verified bool
Logo string
}
```
### type.Notebook 笔记本
```
Notebook {
NotebookId
UserId
ParentNotebookId // 上级
Seq int // 排序
Title string
IsBlog bool
IsDeleted bool
CreatedTime time.Time
UpdatedTime time.Time
// 更新序号
Usn int // UpdateSequenceNum
}
```
### type.Note 笔记
```
Note {
NoteId string
NotebookId string
UserId string
Title string
Tags []string
Content string
IsMarkdown bool
IsBlog bool
IsTrash bool
Files []NoteFile // 图片, 附件
CreatedTime time.Time
UpdatedTime time.Time
PublicTime time.Time
// 更新序号
Usn int
}
```
### type.NoteContent 笔记内容
```
NoteContent {
NoteId string
UserId string
Content string
}
```
### type.NoteFile 笔记文件(图片,附件)
```
NoteFile {
FileId string // 服务器端Id
LocalFileId string // 客户端Id
Type string // images/png, doc, xls, 根据fileName确定
Title string
HasBody bool // 传过来的值是否要更新内容, 如果有true, 则必须传文件
IsAttach bool // 是否是附件, 不是附件就是图片
}
```
### type.Tag 标签
```
Tag {
TagId string
UserId string
Tag string
CreatedTime
UpdatedTime
IsDeleted bool // 删除位
// 更新序号
Usn
}
```
### type.UpdateRe 更新后返回的值, 包含Usn
```
ReUpdate {
Ok bool
Msg string
// 更新序号
Usn int
}
```
-47
View File
@@ -1,47 +0,0 @@
# API设计
By life (life@leanote.com)
## api url
所有api的url前面带/api/, 如:
`/api/user/info?userId=xxxx&token=xxxx`
## 文件目录结构
* 所有API的Controller都在app/api文件夹下
* 文件命名: Api功能Controller.go, 如ApiUserController.go
* 结构体命名为 Api功能, 如ApiUser
* API公用Controller: ApiBaseController
* init.go 注入service和定义拦截器
## 流程
用户登录后返回一个token, 以后所有的请求都携带该token.
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
## 返回值结构
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
* 错误信息全部返回 {Ok: false, Msg: ""}
* 正确信息全部返回真实的返回数据, 如返回笔记:
```
{
"NoteId": "54bdc7e305fcd13ea3000000",
"NotebookId": "54bdc65599c37b0da9000003",
"UserId": "54bdc65599c37b0da9000002",
"Title": "asdfads",
"Desc": "",
"Tags": null,
"Abstract": "",
"Content": "",
"IsMarkdown": false,
"IsBlog": false,
"IsTrash": true,
"IsDeleted": false,
"Usn": 15,
"Files": [],
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
"PublicTime": "0001-01-01T00:00:00Z"
}
```
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
+114 -28
View File
@@ -1,10 +1,9 @@
package api package api
import ( import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// "strconv" // "strconv"
) )
@@ -17,53 +16,140 @@ type ApiAuth struct {
ApiBaseContrller ApiBaseContrller
} }
// 登录 // 为了demo和register
// [ok] func (c ApiAuth) doLogin(email, pwd string) revel.Result {
// 成功返回 {Ok: true, Item: token } sessionId := c.Session.Id()
// 失败返回 {Ok: false, Msg: ""}
func (c ApiAuth) Login(email, pwd string) revel.Result {
var msg = "" var msg = ""
userInfo, err := authService.Login(email, pwd) userInfo := authService.Login(email, pwd)
if err == nil { if userInfo.Email != "" {
token := bson.NewObjectId().Hex() c.SetSession(userInfo)
sessionService.SetUserId(token, userInfo.UserId.Hex()) sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username}) return c.RenderJson(info.Re{Ok: true})
} else { } else {
// 登录错误, 则错误次数++ // 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword" msg = "wrongUsernameOrPassword"
} }
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
}
func (c ApiAuth) Login(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 {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
sessionService.IncrLoginTimes(sessionId)
}
}
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
} }
// 注销 // 注销
// [Ok]
func (c ApiAuth) Logout() revel.Result { func (c ApiAuth) Logout() revel.Result {
token := c.getToken() sessionId := c.Session.Id()
sessionService.Clear(token) sessionService.Clear(sessionId)
re := info.NewApiRe() c.ClearSession()
re := info.NewRe()
re.Ok = true re.Ok = true
return c.RenderJson(re) return c.RenderJson(re)
} }
// 注册 // 体验一下
// [Ok] func (c ApiAuth) Demo() revel.Result {
// 成功后并不返回用户ID, 需要用户重新登录 c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
func (c ApiAuth) Register(email, pwd string) revel.Result { return c.Redirect("/note")
re := info.NewApiRe()
if !configService.IsOpenRegister() {
re.Msg = "notOpenRegister" // 未开放注册
return c.RenderJson(re)
} }
//--------
// 注册
func (c ApiAuth) Register(from string) revel.Result {
if !configService.IsOpenRegister() {
return c.Redirect("/index")
}
c.SetLocale()
c.RenderArgs["from"] = from
c.RenderArgs["title"] = c.Message("register")
c.RenderArgs["subTitle"] = c.Message("register")
return c.RenderTemplate("home/register.html")
}
func (c ApiAuth) DoRegister(email, pwd string) revel.Result {
if !configService.IsOpenRegister() {
return c.Redirect("/index")
}
re := info.NewRe();
if re.Ok, re.Msg = Vd("email", email); !re.Ok { if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderJson(re) return c.RenderRe(re);
} }
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok { if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re) return c.RenderRe(re);
} }
// 注册 // 注册
re.Ok, re.Msg = authService.Register(email, pwd, "") re.Ok, re.Msg = authService.Register(email, pwd)
// 注册成功, 则立即登录之
if re.Ok {
c.doLogin(email, pwd)
}
return c.RenderRe(re)
}
//--------
// 找回密码
func (c ApiAuth) FindPassword() revel.Result {
c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword")
return c.RenderTemplate("home/find_password.html")
}
func (c ApiAuth) DoFindPassword(email string) revel.Result {
pwdService.FindPwd(email)
re := info.NewRe()
re.Ok = true
return c.RenderJson(re) return c.RenderJson(re)
} }
// 点击链接后, 先验证之
func (c ApiAuth) FindPassword2(token string) revel.Result {
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);
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 ApiAuth) FindPasswordUpdate(token, pwd string) revel.Result {
re := info.NewRe();
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re);
}
// 修改之
re.Ok, re.Msg = pwdService.UpdatePwd(token, pwd)
return c.RenderRe(re)
}
+5 -175
View File
@@ -1,189 +1,19 @@
package api package api
import ( import (
"github.com/revel/revel" // "github.com/revel/revel"
"gopkg.in/mgo.v2/bson" // "gopkg.in/mgo.v2/bson"
// "encoding/json" // "encoding/json"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/controllers" "github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/info" // "io/ioutil"
. "github.com/leanote/leanote/app/lea"
"os"
// "fmt"
"io/ioutil"
// "fmt" // "fmt"
// "math" // "math"
// "strconv" // "strconv"
"strings" // "strings"
) )
// 公用Controller, 其它Controller继承它 // 公用Controller, 其它Controller继承它
type ApiBaseContrller struct { type ApiBaseContrller struct {
controllers.BaseController // 不能用*BaseController controllers.BaseController // 不能用*BaseController
} }
// 得到token, 这个token是在AuthInterceptor设到Session中的
func (c ApiBaseContrller) getToken() string {
return c.Session["_token"]
}
// userId
// _userId是在AuthInterceptor设置的
func (c ApiBaseContrller) getUserId() string {
return c.Session["_userId"]
}
// 得到用户信息
func (c ApiBaseContrller) getUserInfo() info.User {
userId := c.Session["_userId"]
if userId == "" {
return info.User{}
}
return userService.GetUserInfo(userId)
}
// 上传附件
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
userId := c.getUserId()
// 判断是否有权限为笔记添加附件
// 如果笔记还没有添加是不是会有问题
/*
if !shareService.HasUpdateNotePerm(noteId, userId) {
return
}
*/
file, handel, err := c.Request.FormFile(name)
if err != nil {
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return
}
// > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
if float64(len(data)) > maxFileSize*float64(1024*1024) {
msg = "fileIsTooLarge"
return
}
// 生成上传路径
newGuid := NewGuid()
// filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
filePath := "files/" + GetRandomFilePath(userId, newGuid) + "/attachs"
dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755)
if err != nil {
return
}
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename) // .doc
filename = newGuid + ext
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return
}
// add File to db
fileType := ""
if ext != "" {
fileType = strings.ToLower(ext[1:])
}
filesize := GetFilesize(toPath)
fileInfo := info.Attach{AttachId: bson.NewObjectId(),
Name: filename,
Title: handel.Filename,
NoteId: bson.ObjectIdHex(noteId),
UploadUserId: bson.ObjectIdHex(userId),
Path: filePath + "/" + filename,
Type: fileType,
Size: filesize}
ok, msg = attachService.AddAttach(fileInfo, true)
if !ok {
return
}
id = fileInfo.AttachId.Hex()
return
}
// 上传图片
func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok bool, msg string, id string) {
if isAttach {
return c.uploadAttach(name, noteId)
}
file, handel, err := c.Request.FormFile(name)
if err != nil {
return
}
defer file.Close()
newGuid := NewGuid()
// 生成上传路径
userId := c.getUserId()
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
return
}
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename)
// if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
// msg = "notImage"
// return
// }
filename = newGuid + ext
data, err := ioutil.ReadAll(file)
if err != nil {
return
}
maxFileSize := configService.GetUploadSize("uploadImageSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
// > 2M?
if float64(len(data)) > maxFileSize*float64(1024*1024) {
msg = "fileIsTooLarge"
return
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return
}
// 改变成gif图片
_, toPathGif := TransToGif(toPath, 0, true)
filename = GetFilename(toPathGif)
filesize := GetFilesize(toPathGif)
fileUrlPath += "/" + filename
// File
fileInfo := info.File{FileId: bson.NewObjectId(),
Name: filename,
Title: handel.Filename,
Path: fileUrlPath,
Size: filesize}
ok, msg = fileService.AddImage(fileInfo, "", c.getUserId(), true)
if ok {
id = fileInfo.FileId.Hex()
}
return
}
-163
View File
@@ -1,163 +0,0 @@
package api
import (
"github.com/revel/revel"
// "encoding/json"
// . "github.com/leanote/leanote/app/lea"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/lea/netutil"
// "github.com/leanote/leanote/app/info"
// "io/ioutil"
"os"
// "strconv"
"archive/tar"
"compress/gzip"
"io"
"strings"
"time"
)
// 文件操作, 图片, 头像上传, 输出
type ApiFile struct {
ApiBaseContrller
}
/*
// 协作时复制图片到owner
func (c ApiFile) CopyImage(userId, fileId, toUserId string) revel.Result {
re := info.NewRe()
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
return c.RenderJson(re)
}
// get all images by userId with page
func (c ApiFile) GetImages(albumId, key string, page int) revel.Result {
imagesPage := fileService.ListImagesWithPage(c.getUserId(), albumId, key, page, 12)
re := info.NewRe()
re.Ok = true
re.Item = imagesPage
return c.RenderJson(re)
}
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
re := info.NewRe()
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
return c.RenderJson(re)
}
func (c ApiFile) DeleteImage(fileId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
return c.RenderJson(re)
}
*/
//-----------
// 输出image
// [OK]
func (c ApiFile) GetImage(fileId string) revel.Result {
path := fileService.GetFile(c.getUserId(), fileId) // 得到路径
if path == "" {
return c.RenderText("")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderFile(file, revel.Inline) // revel.Attachment
}
// 下载附件
// [OK]
func (c ApiFile) GetAttach(fileId string) revel.Result {
attach := attachService.GetAttach(fileId, c.getUserId()) // 得到路径
path := attach.Path
if path == "" {
return c.RenderText("No Such File")
}
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
file, _ := os.Open(fn)
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
}
// 下载所有附件
// [OK]
func (c ApiFile) GetAllAttachs(noteId string) revel.Result {
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
return c.RenderText("")
}
// 得到文件列表
attachs := attachService.ListAttachs(noteId, c.getUserId())
if attachs == nil || len(attachs) == 0 {
return c.RenderText("")
}
/*
dir := revel.BasePath + "/files/tmp"
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderText("")
}
*/
filename := note.Title + ".tar.gz"
if note.Title == "" {
filename = "all.tar.gz"
}
// file write
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
// gzip write
gw := gzip.NewWriter(fw)
defer gw.Close()
// tar write
tw := tar.NewWriter(gw)
defer tw.Close()
// 遍历文件列表
for _, attach := range attachs {
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
fr, err := os.Open(fn)
fileInfo, _ := fr.Stat()
if err != nil {
return c.RenderText("")
}
defer fr.Close()
// 信息头
h := new(tar.Header)
h.Name = attach.Title
h.Size = fileInfo.Size()
h.Mode = int64(fileInfo.Mode())
h.ModTime = fileInfo.ModTime()
// 写信息头
err = tw.WriteHeader(h)
if err != nil {
panic(err)
}
// 写文件
_, err = io.Copy(tw, fr)
if err != nil {
panic(err)
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// fw.Seek(0, 0)
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
}
-642
View File
@@ -1,642 +0,0 @@
package api
import (
"github.com/revel/revel"
// "encoding/json"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"os"
"os/exec"
// "strings"
"time"
"regexp"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "bytes"
// "os"
)
// 笔记API
type ApiNote struct {
ApiBaseContrller
}
// 获取同步的笔记
// > afterUsn的笔记
// 无Desc, Abstract, 有Files
/*
{
"NoteId": "55195fa199c37b79be000005",
"NotebookId": "55195fa199c37b79be000002",
"UserId": "55195fa199c37b79be000001",
"Title": "Leanote语法Leanote语法Leanote语法Leanote语法Leanote语法",
"Desc": "",
"Tags": null,
"Abstract": "",
"Content": "",
"IsMarkdown": true,
"IsBlog": false,
"IsTrash": false,
"Usn": 5,
"Files": [],
"CreatedTime": "2015-03-30T22:37:21.695+08:00",
"UpdatedTime": "2015-03-30T22:37:21.724+08:00",
"PublicTime": "2015-03-30T22:37:21.695+08:00"
}
*/
func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
if maxEntry == 0 {
maxEntry = 100
}
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(notes)
}
// 得到笔记本下的笔记
// [OK]
func (c ApiNote) GetNotes(notebookId string) revel.Result {
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
re := info.NewApiRe()
re.Msg = "notebookIdInvalid"
return c.RenderJson(re)
}
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(noteService.ToApiNotes(notes))
}
// 得到trash
// [OK]
func (c ApiNote) GetTrashNotes() revel.Result {
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
return c.RenderJson(noteService.ToApiNotes(notes))
}
// get Note
// [OK]
/*
{
"NoteId": "550c0bee2ec82a2eb5000000",
"NotebookId": "54a1676399c37b1c77000004",
"UserId": "54a1676399c37b1c77000002",
"Title": "asdfadsf--=",
"Desc": "",
"Tags": [
],
"Abstract": "",
"Content": "",
"IsMarkdown": false,
"IsBlog": false,
"IsTrash": false,
"Usn": 8,
"Files": [
{
"FileId": "551975d599c37b970f000000",
"LocalFileId": "",
"Type": "",
"Title": "",
"HasBody": false,
"IsAttach": false
},
{
"FileId": "551975de99c37b970f000001",
"LocalFileId": "",
"Type": "doc",
"Title": "李铁-print-en.doc",
"HasBody": false,
"IsAttach": true
},
{
"FileId": "551975de99c37b970f000002",
"LocalFileId": "",
"Type": "doc",
"Title": "李铁-print.doc",
"HasBody": false,
"IsAttach": true
}
],
"CreatedTime": "2015-03-20T20:00:52.463+08:00",
"UpdatedTime": "2015-03-31T00:12:44.967+08:00",
"PublicTime": "2015-03-20T20:00:52.463+08:00"
}
*/
func (c ApiNote) GetNote(noteId string) revel.Result {
if !bson.IsObjectIdHex(noteId) {
re := info.NewApiRe()
re.Msg = "noteIdInvalid"
return c.RenderJson(re)
}
note := noteService.GetNote(noteId, c.getUserId())
if note.NoteId == "" {
re := info.NewApiRe()
re.Msg = "notExists"
return c.RenderJson(re)
}
apiNotes := noteService.ToApiNotes([]info.Note{note})
return c.RenderJson(apiNotes[0])
}
// 得到note和内容
// [OK]
func (c ApiNote) GetNoteAndContent(noteId string) revel.Result {
noteAndContent := noteService.GetNoteAndContent(noteId, c.getUserId())
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
apiNote := apiNotes[0]
apiNote.Content = noteService.FixContent(noteAndContent.Content, noteAndContent.IsMarkdown)
return c.RenderJson(apiNote)
}
// content里的image, attach链接是
// https://leanote.com/api/file/getImage?fileId=xx
// https://leanote.com/api/file/getAttach?fileId=xx
// 将fileId=映射成ServerFileId, 这里的fileId可能是本地的FileId
func (c ApiNote) fixPostNotecontent(noteOrContent *info.ApiNote) {
if noteOrContent.Content == "" {
return
}
files := noteOrContent.Files
if files != nil && len(files) > 0 {
for _, file := range files {
if file.LocalFileId != "" {
LogJ(file)
if !file.IsAttach {
// <img src="https://"
// ![](http://demo.leanote.top/api/file/getImage?fileId=5863219465b68e4fd5000001)
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)
*/
}
}
}
}
}
// 得到内容
func (c ApiNote) GetNoteContent(noteId string) revel.Result {
userId := c.getUserId()
note := noteService.GetNote(noteId, userId)
// re := info.NewRe()
noteContent := noteService.GetNoteContent(noteId, userId)
if noteContent.Content != "" {
noteContent.Content = noteService.FixContent(noteContent.Content, note.IsMarkdown)
}
apiNoteContent := info.ApiNoteContent{
NoteId: noteContent.NoteId,
UserId: noteContent.UserId,
Content: noteContent.Content,
}
return c.RenderJson(apiNoteContent)
}
// 添加笔记
// [OK]
func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
userId := bson.ObjectIdHex(c.getUserId())
re := info.NewRe()
myUserId := userId
// 为共享新建?
/*
if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
}
*/
// Log(noteOrContent.Title)
// LogJ(noteOrContent)
/*
LogJ(c.Params)
for name, _ := range c.Params.Files {
Log(name)
file, _, _ := c.Request.FormFile(name)
LogJ(file)
}
*/
// return c.RenderJson(re)
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
re.Msg = "notebookIdNotExists"
return c.RenderJson(re)
}
noteId := bson.NewObjectId()
// TODO 先上传图片/附件, 如果不成功, 则返回false
//
attachNum := 0
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
for i, file := range noteOrContent.Files {
if file.HasBody {
if file.LocalFileId != "" {
// FileDatas[54c7ae27d98d0329dd000000]
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId.Hex(), file.IsAttach)
if !ok {
re.Ok = false
if msg != "" {
Log(msg)
Log(file.LocalFileId)
re.Msg = "fileUploadError"
}
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
if msg != "notImage" {
return c.RenderJson(re)
}
} else {
// 建立映射
file.FileId = fileId
noteOrContent.Files[i] = file
if file.IsAttach {
attachNum++
}
}
} else {
return c.RenderJson(re)
}
}
}
}
c.fixPostNotecontent(&noteOrContent)
// Log("Add")
// LogJ(noteOrContent)
// return c.RenderJson(re)
note := info.Note{UserId: userId,
NoteId: noteId,
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
Title: noteOrContent.Title,
Tags: noteOrContent.Tags,
Desc: noteOrContent.Desc,
// ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown,
AttachNum: attachNum,
CreatedTime: noteOrContent.CreatedTime,
UpdatedTime: noteOrContent.UpdatedTime,
}
noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract,
CreatedTime: noteOrContent.CreatedTime,
UpdatedTime: noteOrContent.UpdatedTime,
}
// 通过内容得到Desc, abstract
if noteOrContent.Abstract == "" {
note.Desc = SubStringHTMLToRaw(noteContent.Content, 200)
noteContent.Abstract = SubStringHTML(noteContent.Content, 200, "")
} else {
note.Desc = SubStringHTMLToRaw(noteContent.Abstract, 200)
}
note = noteService.AddNoteAndContentApi(note, noteContent, myUserId)
if note.NoteId == "" {
re.Ok = false
return c.RenderJson(re)
}
// 添加需要返回的
noteOrContent.NoteId = note.NoteId.Hex()
noteOrContent.Usn = note.Usn
noteOrContent.CreatedTime = note.CreatedTime
noteOrContent.UpdatedTime = note.UpdatedTime
noteOrContent.UserId = c.getUserId()
noteOrContent.IsMarkdown = note.IsMarkdown
// 删除一些不要返回的, 删除Desc?
noteOrContent.Content = ""
noteOrContent.Abstract = ""
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
return c.RenderJson(noteOrContent)
}
// 更新笔记
// [OK]
func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
re := info.NewReUpdate()
noteUpdate := bson.M{}
needUpdateNote := false
noteId := noteOrContent.NoteId
if noteOrContent.NoteId == "" {
re.Msg = "noteIdNotExists"
return c.RenderJson(re)
}
if noteOrContent.Usn <= 0 {
re.Msg = "usnNotExists"
return c.RenderJson(re)
}
// Log("_____________")
// LogJ(noteOrContent)
/*
LogJ(c.Params.Files)
LogJ(c.Request.Header)
LogJ(c.Params.Values)
*/
// 先判断USN的问题, 因为很可能添加完附件后, 会有USN冲突, 这时附件就添错了
userId := c.getUserId()
note := noteService.GetNote(noteId, userId)
if note.NoteId == "" {
re.Msg = "notExists"
return c.RenderJson(re)
}
if note.Usn != noteOrContent.Usn {
re.Msg = "conflict"
Log("conflict")
return c.RenderJson(re)
}
Log("没有冲突")
// 如果传了files
// TODO 测试
/*
for key, v := range c.Params.Values {
Log(key)
Log(v)
}
*/
// Log(c.Has("Files[0]"))
if c.Has("Files[0][LocalFileId]") {
// LogJ(c.Params.Files)
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
for i, file := range noteOrContent.Files {
if file.HasBody {
if file.LocalFileId != "" {
// FileDatas[54c7ae27d98d0329dd000000]
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId, file.IsAttach)
if !ok {
Log("upload file error")
re.Ok = false
if msg == "" {
re.Msg = "fileUploadError"
} else {
re.Msg = msg
}
return c.RenderJson(re)
} else {
// 建立映射
file.FileId = fileId
noteOrContent.Files[i] = file
}
} else {
return c.RenderJson(re)
}
}
}
}
// Log("after upload")
// LogJ(noteOrContent.Files)
}
// 移到外面来, 删除最后一个file时也要处理, 不然总删不掉
// 附件问题, 根据Files, 有些要删除的, 只留下这些
attachService.UpdateOrDeleteAttachApi(noteId, userId, noteOrContent.Files)
// Desc前台传来
if c.Has("Desc") {
needUpdateNote = true
noteUpdate["Desc"] = noteOrContent.Desc
}
/*
if c.Has("ImgSrc") {
needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
}
*/
if c.Has("Title") {
needUpdateNote = true
noteUpdate["Title"] = noteOrContent.Title
}
if c.Has("IsTrash") {
needUpdateNote = true
noteUpdate["IsTrash"] = noteOrContent.IsTrash
}
// 是否是博客
if c.Has("IsBlog") {
needUpdateNote = true
noteUpdate["IsBlog"] = noteOrContent.IsBlog
}
/*
Log(c.Has("tags[0]"))
Log(c.Has("Tags[]"))
for key, v := range c.Params.Values {
Log(key)
Log(v)
}
*/
if c.Has("Tags[0]") {
needUpdateNote = true
noteUpdate["Tags"] = noteOrContent.Tags
}
if c.Has("NotebookId") {
if bson.IsObjectIdHex(noteOrContent.NotebookId) {
needUpdateNote = true
noteUpdate["NotebookId"] = bson.ObjectIdHex(noteOrContent.NotebookId)
}
}
if c.Has("Content") {
// 通过内容得到Desc, 如果有Abstract, 则用Abstract生成Desc
if noteOrContent.Abstract == "" {
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Content, 200)
} else {
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Abstract, 200)
}
}
noteUpdate["UpdatedTime"] = noteOrContent.UpdatedTime
afterNoteUsn := 0
noteOk := false
noteMsg := ""
if needUpdateNote {
noteOk, noteMsg, afterNoteUsn = noteService.UpdateNote(c.getUserId(), noteOrContent.NoteId, noteUpdate, noteOrContent.Usn)
if !noteOk {
re.Ok = false
re.Msg = noteMsg
return c.RenderJson(re)
}
}
//-------------
afterContentUsn := 0
contentOk := false
contentMsg := ""
if c.Has("Content") {
// 把fileId替换下
c.fixPostNotecontent(&noteOrContent)
// 如果传了Abstract就用之
if noteOrContent.Abstract == "" {
noteOrContent.Abstract = SubStringHTML(noteOrContent.Content, 200, "")
}
// Log("--------> afte fixed")
// Log(noteOrContent.Content)
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.getUserId(),
noteOrContent.NoteId,
noteOrContent.Content,
noteOrContent.Abstract,
needUpdateNote,
noteOrContent.Usn,
noteOrContent.UpdatedTime)
}
if needUpdateNote {
re.Ok = noteOk
re.Msg = noteMsg
re.Usn = afterNoteUsn
} else {
re.Ok = contentOk
re.Msg = contentMsg
re.Usn = afterContentUsn
}
if !re.Ok {
return c.RenderJson(re)
}
noteOrContent.Content = ""
noteOrContent.Usn = re.Usn
noteOrContent.UpdatedTime = time.Now()
// Log("after upload")
// LogJ(noteOrContent.Files)
noteOrContent.UserId = c.getUserId()
return c.RenderJson(noteOrContent)
}
// 删除trash
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
re := info.NewReUpdate()
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
return c.RenderJson(re)
}
// 得到历史列表
/*
func (c ApiNote) GetHistories(noteId string) revel.Result {
re := info.NewRe()
histories := noteContentHistoryService.ListHistories(noteId, c.getUserId())
if len(histories) > 0 {
re.Ok = true
re.Item = histories
}
return c.RenderJson(re)
}
*/
// 0.2 新增
// 导出成PDF
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
}
@@ -1,106 +0,0 @@
package api
import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// "io/ioutil"
)
// 笔记本API
type ApiNotebook struct {
ApiBaseContrller
}
// 从Notebook -> ApiNotebook
func (c ApiNotebook) fixNotebooks(notebooks []info.Notebook) []info.ApiNotebook {
if notebooks == nil {
return nil
}
apiNotebooks := make([]info.ApiNotebook, len(notebooks))
for i, notebook := range notebooks {
apiNotebooks[i] = c.fixNotebook(&notebook)
}
return apiNotebooks
}
func (c ApiNotebook) fixNotebook(notebook *info.Notebook) info.ApiNotebook {
if notebook == nil {
return info.ApiNotebook{}
}
return info.ApiNotebook{
NotebookId: notebook.NotebookId,
UserId: notebook.UserId,
ParentNotebookId: notebook.ParentNotebookId,
Seq: notebook.Seq,
Title: notebook.Title,
UrlTitle: notebook.UrlTitle,
IsBlog: notebook.IsBlog,
CreatedTime: notebook.CreatedTime,
UpdatedTime: notebook.UpdatedTime,
Usn: notebook.Usn,
IsDeleted: notebook.IsDeleted,
}
}
// 获取同步的笔记本
// [OK]
// > afterUsn的笔记
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
if maxEntry == 0 {
maxEntry = 100
}
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(c.fixNotebooks(notebooks))
}
// 得到用户的所有笔记本
// [OK]
// info.SubNotebooks
func (c ApiNotebook) GetNotebooks() revel.Result {
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
return c.RenderJson(c.fixNotebooks(notebooks))
}
// 添加notebook
// [OK]
func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.Result {
notebook := info.Notebook{NotebookId: bson.NewObjectId(),
Title: title,
Seq: seq,
UserId: bson.ObjectIdHex(c.getUserId())}
if parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId) {
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
}
re := info.NewRe()
re.Ok, notebook = notebookService.AddNotebook(notebook)
if !re.Ok {
return c.RenderJson(re)
}
return c.RenderJson(c.fixNotebook(&notebook))
}
// 修改笔记
// [OK]
func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string, seq, usn int) revel.Result {
re := info.NewApiRe()
ok, msg, notebook := notebookService.UpdateNotebookApi(c.getUserId(), notebookId, title, parentNotebookId, seq, usn)
if !ok {
re.Ok = false
re.Msg = msg
return c.RenderJson(re)
}
LogJ(notebook)
return c.RenderJson(c.fixNotebook(&notebook))
}
// 删除笔记本
// [OK]
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
re := info.NewApiRe()
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
return c.RenderJson(re)
}
-56
View File
@@ -1,56 +0,0 @@
package api
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
// 标签API
type ApiTag struct {
ApiBaseContrller
}
// 获取同步的标签
// [OK]
// > afterUsn的笔记
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
if maxEntry == 0 {
maxEntry = 100
}
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
return c.RenderJson(tags)
}
// 添加Tag
// [OK]
// 不会产生冲突, 即使里面有
// 返回
/*
{
"TagId": "551978dd99c37b9bc5000001",
"UserId": "54a1676399c37b1c77000002",
"Tag": "32",
"Usn": 25,
"Count": 1,
"CreatedTime": "2015-03-31T00:25:01.149312407+08:00",
"UpdatedTime": "2015-03-31T00:25:01.149312407+08:00",
"IsDeleted": false
}
*/
func (c ApiTag) AddTag(tag string) revel.Result {
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
return c.RenderJson(ret)
}
// 删除标签
// [OK]
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
re := info.NewReUpdate()
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
return c.RenderJson(re)
}
+8 -134
View File
@@ -3,15 +3,14 @@ package api
import ( import (
"github.com/revel/revel" "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" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" // "github.com/leanote/leanote/app/info"
"time"
// "github.com/leanote/leanote/app/types" // "github.com/leanote/leanote/app/types"
"io/ioutil" // "io/ioutil"
// "fmt" // "fmt"
// "math" // "math"
"os" // "os"
// "path" // "path"
// "strconv" // "strconv"
@@ -21,134 +20,9 @@ type ApiUser struct {
ApiBaseContrller ApiBaseContrller
} }
// 获取用户信息 // 修改用户名, 需要重置session
// [OK]
func (c ApiUser) Info() revel.Result { func (c ApiUser) Info() revel.Result {
re := info.NewApiRe() Log("APIUser");
return c.RenderTemplate("home/index.html");
userInfo := c.getUserInfo() // return nil;
if userInfo.UserId == "" {
return c.RenderJson(re)
}
apiUser := info.ApiUser{
UserId: userInfo.UserId.Hex(),
Username: userInfo.Username,
Email: userInfo.Email,
Logo: userInfo.Logo,
Verified: userInfo.Verified,
}
return c.RenderJson(apiUser)
}
// 修改用户名
// [OK]
func (c ApiUser) UpdateUsername(username string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
return c.RenderJson(re)
}
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
return c.RenderJson(re)
}
// 修改密码
// [OK]
func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re)
}
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
return c.RenderJson(re)
}
// 获得同步状态
// [OK]
func (c ApiUser) GetSyncState() revel.Result {
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
return c.RenderJson(ret)
}
// 头像设置
// 参数file=文件
// 成功返回{Logo: url} 头像新url
// [OK]
func (c ApiUser) UpdateLogo() revel.Result {
ok, msg, url := c.uploadImage()
if ok {
ok = userService.UpdateAvatar(c.getUserId(), url)
return c.RenderJson(map[string]string{"Logo": url})
} else {
re := info.NewApiRe()
re.Msg = msg
return c.RenderJson(re)
}
}
// 上传图片
func (c ApiUser) uploadImage() (ok bool, msg, url string) {
var fileUrlPath = ""
ok = false
file, handel, err := c.Request.FormFile("file")
if err != nil {
return
}
defer file.Close()
// 生成上传路径
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
return
}
// 生成新的文件名
filename := handel.Filename
var ext string
_, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
msg = "notImage"
return
}
filename = NewGuid() + ext
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return
}
// > 5M?
if len(data) > 5*1024*1024 {
msg = "fileIsTooLarge"
return
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
LogJ(err)
return
}
ok = true
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
return
} }
+46 -51
View File
@@ -1,8 +1,8 @@
package api package api
import ( import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service" "github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
"strings" "strings"
@@ -31,29 +31,41 @@ var sessionService *service.SessionService
var pageSize = 1000 var pageSize = 1000
var defaultSortField = "UpdatedTime" var defaultSortField = "UpdatedTime"
var leanoteUserId = "admin" // 不能更改 var leanoteUserId = "admin" // 不能更改
var siteUrl = "http://leanote.com"
// 状态
const (
S_DEFAULT = iota // 0
S_NOT_LOGIN // 1
S_WRONG_USERNAME_PASSWORD // 2
S_WRONG_CAPTCHA // 3
S_NEED_CAPTCHA // 4
S_NOT_OPEN_REGISTER // 4
)
// 拦截器 // 拦截器
// 不需要拦截的url // 不需要拦截的url
var commonUrl = map[string]map[string]bool{"ApiAuth": map[string]bool{"Login": true, // Index 除了Note之外都不需要
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
"Login": true,
"DoLogin": true,
"Logout": true,
"Register": true, "Register": true,
"DoRegister": true,
"FindPasswword": true,
"DoFindPassword": true,
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
}, },
// 文件的操作也不用登录, userId会从session中获取 "Note": map[string]bool{"ToImage": true},
"ApiFile": map[string]bool{"GetImage": true, "Blog": map[string]bool{"Index": true,
"GetAttach": true, "View": true,
"GetAllAttachs": true, "AboutMe": true,
"Cate": true,
"Search": true,
"GetLikeAndComments": true,
"IncReadNum": true,
"ListComments": true,
}, },
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": 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 { func needValidate(controller, method string) bool {
// 在里面 // 在里面
if v, ok := commonUrl[controller]; ok { if v, ok := commonUrl[controller]; ok {
@@ -64,59 +76,32 @@ func needValidate(controller, method string) bool {
return true return true
} else { } else {
// controller不在这里的, 肯定要验证 // controller不在这里的, 肯定要验证
return true return true;
} }
} }
// 这里得到token, 若不是login, logout等公用操作, 必须验证是否已登录
func AuthInterceptor(c *revel.Controller) revel.Result { func AuthInterceptor(c *revel.Controller) revel.Result {
// 得到token /api/user/info?userId=xxx&token=xxxxx
token := c.Params.Values.Get("token")
noToken := false
if token == "" {
// 若无, 则取sessionId
token = c.Session.Id()
noToken = true
}
c.Session["_token"] = token
// 全部变成首字大写 // 全部变成首字大写
var controller = strings.Title(c.Name) var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName) var method = strings.Title(c.MethodName)
// 验证是否已登录
// 通过sessionService判断该token下是否有userId, 并返回userId
userId := sessionService.GetUserId(token)
if noToken && userId == "" {
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
// 客户端
userId, _ = c.Session["UserId"]
}
c.Session["_userId"] = userId
// 是否需要验证? // 是否需要验证?
if !needValidate(controller, method) { if !needValidate(controller, method) {
return nil return nil
} }
if userId != "" { // 验证是否已登录
if userId, ok := c.Session["UserId"]; ok && userId != "" {
return nil // 已登录 return nil // 已登录
} }
// 没有登录, 返回错误的信息, 需要登录 // 没有登录, 判断是否是ajax操作
re := info.NewApiRe() if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
re := info.NewRe()
re.Msg = "NOTLOGIN" re.Msg = "NOTLOGIN"
return c.RenderJson(re) return c.RenderJson(re)
} }
func init() { return c.Redirect("/login")
// interceptors
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiFile{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNote{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiTag{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNotebook{})
} }
// 最外层init.go调用 // 最外层init.go调用
@@ -142,3 +127,13 @@ func InitService() {
emailService = service.EmailS emailService = service.EmailS
sessionService = service.SessionS sessionService = service.SessionS
} }
func init() {
// interceptors
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
revel.OnAppStart(func() {
siteUrl, _ = revel.Config.String("site.url")
})
}
+8 -21
View File
@@ -1,9 +1,8 @@
package controllers package controllers
import ( import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/blog"
"github.com/leanote/leanote/app/service" "github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
"strings" "strings"
@@ -28,10 +27,11 @@ var attachService *service.AttachService
var configService *service.ConfigService var configService *service.ConfigService
var emailService *service.EmailService var emailService *service.EmailService
var sessionService *service.SessionService var sessionService *service.SessionService
var themeService *service.ThemeService
var pageSize = 1000 var pageSize = 1000
var defaultSortField = "UpdatedTime" var defaultSortField = "UpdatedTime"
var leanoteUserId = "admin" // 不能更改
var siteUrl = "http://leanote.com"
// 拦截器 // 拦截器
// 不需要拦截的url // 不需要拦截的url
@@ -48,19 +48,15 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"FindPasswordUpdate": true, "FindPasswordUpdate": true,
"Suggestion": true, "Suggestion": true,
}, },
"Note": map[string]bool{"ToPdf": true}, "Note": map[string]bool{"ToImage": true},
"Blog": map[string]bool{"Index": true, "Blog": map[string]bool{"Index": true,
"View": true, "View": true,
"AboutMe": true, "AboutMe": true,
"Cate": true, "Cate": true,
"ListCateLatest": true,
"Search": true, "Search": true,
"GetLikeAndComments": true, "GetLikeAndComments": true,
"IncReadNum": true, "IncReadNum": true,
"ListComments": true, "ListComments": true,
"Single": true,
"Archive": true,
"Tags": true,
}, },
// 用户的激活与修改邮箱都不需要登录, 通过链接地址 // 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true, "User": map[string]bool{"UpdateEmail": true,
@@ -68,9 +64,8 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
}, },
"Oauth": map[string]bool{"GithubCallback": true}, "Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true}, "File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true /*, "DownloadAll": true*/}, "Attach": map[string]bool{"Download": true, "DownloadAll": true},
} }
func needValidate(controller, method string) bool { func needValidate(controller, method string) bool {
// 在里面 // 在里面
if v, ok := commonUrl[controller]; ok { if v, ok := commonUrl[controller]; ok {
@@ -81,7 +76,7 @@ func needValidate(controller, method string) bool {
return true return true
} else { } else {
// controller不在这里的, 肯定要验证 // controller不在这里的, 肯定要验证
return true return true;
} }
} }
func AuthInterceptor(c *revel.Controller) revel.Result { func AuthInterceptor(c *revel.Controller) revel.Result {
@@ -131,12 +126,6 @@ func InitService() {
configService = service.ConfigS configService = service.ConfigS
emailService = service.EmailS emailService = service.EmailS
sessionService = service.SessionS sessionService = service.SessionS
themeService = service.ThemeS
}
// 初始化博客模板
// 博客模板不由revel的
func initBlogTemplate() {
} }
func init() { func init() {
@@ -146,14 +135,12 @@ func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Album{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{}) revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
revel.OnAppStart(func() { revel.OnAppStart(func() {
// 博客初始化模板 siteUrl, _ = revel.Config.String("site.url")
blog.Init()
}) })
} }
@@ -1,59 +0,0 @@
package member
import (
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
// 公用Controller, 其它Controller继承它
type MemberBaseController struct {
controllers.BaseController // 不能用*BaseController
}
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc
}
}
sorterField = strings.Title(s2[0])
if s2[1] == "up" {
isAsc = true
} else {
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc
}
func (c MemberBaseController) updateConfig(keys []string) {
userId := c.GetUserId()
for _, key := range keys {
v := c.Params.Values.Get(key)
configService.UpdateGlobalStringConfig(userId, key, v)
}
}
@@ -1,528 +0,0 @@
package member
import (
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"io/ioutil"
"os"
"strings"
"time"
// "github.com/leanote/leanote/app/lea/blog"
)
// 博客管理
type MemberBlog struct {
MemberBaseController
}
func (c MemberBlog) common() info.UserBlog {
userId := c.GetUserId()
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
// 得到博客设置信息
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
userBlog := blogService.GetUserBlog(userId)
c.RenderArgs["userBlog"] = userBlog
c.SetUserInfo()
c.SetLocale()
return userBlog
}
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc
}
}
sorterField = strings.Title(s2[0])
if s2[1] == "up" {
isAsc = true
} else {
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc
}
// 博客列表
var userPageSize = 15
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
userId := c.GetUserId()
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
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)
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
c.RenderArgs["userAndBlog"] = userAndBlog
c.common()
return c.RenderTemplate("member/blog/list.html")
}
// 修改笔记的urlTitle
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
return c.RenderJson(re)
}
// 修改笔记的urlTitle
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Update Post Abstract")
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
if !note.Note.IsBlog {
return c.E404()
}
c.RenderArgs["note"] = note
c.RenderArgs["noteId"] = noteId
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)
}
// 基本信息设置
func (c MemberBlog) Base() revel.Result {
c.common()
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"] = c.Message("Comment")
return c.RenderTemplate("member/blog/comment.html")
}
func (c MemberBlog) Paging() revel.Result {
c.common()
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"] = c.Message("Category")
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
notebooksMap := map[string]info.Notebook{}
for _, each := range notebooks {
notebooksMap[each.NotebookId.Hex()] = each
}
var i = 0
notebooks2 := make([]info.Notebook, len(notebooks))
// 先要保证已有的是正确的排序
cateIds := userBlog.CateIds
has := map[string]bool{} // cateIds中有的
if cateIds != nil && len(cateIds) > 0 {
for _, cateId := range cateIds {
if n, ok := notebooksMap[cateId]; ok {
notebooks2[i] = n
i++
has[cateId] = true
}
}
}
// 之后
for _, each := range notebooks {
id := each.NotebookId.Hex()
if !has[id] {
notebooks2[i] = each
i++
}
}
c.RenderArgs["notebooks"] = notebooks2
return c.RenderTemplate("member/blog/cate.html")
}
// 修改分类排序
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
return c.RenderJson(re)
}
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
return c.RenderJson(re)
}
// 保存之, 包含增加与保存
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
re := info.NewRe()
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
return c.RenderJson(re)
}
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Add Single")
c.RenderArgs["singleId"] = singleId
if singleId != "" {
c.RenderArgs["title"] = c.Message("Update Single")
c.RenderArgs["single"] = blogService.GetSingle(singleId)
}
return c.RenderTemplate("member/blog/add_single.html")
}
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
re := info.NewRe()
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
return c.RenderJson(re)
}
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
re := info.NewRe()
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
return c.RenderJson(re)
}
// 修改页面标题
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
return c.RenderJson(re)
}
func (c MemberBlog) Single() revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Single")
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
return c.RenderTemplate("member/blog/single.html")
}
// 主题
func (c MemberBlog) Theme() revel.Result {
c.common()
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
c.RenderArgs["activeTheme"] = activeTheme
c.RenderArgs["otherThemes"] = otherThemes
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
c.RenderArgs["title"] = c.Message("Theme")
return c.RenderTemplate("member/blog/theme.html")
}
// 编辑主题
var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"}
func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
// 查看用户是否有该theme, 若没有则复制default之
// 得到主题的文件列表
userBlog := blogService.GetUserBlog(c.GetUserId())
if themeId == "" {
_, themeId = themeService.NewThemeForFirst(userBlog)
return c.Redirect("/member/blog/updateTheme?themeId=" + themeId)
}
c.common()
c.RenderArgs["title"] = c.Message("Update Theme")
c.RenderArgs["isNew"] = isNew
// 先复制之
c.RenderArgs["themeId"] = themeId
// 得到脚本目录
userId := c.GetUserId()
theme := themeService.GetTheme(userId, themeId)
if theme.ThemeId == "" {
return c.E404()
}
c.RenderArgs["theme"] = theme
path := revel.BasePath + "/" + theme.Path
tpls := ListDir(path)
myTpls := make([]string, len(baseTpls))
tplMap := map[string]bool{}
for i, t := range baseTpls {
myTpls[i] = t
tplMap[t] = true
}
// 得到没有的tpls
for _, t := range tpls {
if t == "images" {
continue
}
if !tplMap[t] {
myTpls = append(myTpls, t)
}
}
c.RenderArgs["myTpls"] = myTpls
return c.RenderTemplate("member/blog/update_theme.html")
}
// 得到文件内容
func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result {
re := info.NewRe()
re.Ok = true
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
return c.RenderJson(re)
}
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content)
return c.RenderRe(re)
}
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
re := info.NewRe()
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
return c.RenderJson(re)
}
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
re := info.NewRe()
userId := c.GetUserId()
path := themeService.GetThemeAbsolutePath(userId, themeId) + "/images"
os.MkdirAll(path, 0755)
images := ListDir(path)
re.List = images
re.Ok = true
return c.RenderJson(re)
}
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
re := info.NewRe()
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
re.Ok = DeleteFile(path)
return c.RenderJson(re)
}
// 上传主题图片
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
re := c.uploadImage(themeId)
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
c.RenderArgs["resultMsg"] = re.Msg
return c.RenderTemplate("file/blog_logo.html")
}
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
var fileId = ""
var resultCode = 0 // 1表示正常
var resultMsg = "内部错误" // 错误信息
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()
// 生成上传路径
dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images"
err = os.MkdirAll(dir, 0755)
if err != nil {
return re
}
// 生成新的文件名
filename := handel.Filename
var ext string
_, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
resultMsg = "不是图片"
return re
}
filename = filename
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return re
}
// > 2M?
if len(data) > 5*1024*1024 {
resultCode = 0
resultMsg = "图片大于2M"
return re
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
LogJ(err)
return re
}
TransToGif(toPath, 0, true)
resultCode = 1
resultMsg = "上传成功!"
return re
}
//
// 使用主题
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 删除主题
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 管理员公开主题
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 导出
func (c MemberBlog) ExportTheme(themeId string) revel.Result {
re := info.NewRe()
var path string
re.Ok, path = themeService.ExportTheme(c.GetUserId(), themeId)
if !re.Ok {
return c.RenderText("error...")
}
fw, err := os.Open(path)
if err != nil {
return c.RenderText("error")
}
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
}
// 导入主题
func (c MemberBlog) ImportTheme() revel.Result {
re := info.NewRe()
file, handel, err := c.Request.FormFile("file")
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
defer file.Close()
// 生成上传路径
userId := c.GetUserId()
dir := revel.BasePath + "/public/upload/" + userId + "/tmp"
err = os.MkdirAll(dir, 0755)
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
// 生成新的文件名
filename := handel.Filename
var ext string
_, ext = SplitFilename(filename)
if ext != ".zip" {
re.Msg = "Please upload zip file"
return c.RenderJson(re)
}
filename = filename
data, err := ioutil.ReadAll(file)
if err != nil {
return c.RenderJson(re)
}
// > 10M?
if len(data) > 10*1024*1024 {
re.Msg = "File is big than 10M"
return c.RenderJson(re)
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
// 上传好后, 增加之
re.Ok, re.Msg = themeService.ImportTheme(c.GetUserId(), toPath)
return c.RenderRe(re)
}
// 安装
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
re := info.NewRe()
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
return c.RenderJson(re)
}
// 新建主题
func (c MemberBlog) NewTheme() revel.Result {
_, themeId := themeService.NewTheme(c.GetUserId())
return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId)
}
//-----------
//
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
return c.RenderJson(re)
}
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
return c.RenderJson(re)
}
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
return c.RenderJson(re)
}
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc)
return c.RenderRe(re)
}
@@ -1,58 +0,0 @@
package member
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
)
// 分组管理
type MemberGroup struct {
MemberBaseController
}
// 首页, 显示所有分组和用户
func (c MemberGroup) Index() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = c.Message("My Group")
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
return c.RenderTemplate("member/group/index.html")
}
// 添加分组
func (c MemberGroup) AddGroup(title string) revel.Result {
re := info.NewRe()
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
return c.RenderJson(re)
}
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
re := info.NewRe()
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
return c.RenderJson(re)
}
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = groupService.DeleteGroup(c.GetUserId(), groupId)
return c.RenderRe(re)
}
// 添加用户
func (c MemberGroup) AddUser(groupId, email string) revel.Result {
re := info.NewRe()
userInfo := userService.GetUserInfoByAny(email)
if userInfo.UserId == "" {
re.Msg = "userNotExists"
} else {
re.Ok, re.Msg = groupService.AddUser(c.GetUserId(), groupId, userInfo.UserId.Hex())
re.Item = userInfo
}
return c.RenderRe(re)
}
func (c MemberGroup) DeleteUser(groupId, userId string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = groupService.DeleteUser(c.GetUserId(), groupId, userId)
return c.RenderRe(re)
}
@@ -1,37 +0,0 @@
package member
import (
"github.com/revel/revel"
)
// admin 首页
type MemberIndex struct {
MemberBaseController
}
// admin 主页
func (c MemberIndex) Index() revel.Result {
c.SetUserInfo()
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")
}
// 模板
func (c MemberIndex) T(t string) revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
return c.RenderTemplate("admin/" + t + ".html")
}
func (c MemberIndex) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view)
}
@@ -1,40 +0,0 @@
package member
import (
"github.com/revel/revel"
)
// 帐户信息
type MemberUser struct {
MemberBaseController
}
func (c MemberUser) Username() revel.Result {
c.SetUserInfo()
c.SetLocale()
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"] = c.Message("Email")
return c.RenderTemplate("member/user/email.html")
}
func (c MemberUser) Password() revel.Result {
c.SetUserInfo()
c.SetLocale()
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"] = c.Message("Avatar")
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
return c.RenderTemplate("member/user/avatar.html")
}
-135
View File
@@ -1,135 +0,0 @@
package member
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "strings"
)
var userService *service.UserService
var groupService *service.GroupService
var noteService *service.NoteService
var trashService *service.TrashService
var notebookService *service.NotebookService
var noteContentHistoryService *service.NoteContentHistoryService
var authService *service.AuthService
var shareService *service.ShareService
var blogService *service.BlogService
var tagService *service.TagService
var pwdService *service.PwdService
var tokenService *service.TokenService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var fileService *service.FileService
var attachService *service.AttachService
var configService *service.ConfigService
var emailService *service.EmailService
var upgradeService *service.UpgradeService
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,
},
"Blog": map[string]bool{"Index": 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},
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
// 在commonUrl里
if _, ok2 := v[method]; ok2 {
return false
}
return true
} else {
// controller不在这里的, 肯定要验证
return true
}
}
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
}
*/
// 验证是否已登录
// 必须是管理员
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")
}
// 最外层init.go调用
// 获取service, 单例
func InitService() {
notebookService = service.NotebookS
noteService = service.NoteS
noteContentHistoryService = service.NoteContentHistoryS
trashService = service.TrashS
shareService = service.ShareS
userService = service.UserS
groupService = service.GroupS
tagService = service.TagS
blogService = service.BlogS
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService = service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
authService = service.AuthS
configService = service.ConfigS
emailService = service.EmailS
upgradeService = service.UpgradeS
themeService = service.ThemeS
}
func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberGroup{})
revel.OnAppStart(func() {
})
}
+9 -72
View File
@@ -2,11 +2,9 @@ package db
import ( import (
"fmt" "fmt"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2" "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"strings" "github.com/revel/revel"
) )
// Init mgo and the common DAO // Init mgo and the common DAO
@@ -25,12 +23,9 @@ var ShareNotebooks *mgo.Collection
var HasShareNotes *mgo.Collection var HasShareNotes *mgo.Collection
var Blogs *mgo.Collection var Blogs *mgo.Collection
var Users *mgo.Collection var Users *mgo.Collection
var Groups *mgo.Collection
var GroupUsers *mgo.Collection
var Tags *mgo.Collection var Tags *mgo.Collection
var NoteTags *mgo.Collection var TagNotes *mgo.Collection
var TagCounts *mgo.Collection
var UserBlogs *mgo.Collection var UserBlogs *mgo.Collection
@@ -51,38 +46,17 @@ var EmailLogs *mgo.Collection
var BlogLikes *mgo.Collection var BlogLikes *mgo.Collection
var BlogComments *mgo.Collection var BlogComments *mgo.Collection
var Reports *mgo.Collection var Reports *mgo.Collection
var BlogSingles *mgo.Collection
var Themes *mgo.Collection
// session // session
var Sessions *mgo.Collection var Sessions *mgo.Collection
// 初始化时连接数据库 // 初始化时连接数据库
func Init(url, dbname string) { func Init() {
ok := true var url string
config := revel.Config var ok bool
if url == "" { config := revel.Config;
url, ok = config.String("db.url") url, ok = config.String("db.url")
if !ok { dbname, _ := config.String("db.dbname")
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 { if !ok {
host, _ := revel.Config.String("db.host") host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port") port, _ := revel.Config.String("db.port")
@@ -94,7 +68,6 @@ func Init(url, dbname string) {
} }
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
} }
Log(url)
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options] // [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb // mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
@@ -124,22 +97,16 @@ func Init(url, dbname string) {
// user // user
Users = Session.DB(dbname).C("users") Users = Session.DB(dbname).C("users")
// group
Groups = Session.DB(dbname).C("groups")
GroupUsers = Session.DB(dbname).C("group_users")
// blog // blog
Blogs = Session.DB(dbname).C("blogs") Blogs = Session.DB(dbname).C("blogs")
// tag // tag
Tags = Session.DB(dbname).C("tags") Tags = Session.DB(dbname).C("tags")
NoteTags = Session.DB(dbname).C("note_tags") TagNotes = Session.DB(dbname).C("tag_notes")
TagCounts = Session.DB(dbname).C("tag_count")
// blog // blog
UserBlogs = Session.DB(dbname).C("user_blogs") UserBlogs = Session.DB(dbname).C("user_blogs")
BlogSingles = Session.DB(dbname).C("blog_singles")
Themes = Session.DB(dbname).C("themes")
// find password // find password
Tokens = Session.DB(dbname).C("tokens") Tokens = Session.DB(dbname).C("tokens")
@@ -212,24 +179,17 @@ func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field stri
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool { func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v}) return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
} }
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool { func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}}) return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
} }
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool { func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v}) return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
} }
// //
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool { func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}}) _, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
return Err(err) return Err(err)
} }
func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool {
_, err := collection.UpdateAll(q, bson.M{"$set": v})
return Err(err)
}
// 查询条件和值 // 查询条件和值
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool { func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
_, err := collection.UpdateAll(q, bson.M{"$set": v}) _, err := collection.UpdateAll(q, bson.M{"$set": v})
@@ -295,7 +255,6 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i
} }
collection.Find(q).Select(selector).One(i) collection.Find(q).Select(selector).One(i)
} }
// 查询某些字段, q是查询条件, fields是字段名列表 // 查询某些字段, q是查询条件, fields是字段名列表
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) { func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
selector := make(bson.M, len(fields)) selector := make(bson.M, len(fields))
@@ -311,11 +270,6 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i) collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
} }
// 按field去重
func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) {
collection.Find(q).Distinct(field, i)
}
//---------------------- //----------------------
func Count(collection *mgo.Collection, q interface{}) int { func Count(collection *mgo.Collection, q interface{}) int {
@@ -349,26 +303,9 @@ func Err(err error) bool {
fmt.Println(err) fmt.Println(err)
// 删除时, 查找 // 删除时, 查找
if err.Error() == "not found" { if err.Error() == "not found" {
return true return true;
} }
return false return false
} }
return true return true
} }
// 检查mognodb是否lost connection
// 每个请求之前都要检查!!
func CheckMongoSessionLost() {
// fmt.Println("检查CheckMongoSessionLostErr")
err := Session.Ping()
if err != nil {
Log("Lost connection to db!")
Session.Refresh()
err = Session.Ping()
if err == nil {
Log("Reconnect to db successful.")
} else {
Log("重连失败!!!! 警告")
}
}
}
+89
View File
@@ -0,0 +1,89 @@
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")
}
-119
View File
@@ -1,119 +0,0 @@
package info
import (
"gopkg.in/mgo.v2/bson"
"time"
)
//---------
// 数据结构
//---------
type NoteFile struct {
FileId string // 服务器端Id
LocalFileId string // 客户端Id
Type string // images/png, doc, xls, 根据fileName确定
Title string
HasBody bool // 传过来的值是否要更新内容
IsAttach bool // 是否是附件, 不是附件就是图片
}
type ApiNote struct {
NoteId string
NotebookId string
UserId string
Title string
Desc string
// ImgSrc string
Tags []string
Abstract string
Content string
IsMarkdown bool
// FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
IsTrash bool
IsDeleted bool
Usn int
Files []NoteFile
CreatedTime time.Time
UpdatedTime time.Time
PublicTime time.Time
}
// 内容
type ApiNoteContent struct {
NoteId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `bson:"UserId"`
Content string `Content`
// CreatedTime time.Time `CreatedTime`
// UpdatedTime time.Time `UpdatedTime`
}
// 转换
func NoteToApiNote(note Note, files []NoteFile) ApiNote {
apiNote := ApiNote{}
return apiNote
}
//----------
// 用户信息
//----------
type ApiUser struct {
UserId string
Username string
Email string
Verified bool
Logo string
}
//----------
// Notebook
//----------
type ApiNotebook struct {
NotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
UserId bson.ObjectId `bson:"UserId"`
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
Seq int `Seq` // 排序
Title string `Title` // 标题
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
CreatedTime time.Time `CreatedTime,omitempty`
UpdatedTime time.Time `UpdatedTime,omitempty`
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
}
//---------
// api 返回
//---------
// 一般返回
type ApiRe struct {
Ok bool
Msg string
}
func NewApiRe() ApiRe {
return ApiRe{Ok: false}
}
// auth
type AuthOk struct {
Ok bool
Token string
UserId bson.ObjectId
Email string
Username string
}
// 供notebook, note, tag更新的返回数据用
type ReUpdate struct {
Ok bool
Msg string
Usn int
}
func NewReUpdate() ReUpdate {
return ReUpdate{Ok: false}
}
-58
View File
@@ -1,58 +0,0 @@
package info
import (
"time"
)
// 仅仅为了博客的主题
type BlogInfoCustom struct {
UserId string
Username string
UserLogo string
Title string
SubTitle string
Logo string
OpenComment bool
CommentType string
ThemeId string
SubDomain string
Domain string
}
type Post struct {
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
}
// 归档
type ArchiveMonth struct {
Month int
Posts []*Post
}
type Archive struct {
Year int
MonthAchives []ArchiveMonth
Posts []*Post
}
type Cate struct {
CateId string
ParentCateId string
Title string
UrlTitle string
Children []*Cate
}
+4 -46
View File
@@ -9,7 +9,6 @@ import (
type BlogItem struct { type BlogItem struct {
Note Note
Abstract string
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了 Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
HasMore bool // 是否是否还有 HasMore bool // 是否是否还有
User User // 用户信息 User User // 用户信息
@@ -19,7 +18,7 @@ type UserBlogBase struct {
Logo string `Logo` Logo string `Logo`
Title string `Title` // 标题 Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题 SubTitle string `SubTitle` // 副标题
// AboutMe string `AboutMe` // 关于我 AboutMe string `AboutMe` // 关于我
} }
type UserBlogComment struct { type UserBlogComment struct {
@@ -39,7 +38,7 @@ type UserBlog struct {
Logo string `Logo` Logo string `Logo`
Title string `Title` // 标题 Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题 SubTitle string `SubTitle` // 副标题
AboutMe string `AboutMe` // 关于我, 弃用 AboutMe string `AboutMe` // 关于我
CanComment bool `CanComment` // 是否可以评论 CanComment bool `CanComment` // 是否可以评论
@@ -49,38 +48,8 @@ type UserBlog struct {
Style string `Style` // 风格 Style string `Style` // 风格
Css string `Css` // 自定义css Css string `Css` // 自定义css
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, 表示降序
SubDomain string `SubDomain` // 二级域名 SubDomain string `SubDomain` // 二级域名
Domain string `Domain` // 自定义域名 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
}
// 单页
type BlogSingle struct {
SingleId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `UserId`
Title string `Title`
UrlTitle string `UrlTitle` // 2014/11/11
Content string `Content`
UpdatedTime time.Time `UpdatedTime`
CreatedTime time.Time `CreatedTime`
} }
//------------------------ //------------------------
@@ -88,7 +57,7 @@ type BlogSingle struct {
// 点赞记录 // 点赞记录
type BlogLike struct { type BlogLike struct {
LikeId bson.ObjectId `bson:"_id,omitempty"` LikeId bson.ObjectId `bson:"_id"`
NoteId bson.ObjectId `NoteId` NoteId bson.ObjectId `NoteId`
UserId bson.ObjectId `UserId` UserId bson.ObjectId `UserId`
CreatedTime time.Time `CreatedTime` CreatedTime time.Time `CreatedTime`
@@ -96,7 +65,7 @@ type BlogLike struct {
// 评论 // 评论
type BlogComment struct { type BlogComment struct {
CommentId bson.ObjectId `bson:"_id,omitempty"` CommentId bson.ObjectId `bson:"_id"`
NoteId bson.ObjectId `NoteId` NoteId bson.ObjectId `NoteId`
UserId bson.ObjectId `UserId` // UserId回复ToUserId UserId bson.ObjectId `UserId` // UserId回复ToUserId
@@ -115,14 +84,3 @@ type BlogCommentPublic struct {
BlogComment BlogComment
IsILikeIt bool IsILikeIt bool
} }
type BlogUrls struct {
IndexUrl string
CateUrl string
SearchUrl string
SingleUrl string
PostUrl string
ArchiveUrl string
TagsUrl string
TagPostsUrl string
}
-25
View File
@@ -1,25 +0,0 @@
package info
import (
"gopkg.in/mgo.v2/bson"
"time"
)
// 分组
type Group struct {
GroupId bson.ObjectId `bson:"_id"` // 谁的
UserId bson.ObjectId `UserId` // 所有者Id
Title string `Title` // 标题
UserCount int `UserCount` // 用户数
CreatedTime time.Time `CreatedTime`
Users []User `Users,omitempty` // 分组下的用户, 不保存, 仅查看
}
// 分组好友
type GroupUser struct {
GroupUserId bson.ObjectId `bson:"_id"` // 谁的
GroupId bson.ObjectId `GroupId` // 分组
UserId bson.ObjectId `UserId` // 用户
CreatedTime time.Time `CreatedTime`
}
-28
View File
@@ -21,10 +21,8 @@ type Note struct {
IsTrash bool `IsTrash` // 是否是trash, 默认是false IsTrash bool `IsTrash` // 是否是trash, 默认是false
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加 IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
UrlTitle string `UrlTitle,omitempty` // 博客的url标题, 为了更友好的url, 在UserId, UrlName下唯一
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加 IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
IsTop bool `IsTop,omitempty` // blog是否置顶 IsTop bool `IsTop,omitempty` // blog是否置顶
HasSelfDefined bool `HasSelfDefined` // 是否已经自定义博客图片, desc, abstract
// 2014/9/28 添加评论社交功能 // 2014/9/28 添加评论社交功能
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28 ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
@@ -40,11 +38,6 @@ type Note struct {
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间 RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置 PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了 UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted` // 删除位
} }
// 内容 // 内容
@@ -80,24 +73,3 @@ type NoteContentHistory struct {
UserId bson.ObjectId `bson:"UserId"` // 所属者 UserId bson.ObjectId `bson:"UserId"` // 所属者
Histories []EachHistory `Histories` 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
}
-5
View File
@@ -13,16 +13,11 @@ type Notebook struct {
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级 ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
Seq int `Seq` // 排序 Seq int `Seq` // 排序
Title string `Title` // 标题 Title string `Title` // 标题
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
NumberNotes int `NumberNotes` // 笔记数 NumberNotes int `NumberNotes` // 笔记数
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加 IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
CreatedTime time.Time `CreatedTime,omitempty` CreatedTime time.Time `CreatedTime,omitempty`
UpdatedTime time.Time `UpdatedTime,omitempty` UpdatedTime time.Time `UpdatedTime,omitempty`
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
} }
// 仅仅是为了返回前台 // 仅仅是为了返回前台
+2 -1
View File
@@ -1,6 +1,7 @@
package info package info
import () import (
)
// controller ajax返回 // controller ajax返回
type Re struct { type Re struct {
-2
View File
@@ -14,8 +14,6 @@ type Session struct {
LoginTimes int `LoginTimes` // 登录错误时间 LoginTimes int `LoginTimes` // 登录错误时间
Captcha string `Captcha` // 验证码 Captcha string `Captcha` // 验证码
UserId string `UserId` // API时有值UserId
CreatedTime time.Time `CreatedTime` CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空 UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
} }
+2 -6
View File
@@ -76,9 +76,7 @@ type SharingNotebookAndNotes struct {
type ShareNotebook struct { type ShareNotebook struct {
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
UserId bson.ObjectId `bson:"UserId"` UserId bson.ObjectId `bson:"UserId"`
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"` ToUserId bson.ObjectId `bson:"ToUserId"`
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
NotebookId bson.ObjectId `bson:"NotebookId"` NotebookId bson.ObjectId `bson:"NotebookId"`
Seq int `bson:"Seq"` // 排序 Seq int `bson:"Seq"` // 排序
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改 Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
@@ -136,9 +134,7 @@ type ShareNotebooksByUser struct {
type ShareNote struct { type ShareNote struct {
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
UserId bson.ObjectId `bson:"UserId"` UserId bson.ObjectId `bson:"UserId"`
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"` ToUserId bson.ObjectId `bson:"ToUserId"`
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
NoteId bson.ObjectId `bson:"NoteId"` NoteId bson.ObjectId `bson:"NoteId"`
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改 Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
CreatedTime time.Time `CreatedTime` CreatedTime time.Time `CreatedTime`
-37
View File
@@ -2,55 +2,18 @@ package info
import ( import (
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"time"
) )
// 这里主要是为了统计每个tag的note数目 // 这里主要是为了统计每个tag的note数目
// 暂时没用
/*
type TagNote struct { type TagNote struct {
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键 TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
UserId bson.ObjectId `bson:"UserId"` UserId bson.ObjectId `bson:"UserId"`
Tag string `Title` // 标题 Tag string `Title` // 标题
NoteNum int `NoteNum` // note数目 NoteNum int `NoteNum` // note数目
} }
*/
// 每个用户一条记录, 存储用户的所有tags // 每个用户一条记录, 存储用户的所有tags
type Tag struct { type Tag struct {
UserId bson.ObjectId `bson:"_id"` UserId bson.ObjectId `bson:"_id"`
Tags []string `Tags` Tags []string `Tags`
} }
// v2 版标签
type NoteTag struct {
TagId bson.ObjectId `bson:"_id"`
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag` // UserId, Tag是唯一索引
Usn int `Usn` // Update Sequence Number
Count int `Count` // 笔记数
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
IsDeleted bool `IsDeleted` // 删除位
}
type TagCount struct {
TagCountId bson.ObjectId `bson:"_id,omitempty"`
UserId bson.ObjectId `UserId` // 谁的
Tag string `Tag`
IsBlog bool `IsBlog` // 是否是博客的tag统计
Count int `Count` // 统计数量
}
/*
type TagsCounts []TagCount
func (this TagsCounts) Len() int {
return len(this)
}
func (this TagsCounts) Less(i, j int) bool {
return this[i].Count > this[j].Count
}
func (this TagsCounts) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
*/
-26
View File
@@ -1,26 +0,0 @@
package info
import (
"gopkg.in/mgo.v2/bson"
"time"
)
// 主题, 每个用户有多个主题, 这里面有主题的配置信息
// 模板, css, js, images, 都在路径Path下
type Theme struct {
ThemeId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
UserId bson.ObjectId `UserId`
Name string `Name`
Version string `Version`
Author string `Author`
AuthorUrl string `AuthorUrl`
Path string `Path` // 文件夹路径, public/upload/54d7620d99c37b030600002c/themes/54d867c799c37b533e000001
Info map[string]interface{} `Info` // 所有信息
IsActive bool `IsActive` // 是否在用
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
}
-54
View File
@@ -34,58 +34,4 @@ type User struct {
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别 ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示 ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
ThirdType int `ThirdType` // 第三方类型 ThirdType int `ThirdType` // 第三方类型
// 用户的帐户类型
ImageNum int `bson:"ImageNum" json:"-"` // 图片数量
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
FromUserId bson.ObjectId `FromUserId,omitempty` // 邀请的用户
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
// 阈值
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum , 全局的
FullSyncBefore time.Time `bson:"FullSyncBefore"` // 需要全量同步的时间, 如果 > 客户端的LastSyncTime, 则需要全量更新
}
type UserAccount struct {
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
// 阈值
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
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不会认为是主键
Email string `Email` // 全是小写
Username string `Username` // 不区分大小写, 全是小写
Logo string `Logo`
BlogTitle string `BlogTitle` // 博客标题
BlogLogo string `BlogLogo` // 博客Logo
BlogUrl string `BlogUrl` // 博客链接, 主页
BlogUrls // 各个页面
} }
+2 -2
View File
@@ -4,11 +4,11 @@ import (
"math" "math"
) )
// 分页数据 // 分页数据
type Page struct { type Page struct {
CurPage int // 当前页码 CurPage int // 当前页码
TotalPage int // 总页 TotalPage int // 总页
PerPageSize int
Count int // 总记录数 Count int // 总记录数
List interface{} List interface{}
} }
@@ -18,5 +18,5 @@ func NewPage(page, perPageSize, count int, list interface{}) Page {
if count > 0 { if count > 0 {
totalPage = int(math.Ceil(float64(count) / float64(perPageSize))) totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
} }
return Page{page, totalPage, perPageSize, count, list} return Page{page, totalPage, count, list}
} }
+29 -158
View File
@@ -1,26 +1,24 @@
package app package app
import ( import (
"encoding/json" "github.com/revel/revel"
"fmt" . "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"
"github.com/leanote/leanote/app/controllers/admin" "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/binder"
"github.com/leanote/leanote/app/lea/i18n" "github.com/leanote/leanote/app/lea/session"
"github.com/leanote/leanote/app/lea/memcache"
"github.com/leanote/leanote/app/lea/route" "github.com/leanote/leanote/app/lea/route"
"github.com/leanote/leanote/app/service" "reflect"
"github.com/revel/revel" "fmt"
"html/template" "html/template"
"math" "math"
"net/url"
"reflect"
"strconv"
"strings" "strings"
"strconv"
"time" "time"
"encoding/json"
) )
func init() { func init() {
@@ -32,17 +30,16 @@ func init() {
// AuthFilter, // Invoke the action. // AuthFilter, // Invoke the action.
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters. revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params. revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie. // revel.SessionFilter, // Restore and write the session cookie.
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到 // 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web // session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
// session.SessionFilter, // leanote session session.SessionFilter, // leanote session
// session.MSessionFilter, // leanote memcache session // session.MSessionFilter, // leanote memcache session
revel.FlashFilter, // Restore and write the flash cookie. revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie. revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
// revel.I18nFilter, // Resolve the requested language revel.I18nFilter, // Resolve the requested language
i18n.I18nFilter, // Resolve the requested language by leanote
revel.InterceptorFilter, // Run interceptors around the action. revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result. revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action. revel.ActionInvoker, // Invoke the action.
@@ -51,31 +48,14 @@ func init() {
revel.TemplateFuncs["raw"] = func(str string) template.HTML { revel.TemplateFuncs["raw"] = func(str string) template.HTML {
return template.HTML(str) return template.HTML(str)
} }
revel.TemplateFuncs["trim"] = func(str string) string {
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
str = strings.Trim(str, "\n")
str = strings.Trim(str, "&nbsp;")
// 以下两个空格不一样
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
return str
}
revel.TemplateFuncs["add"] = func(i int) string { revel.TemplateFuncs["add"] = func(i int) string {
i = i + 1 i = i + 1;
return fmt.Sprintf("%v", i) return fmt.Sprintf("%v", i)
} }
revel.TemplateFuncs["sub"] = func(i int) int { revel.TemplateFuncs["sub"] = func(i int) int {
i = i - 1 i = i - 1;
return i return i
} }
// 增加或减少
revel.TemplateFuncs["incr"] = func(n, i int) int {
n = n + i
return n
}
revel.TemplateFuncs["join"] = func(arr []string) template.HTML { revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
if arr == nil { if arr == nil {
return template.HTML("") return template.HTML("")
@@ -92,24 +72,13 @@ func init() {
} }
return str return str
} }
revel.TemplateFuncs["decodeUrlValue"] = func(i string) string {
v, _ := url.ParseQuery("a=" + i)
return v.Get("a")
}
revel.TemplateFuncs["json"] = func(i interface{}) string { revel.TemplateFuncs["json"] = func(i interface{}) string {
b, _ := json.Marshal(i) b, _ := json.Marshal(i)
return string(b) return string(b)
} }
revel.TemplateFuncs["jsonJs"] = func(i interface{}) template.JS {
b, _ := json.Marshal(i)
return template.JS(string(b))
}
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML { revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
return template.HTML(t.Format("2006-01-02 15:04:05")) return template.HTML(t.Format("2006-01-02 15:04:05"))
} }
revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML {
return template.HTML(t.Format(format))
}
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML { revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
sec, _ := strconv.Atoi(unixSec) sec, _ := strconv.Atoi(unixSec)
t := time.Unix(int64(sec), 0) t := time.Unix(int64(sec), 0)
@@ -124,7 +93,6 @@ func init() {
} }
// tags // tags
// 2014/12/30 标签添加链接
revel.TemplateFuncs["blogTags"] = func(renderArgs map[string]interface{}, tags []string) template.HTML { revel.TemplateFuncs["blogTags"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
if tags == nil || len(tags) == 0 { if tags == nil || len(tags) == 0 {
return "" return ""
@@ -132,113 +100,18 @@ func init() {
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string) locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
tagStr := "" tagStr := ""
lenTags := len(tags) lenTags := len(tags)
tagPostUrl, _ := renderArgs["tagPostsUrl"].(string)
for i, tag := range tags { for i, tag := range tags {
str := revel.Message(locale, tag) str := revel.Message(locale, tag)
var classes = "label"
if strings.HasPrefix(str, "???") { if strings.HasPrefix(str, "???") {
str = tag str = tag
} }
if InArray([]string{"red", "blue", "yellow", "green"}, tag) { tagStr += str
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + "/" + tag
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
if i != lenTags - 1 { if i != lenTags - 1 {
tagStr += " " tagStr += ","
} }
} }
return template.HTML(tagStr) return template.HTML(tagStr)
} }
revel.TemplateFuncs["blogTagsForExport"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
tagStr := ""
lenTags := len(tags)
for i, tag := range tags {
str := tag
var classes = "label"
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>"
if i != lenTags-1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
revel.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, 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 typeStr == "recommend" {
tagPostUrl += "?tag="
} else if typeStr == "latest" {
tagPostUrl += "latest?tag="
} else {
tagPostUrl += "subscription?tag="
}
for i, tag := range tags {
str := revel.Message(locale, tag)
var classes = "label"
if strings.HasPrefix(str, "???") {
str = tag
}
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
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 { revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
if tags == nil || len(tags) == 0 { if tags == nil || len(tags) == 0 {
@@ -262,6 +135,8 @@ func init() {
} }
*/ */
revel.TemplateFuncs["li"] = func(a string) string { revel.TemplateFuncs["li"] = func(a string) string {
Log(a)
Log("life==")
return "" return ""
} }
// str连接 // str连接
@@ -270,7 +145,7 @@ func init() {
for i := 0; i < len(v); i = i + 2 { for i := 0; i < len(v); i = i + 2 {
item := v[i] item := v[i]
if i+1 == len(v) { if i+1 == len(v) {
break break;
} }
value := v[i+1] value := v[i+1]
if item != nil && value != nil { if item != nil && value != nil {
@@ -327,21 +202,21 @@ func init() {
if sorterI != nil { if sorterI != nil {
sorter, _ = sorterI.(string) sorter, _ = sorterI.(string)
} }
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"" html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"";
html += " class=\"th-sortable " html += " class=\"th-sortable ";
if sorter == sorterField + "-up" { if sorter == sorterField + "-up" {
html += "th-sort-up\"" html += "th-sort-up\"";
} else if sorter == sorterField+"-down" { } else if(sorter == sorterField + "-down") {
html += "th-sort-down" html += "th-sort-down";
} }
html += "\"" html += "\"";
return template.HTMLAttr(html) return template.HTMLAttr(html)
} }
// pagination // pagination
revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML { revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML {
if count == 0 { if count == 0 {
return "" return "";
} }
totalPage := int(math.Ceil(float64(count)/float64(pageSize))) totalPage := int(math.Ceil(float64(count)/float64(pageSize)))
@@ -373,7 +248,6 @@ func init() {
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js // https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
// http://play.golang.org/p/snygrVpQva // 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 // 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 { revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
switch a1.(type) { switch a1.(type) {
case string: case string:
@@ -399,7 +273,6 @@ func init() {
} }
return false return false
} }
*/
/* /*
{{range $i := N 1 10}} {{range $i := N 1 10}}
@@ -420,17 +293,15 @@ func init() {
// init Email // init Email
revel.OnAppStart(func() { revel.OnAppStart(func() {
// 数据库 // 数据库
db.Init("", "") db.Init()
// email配置 // email配置
InitEmail() InitEmail()
InitVd() InitVd()
// memcache.InitMemcache() // session服务 memcache.InitMemcache() // session服务
// 其它service // 其它service
service.InitService() service.InitService()
controllers.InitService() controllers.InitService()
admin.InitService() admin.InitService()
member.InitService()
service.ConfigS.InitGlobalConfigs() service.ConfigS.InitGlobalConfigs()
api.InitService()
}) })
} }
+2 -21
View File
@@ -2,33 +2,14 @@ package lea
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/revel/revel" "github.com/revel/revel"
) )
func Log(i ...interface{}) { func Log(i interface{}) {
revel.INFO.Println(i...) 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{}) { func LogJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ") b, _ := json.MarshalIndent(i, "", " ")
revel.INFO.Println(string(b)) revel.INFO.Println(string(b))
} }
// 为test用
func L(i interface{}) {
fmt.Println(i)
}
func LJ(i interface{}) {
b, _ := json.MarshalIndent(i, "", " ")
fmt.Println(string(b))
}
+3 -5
View File
@@ -1,11 +1,10 @@
package lea package lea
import ( import (
"github.com/revel/revel"
"net/smtp" "net/smtp"
"strings" "strings"
"github.com/revel/revel"
) )
// 发送邮件 // 发送邮件
var host = "smtp.ym.163.com" var host = "smtp.ym.163.com"
var port = "25" var port = "25"
@@ -13,7 +12,7 @@ var username = "noreply@leanote.com"
var password = "---" var password = "---"
func InitEmail() { func InitEmail() {
config := revel.Config config := revel.Config;
host, _ = config.String("email.host") host, _ = config.String("email.host")
port, _ = config.String("email.port") port, _ = config.String("email.port")
username, _ = config.String("email.username") username, _ = config.String("email.username")
@@ -57,7 +56,6 @@ var bodyTpl = `
</body> </body>
</html> </html>
` `
func SendEmailOld(to, subject, body string) bool { func SendEmailOld(to, subject, body string) bool {
hp := strings.Split(host, ":") hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", username, password, hp[0]) auth := smtp.PlainAuth("", username, password, hp[0])
@@ -87,5 +85,5 @@ func SendEmailOld(to, subject, body string) bool {
func SendToLeanoteOld(subject, title, body string) { func SendToLeanoteOld(subject, title, body string) {
to := "leanote@leanote.com" to := "leanote@leanote.com"
SendEmailOld(to, subject, body) SendEmailOld(to, subject, body);
} }
+5 -105
View File
@@ -1,11 +1,10 @@
package lea package lea
import ( import (
"io"
"io/ioutil"
"os"
"path/filepath"
"strings" "strings"
"path/filepath"
"os"
"io"
) )
// 分离文件名与扩展名(包含.) // 分离文件名与扩展名(包含.)
@@ -15,7 +14,7 @@ func SplitFilename(filename string) (baseName, ext string) {
ext = SubstringByte(filename, strings.LastIndex(filename, ".")) ext = SubstringByte(filename, strings.LastIndex(filename, "."))
baseName = strings.TrimRight(filename, ext) baseName = strings.TrimRight(filename, ext)
ext = strings.ToLower(ext) ext = strings.ToLower(ext)
return return;
} }
// 转换文件的格式 // 转换文件的格式
@@ -39,7 +38,7 @@ func GetFilesize(path string) int64 {
if err == nil { if err == nil {
return fileinfo.Size() return fileinfo.Size()
} }
return 0 return 0;
} }
// 清空dir下所有的文件和文件夹 // 清空dir下所有的文件和文件夹
@@ -56,14 +55,6 @@ func ClearDir(dir string) bool {
return true return true
} }
func MkdirAll(dir string) bool {
err := os.MkdirAll(dir, 0777)
if err != nil {
return false
}
return true
}
// list dir's all file, return filenames // list dir's all file, return filenames
func ListDir(dir string) []string { func ListDir(dir string) []string {
f, err := os.Open(dir) f, err := os.Open(dir)
@@ -88,55 +79,6 @@ func CopyFile(srcName, dstName string) (written int64, err error) {
return io.Copy(dst, src) return io.Copy(dst, src)
} }
func CopyDir(source string, dest string) (err error) {
// get properties of source dir
sourceinfo, err := os.Stat(source)
if err != nil {
return err
}
// create dest dir
err = os.MkdirAll(dest, sourceinfo.Mode())
if err != nil {
return err
}
directory, _ := os.Open(source)
objects, err := directory.Readdir(-1)
for _, obj := range objects {
sourcefilepointer := source + "/" + obj.Name()
destinationfilepointer := dest + "/" + obj.Name()
if obj.IsDir() {
// create sub-directories - recursively
err = CopyDir(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
}
} else {
// perform copy
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
}
}
}
return
}
func DeleteFile(path string) bool {
err := os.Remove(path)
if err != nil {
return false
}
return true
}
func IsDirExists(path string) bool { func IsDirExists(path string) bool {
fi, err := os.Stat(path) fi, err := os.Stat(path)
if err != nil { if err != nil {
@@ -146,45 +88,3 @@ func IsDirExists(path string) bool {
} }
return false return false
} }
// 获得文件str内容
func GetFileStrContent(path string) string {
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
return ""
}
return string(fileBytes)
}
func IsFileExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
// 写入string内容
func PutFileStrContent(path, content string) bool {
var f *os.File
var err1 error
defer (func() {
if f != nil {
f.Close()
}
})()
f, err1 = os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) //打开文件
// Log(err1)
// var n int
_, err1 = io.WriteString(f, content) //写入文件(字符串)
// Log(content)
// Log(err1)
// Log(n)
// Log(path)
if err1 != nil {
Log(err1)
return false
}
return true
}
-22
View File
@@ -1,22 +0,0 @@
package lea
// 对比密码是否一致
// 因为之前密码是用md5加密的, 所以通过密码长度来判断
// rawPwd 原始, 用户输入的密码
func ComparePwd(rawPwd, dbPwd string) bool {
if len(dbPwd) == 32 {
return Md5(rawPwd) == dbPwd
}
hex := []byte(dbPwd)
return CompareHash(hex, rawPwd)
}
// 加密
func GenPwd(rawPwd string) string {
digest, err := GenerateHash(rawPwd)
if err != nil {
return ""
}
return string(digest)
}
+27 -179
View File
@@ -1,19 +1,16 @@
package lea package lea
import ( import (
"bytes" "fmt"
"regexp"
"crypto/md5" "crypto/md5"
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"fmt"
"github.com/PuerkitoBio/goquery"
"gopkg.in/mgo.v2/bson"
"io" "io"
math_rand "math/rand" "gopkg.in/mgo.v2/bson"
"regexp"
"strings"
"time" "time"
math_rand "math/rand"
) )
// 字符串 // 字符串
@@ -25,22 +22,6 @@ func Md5(s string) string {
return hex.EncodeToString(h.Sum(nil)) return hex.EncodeToString(h.Sum(nil))
} }
// 3位数的转换, 为了用bson.id -> 3位数
func Digest3(str string) string {
var b rune = 0
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b%1000)
}
func Digest2(str string) string {
var b rune = 0
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b%100)
}
// Guid // Guid
func NewGuid() string { func NewGuid() string {
b := make([]byte, 48) b := make([]byte, 48)
@@ -141,49 +122,39 @@ func ReplaceAll(oldStr, pattern, newStr string) string {
return string(s) return string(s)
} }
// 获取纯文本 func SubStringHTML(param string, length int, end string) string {
func SubStringHTMLToRaw(param string, length int) string { // 先取出<pre></pre>占位..
if param == "" {
return param result := ""
}
// 1
n := 0 n := 0
var temp rune // 中文问题, 用rune来解决 var temp rune // 中文问题, 用rune来解决
isCode := false //是不是HTML代码
isHTML := false //是不是HTML特殊字符,如&nbsp;
rStr := []rune(param) rStr := []rune(param)
lenStr := len(rStr) for i := 0; i < len(rStr); i++ {
isCode := false
resultRune := make([]rune, length)
// s := ""
for i := 0; i < lenStr; i++ {
temp = rStr[i] temp = rStr[i]
if temp == '<' { if temp == '<' {
isCode = true isCode = true
continue } else if temp == '&' {
} else if temp == '>' { isHTML = true
} else if temp == '>' && isCode {
n = n - 1
isCode = false isCode = false
resultRune[n] = ' ' } else if temp == ';' && isHTML {
isHTML = false
n++
if n >= length {
break
} }
continue if !isCode && !isHTML {
n = n + 1
} }
if !isCode { result += string(temp)
resultRune[n] = temp
// s += string(temp)
n++
if n >= length { if n >= length {
break break
} }
} }
} result += end
result := string(resultRune[0:n])
return strings.Trim(result, " ")
}
// 自带方法补全html
func fixHtml(result string) string {
// 取出所有标签 // 取出所有标签
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了 tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
@@ -225,72 +196,6 @@ func fixHtml(result string) string {
return result return result
} }
// 获取摘要, HTML
func SubStringHTML(param string, length int, end string) string {
if param == "" {
return param
}
result := ""
rStr := []rune(param)
lenStr := len(rStr)
if lenStr <= length {
result = param
} else {
// 1
n := 0
var temp rune // 中文问题, 用rune来解决
isCode := false //是不是HTML代码
isHTML := false //是不是HTML特殊字符,如&nbsp;
var i = 0
for ; i < lenStr; i++ {
temp = rStr[i]
if temp == '<' {
isCode = true
} else if temp == '&' {
isHTML = true
} else if temp == '>' && isCode {
// n = n - 1
isCode = false
} else if temp == ';' && isHTML {
isHTML = false
}
if !isCode && !isHTML {
n = n + 1
}
// 每一次都相加, 速度非常慢!, 重新分配内存, 7倍的差距
// result += string(temp)
if n >= length {
break
}
}
result = string(rStr[0:i])
if end != "" {
result += end
}
}
// 使用goquery来取出html, 为了补全html
htmlReader := bytes.NewBufferString(result)
dom, err1 := goquery.NewDocumentFromReader(htmlReader)
if err1 == nil {
html, _ := dom.Html()
html = strings.Replace(html, "<html><head></head><body>", "", 1)
html = strings.Replace(html, "</body></html>", "", 1)
// TODO 把style="float: left"去掉
return html
// 如果有错误, 则使用自己的方法补全, 有风险
} else {
return fixHtml(result)
}
}
// 是否是合格的密码 // 是否是合格的密码
func IsGoodPwd(pwd string) (bool, string) { func IsGoodPwd(pwd string) (bool, string) {
if pwd == "" { if pwd == "" {
@@ -305,16 +210,16 @@ func IsGoodPwd(pwd string) (bool, string) {
// 是否是email // 是否是email
func IsEmail(email string) bool { func IsEmail(email string) bool {
if email == "" { if email == "" {
return false return false;
} }
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.|\-]?)*[_a-z\-A-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-zA-Z0-9\-]+\.[0-9a-zA-Z]{2,6}$`, email) ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[0-9a-zA-Z]{2,3}$`, email)
return ok return ok
} }
// 是否只包含数字, 字母 -, _ // 是否只包含数字, 字母 -, _
func IsUsername(username string) bool { func IsUsername(username string) bool {
if username == "" { if username == "" {
return false return false;
} }
ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username) ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username)
return !ok return !ok
@@ -351,7 +256,7 @@ func RandomPwd(num int) string {
chars[j] = byte(i) chars[j] = byte(i)
j++ j++
} }
j-- j--;
str := "" str := ""
math_rand.Seed(time.Now().UnixNano()) math_rand.Seed(time.Now().UnixNano())
@@ -374,60 +279,3 @@ func InArray(arr []string, str string) bool {
} }
return false return false
} }
// 将名称的特殊字符去掉
func FixFilename(filename string) string {
if filename != "" {
// 把特殊字段给替换掉
// str := `life "%&()+,/:;<>=?@\|`
// . == \\.
// $ === \\$
reg, _ := regexp.Compile("\\.|/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
filename = reg.ReplaceAllString(filename, "-")
filename = strings.Trim(filename, "-") // 左右单独的-去掉
// 把空格替换成-
// filename = strings.Replace(filename, " ", "-", -1)
for strings.Index(filename, "--") >= 0 { // 防止出现连续的--
filename = strings.Replace(filename, "--", "-", -1)
}
return filename
}
return filename
}
// 是否是合法的时间
// 不是, 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)
}
+1 -26
View File
@@ -2,8 +2,8 @@ package lea
import ( import (
"encoding/json" "encoding/json"
"regexp"
"strconv" "strconv"
"regexp"
) )
// 验证 // 验证
@@ -27,12 +27,6 @@ var rulesStr = `{
], ],
"domain": [ "domain": [
{"rule": "domain", "msg": "errorDomain"} {"rule": "domain", "msg": "errorDomain"}
],
"perPageSize": [
{"rule": "min", "data": "1", "msg": "errorPerPageSize"}
],
"sortField": [
{"rule": "sortField", "msg": "errorSortField"}
] ]
} }
` `
@@ -55,25 +49,6 @@ var rules = map[string]func(string, map[string]string) (bool, string){
ok = len(value) >= dataI ok = len(value) >= dataI
return return
}, },
"min": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
data := rule["data"]
dataI, _ := strconv.Atoi(data)
vI, _ := strconv.Atoi(value)
ok = vI >= dataI
return
},
"sortField": func(value string, rule map[string]string) (ok bool, msg string) {
if value == "" {
return
}
sortFields := []string{"PublicTime", "CreatedTime", "UpdatedTime", "Title"}
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 == "" { if value == "" {
-230
View File
@@ -1,230 +0,0 @@
package archive
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path"
)
// main functions shows how to TarGz a directory/file and
// UnTarGz a file
// Gzip and tar from source directory or file to destination file
// you need check file exist before you call this function
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)
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异常
if err := recover(); err != nil {
ok = false
}
}()
fw, err := os.Create(destFilePath)
if err != nil {
panic(err)
}
defer fw.Close()
// Gzip writer
gw := gzip.NewWriter(fw)
defer gw.Close()
// 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
// if find files, handle them with tarGzFile
// 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()
// 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)
}
}
// 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() // 加这个会有错误!!
// 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()
// Write hander
err = tw.WriteHeader(hdr)
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)
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()
// 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!")
}
// 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)
}
-199
View File
@@ -1,199 +0,0 @@
package archive
import (
"archive/zip"
"fmt"
"io"
"os"
"path"
"strings"
"github.com/leanote/leanote/app/lea"
)
// main functions shows how to TarGz a directory/file and
// UnTarGz a file
// Gzip and tar from source directory or file to destination file
// you need check file exist before you call this function
func Zip(srcDirPath string, destFilePath string) (ok bool) {
defer func() { //必须要先声明defer,否则不能捕获到panic异常
if err := recover(); err != nil {
ok = false
}
}()
fw, err := os.Create(destFilePath)
if err != nil {
panic(err)
}
defer fw.Close()
// 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
// if find files, handle them with zipFile
// 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()
// 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)
}
}
// 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()
// 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
// you need check file exist before you call this function
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
ok = false
msg = ""
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)
if err != nil {
panic(err)
}
defer r.Close()
for _, f := range r.File {
// 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)
if l > 1 {
// 去掉第1个文件夹
if l == 2 {
filename = paths[1]
} else {
filename = paths[l-1]
prePath = strings.Join(paths[1:l-1], "/")
}
} else {
filename = f.Name
}
// fmt.Println(prePath)
// 相对于目标文件件下的路径
destPath := destDirPath + "/" + filename
if prePath != "" {
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)
}
}
ok = true
return
}
+7 -43
View File
@@ -1,9 +1,9 @@
package binder package binder
import ( import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel" "github.com/revel/revel"
// "github.com/leanote/leanote/app/controllers/api" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/controllers"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@@ -53,36 +53,16 @@ func nextKey(key string) string {
} }
return key[:fieldLen] return key[:fieldLen]
} }
var leanoteStructBinder = revel.Binder{ var leanoteStructBinder = revel.Binder{
// name == "noteOrContent"
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value { Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取 result := reflect.New(typ).Elem()
fieldValues := make(map[string]reflect.Value) fieldValues := make(map[string]reflect.Value)
// fmt.Println(name) for key, _ := range params.Values {
// fmt.Println(typ) // api.NoteFiles
// name = files[0], files[1], noteContent
// fmt.Println(params.Values)
/*
map[Title:[test1] METHOD:[POST] NotebookId:[54c4f51705fcd14031000002]
files[1][FileId]:[]
controller:[note]
files[1][LocalFileId]:[54c7ae27d98d0329dd000000] files[1][HasBody]:[true] files[0][FileId]:[] files[0][LocalFileId]:[54c7ae855e94ea2dba000000] action:[addNote] Content:[<p>lifedddddd</p><p><img src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" alt="" data-mce-src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" style="display: block; margin-left: auto; margin-right: auto;"></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae27d98d0329dd000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImg?fileId=54c7ae27d98d0329dd000000"></p><p><br></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" style="display: block; margin-left: auto; margin-right: auto;"></p><p><br></p><p><br></p>] IsBlog:[false] token:[user1]
files[0][HasBody]:[true]]
*/
nameIsSlice := strings.Contains(name, "[")
// fmt.Println(params.Values["files[1]"])
// fmt.Println(params.Values["Title"])
for key, _ := range params.Values { // Title, Content, Files
// 这里, 如果没有点, 默认就是a. // 这里, 如果没有点, 默认就是a.
// life // life
// fmt.Println("key:" + key); // files[0][LocalFileId]
// fmt.Println("name:" + name); // files[0][LocalFileId]
var suffix string var suffix string
var noPrefix = false var noPrefix = false
if nameIsSlice && strings.HasPrefix(key, name) { if !strings.HasPrefix(key, name + ".") {
suffix = key[len(name)+1 : len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
} else if !strings.HasPrefix(key, name+".") {
noPrefix = true noPrefix = true
suffix = key suffix = key
// continue // continue
@@ -91,18 +71,13 @@ var leanoteStructBinder = revel.Binder{
// Strip off the prefix. e.g. foo.bar.baz => bar.baz // Strip off the prefix. e.g. foo.bar.baz => bar.baz
suffix = key[len(name)+1:] suffix = key[len(name)+1:]
} }
// fmt.Println(suffix);
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar" fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
// fmt.Println(fieldName);
fieldLen := len(fieldName) fieldLen := len(fieldName)
if _, ok := fieldValues[fieldName]; !ok { if _, ok := fieldValues[fieldName]; !ok {
// Time to bind this field. Get it and make sure we can set it. // Time to bind this field. Get it and make sure we can set it.
fieldName = strings.Title(fieldName) // 传过来title, 但struct是Title
// fmt.Println("xx: " + fieldName)
fieldValue := result.FieldByName(fieldName) fieldValue := result.FieldByName(fieldName)
// fmt.Println(fieldValue)
if !fieldValue.IsValid() { if !fieldValue.IsValid() {
continue continue
} }
@@ -111,17 +86,9 @@ var leanoteStructBinder = revel.Binder{
} }
var boundVal reflect.Value var boundVal reflect.Value
// 没有name前缀 // 没有name前缀
if noPrefix { if(noPrefix) {
// life
// fmt.Println("<<")
// fmt.Println(strings.Title(key[:fieldLen]));
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type()) boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
} else { } else {
// fmt.Println("final")
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
if nameIsSlice {
fieldLen += 1
}
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type()) boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
} }
fieldValue.Set(boundVal) fieldValue.Set(boundVal)
@@ -149,8 +116,5 @@ func init() {
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.UserAccount{})] = leanoteStructBinder revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteOrContent{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
} }
-298
View File
@@ -1,298 +0,0 @@
package blog
import (
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"html/template"
"io/ioutil"
// "os"
"bytes"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
)
//--------------------
// leanote 自定义主题
// 不使用revel的模板机制
// By life
//--------------------
var ts = []string{"header.html", "footer.html", "highlight.html", "comment.html", "view.html", "404.html"}
var selfTs = []string{"header.html", "footer.html", "index.html", "about_me.html"} // 用户自定义的文件列表
type BlogTpl struct {
Template *template.Template
PathContent map[string]string // path => content
}
func (this *BlogTpl) Content(name string) string {
return this.PathContent[name]
}
var BlogTplObject *BlogTpl
var CloneTemplate *template.Template
type RenderTemplateResult struct {
Template *template.Template
PathContent map[string]string
RenderArgs map[string]interface{}
IsPreview bool // 是否是预览
CurBlogTpl *BlogTpl
}
func parseTemplateError(err error) (templateName string, line int, description string) {
description = err.Error()
i := regexp.MustCompile(`:\d+:`).FindStringIndex(description)
if i != nil {
line, err = strconv.Atoi(description[i[0]+1 : i[1]-1])
if err != nil {
}
templateName = description[:i[0]]
if colon := strings.Index(templateName, ":"); colon != -1 {
templateName = templateName[colon+1:]
}
templateName = strings.TrimSpace(templateName)
description = description[i[1]+1:]
}
return templateName, line, description
}
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
err := r.Template.Execute(wr, r.RenderArgs)
if err == nil {
return
}
var templateContent []string
templateName, line, description := parseTemplateError(err)
var content = ""
if templateName == "" {
templateName = r.Template.Name()
content = r.PathContent[templateName]
} else {
content = r.PathContent[templateName]
}
if content != "" {
templateContent = strings.Split(content, "\n")
}
compileError := &revel.Error{
Title: "Template Execution Error",
Path: templateName,
Description: description,
Line: line,
SourceLines: templateContent,
}
// 这里, 错误!!
// 这里应该导向到本主题的错误页面
resp.Status = 500
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
}
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
// Handle panics when rendering templates.
defer func() {
if err := recover(); err != nil {
}
}()
chunked := revel.Config.BoolDefault("results.chunked", false)
// If it's a HEAD request, throw away the bytes.
out := io.Writer(resp.Out)
if req.Method == "HEAD" {
out = ioutil.Discard
}
// In a prod mode, write the status, render, and hope for the best.
// (In a dev mode, always render to a temporary buffer first to avoid having
// error pages distorted by HTML already written)
if chunked && !revel.DevMode {
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
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
// would carry a 200 status code)
var b bytes.Buffer
r.render(req, resp, &b)
if !chunked {
resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len()))
}
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
b.WriteTo(out)
}
// 博客模板
func Init() {
BlogTplObject = &BlogTpl{PathContent: map[string]string{}}
BlogTplObject.Template = template.New("blog").Funcs(revel.TemplateFuncs)
for _, path := range ts {
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
fileStr := string(fileBytes)
path := "blog/" + path
// path := path
BlogTplObject.PathContent[path] = fileStr
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
}
// 复制一份
CloneTemplate, _ = BlogTplObject.Template.Clone()
}
// name = index.html, search.html, cate.html, page.html
// basePath 表未用户主题的基路径, 如/xxx/public/upload/32323232/themes/theme1, 如果没有, 则表示用自带的
// isPreview 如果是, 错误提示则显示系统的 500 错误详情信息, 供debug
//
func RenderTemplate(name string, args map[string]interface{}, basePath string, isPreview bool) revel.Result {
var r *RenderTemplateResult
// 传来的主题路径为空, 则用系统的
// 都不会为空的
if basePath == "" {
path := "blog/" + name
// path := name
t := BlogTplObject.Template.Lookup(path)
r = &RenderTemplateResult{
Template: t,
PathContent: BlogTplObject.PathContent, // 为了显示错误
RenderArgs: args, // 把args给它
}
} else {
// 复制一份
newBlogTplObject := &BlogTpl{}
var err error
newBlogTplObject.Template, err = CloneTemplate.Clone() // 复制一份, 为防止多用户出现问题, 因为newBlogTplObject是全局的
if err != nil {
return nil
}
newBlogTplObject.PathContent = map[string]string{}
for k, v := range BlogTplObject.PathContent {
newBlogTplObject.PathContent[k] = v
}
// 将该basePath下的所有文件提出
files := ListDir(basePath)
for _, t := range files {
if !strings.Contains(t, ".html") {
continue
}
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
if err != nil {
continue
}
fileStr := string(fileBytes)
newBlogTplObject.PathContent[t] = fileStr
newBlogTplObject.Template.New(t).Parse(fileStr)
}
// 如果本主题下没有, 则用系统的
t := newBlogTplObject.Template.Lookup(name)
if t == nil {
path := "blog/" + name
t = BlogTplObject.Template.Lookup(path)
}
r = &RenderTemplateResult{
Template: t,
PathContent: newBlogTplObject.PathContent, // 为了显示错误
RenderArgs: args,
CurBlogTpl: newBlogTplObject,
IsPreview: isPreview,
}
}
return r
}
////////////////////
//
type ErrorResult struct {
RenderArgs map[string]interface{}
Error error
IsPreview bool
CurBlogTpl *BlogTpl
}
// 错误显示出
func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
format := req.Format
status := resp.Status
if status == 0 {
status = http.StatusInternalServerError
}
contentType := revel.ContentTypeByFilename("xxx." + format)
if contentType == revel.DefaultFileContentType {
contentType = "text/plain"
}
// Get the error template.
var err error
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
err = nil
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
// This func shows a plaintext error message, in case the template rendering
// doesn't work.
showPlaintext := func(err error) {
revel.PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+
"Additionally, an error occurred when rendering the error page:\n%s",
r.Error, err)}.Apply(req, resp)
}
// 根据是否是preview来得到404模板
// 是, 则显示系统的错误信息, blog-500.html
var tmpl *template.Template
if r.IsPreview {
tmpl = r.CurBlogTpl.Template.Lookup("blog/404.html")
} else {
tmpl = r.CurBlogTpl.Template.Lookup("404.html")
}
if tmpl == nil {
if err == nil {
err = fmt.Errorf("Couldn't find template %s", templatePath)
}
showPlaintext(err)
return
}
// If it's not a revel error, wrap it in one.
var revelError *revel.Error
switch e := r.Error.(type) {
case *revel.Error:
revelError = e
case error:
revelError = &revel.Error{
Title: "Server Error",
Description: e.Error(),
}
}
if revelError == nil {
panic("no error provided")
}
if r.RenderArgs == nil {
r.RenderArgs = make(map[string]interface{})
}
r.RenderArgs["Error"] = revelError
r.RenderArgs["Router"] = revel.MainRouter
// 不是preview就不要显示错误了
if r.IsPreview {
var b bytes.Buffer
out := io.Writer(resp.Out)
// out = ioutil.Discard
err = tmpl.Execute(&b, r.RenderArgs)
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
b.WriteTo(out)
}
}
+2 -4
View File
@@ -1,16 +1,15 @@
package captcha package captcha
import ( import (
crand "crypto/rand"
"image" "image"
"image/color" "image/color"
"image/png" "image/png"
"io" "io"
"math/rand" "math/rand"
"strconv" crand "crypto/rand"
"time" "time"
"strconv"
) )
const ( const (
stdWidth = 100 stdWidth = 100
stdHeight = 40 stdHeight = 40
@@ -133,7 +132,6 @@ type Image struct {
height int //a digit height height int //a digit height
dotsize int dotsize int
} }
func init(){ func init(){
rand.Seed(int64(time.Second)) rand.Seed(int64(time.Second))
} }
-26
View File
@@ -1,26 +0,0 @@
// contains two cryptographic functions for both storing and comparing passwords.
package lea
import (
"golang.org/x/crypto/bcrypt"
)
// GenerateHash generates bcrypt hash from plaintext password
func GenerateHash(password string) ([]byte, error) {
hex := []byte(password)
hashedPassword, err := bcrypt.GenerateFromPassword(hex, 10)
if err != nil {
return hashedPassword, err
}
return hashedPassword, nil
}
// CompareHash compares bcrypt password with a plaintext one. Returns true if passwords match
// and false if they do not.
func CompareHash(digest []byte, password string) bool {
hex := []byte(password)
if err := bcrypt.CompareHashAndPassword(digest, hex); err == nil {
return true
}
return false
}
+1
View File
@@ -7,3 +7,4 @@ import (
func Html2Image(userInfo info.User, note info.Note, content, toPath string) bool { func Html2Image(userInfo info.User, note info.Note, content, toPath string) bool {
return true return true
} }
-223
View File
@@ -1,223 +0,0 @@
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, ""
}
+66
View File
@@ -0,0 +1,66 @@
package memcache
import (
"github.com/robfig/gomemcache/memcache"
"encoding/json"
"strconv"
)
var client *memcache.Client
// onAppStart后调用
func InitMemcache() {
client = memcache.New("localhost:11211")
}
//------------
// map
func SetMap(key string, value map[string]string, expiration int32) {
// 把value转成byte
bytes, _ := json.Marshal(value)
if expiration == -1 {
expiration = 30 * 24 * 60 * 60 // 30天
}
client.Set(&memcache.Item{Key: key, Value: bytes, Expiration: expiration})
}
func GetMap(key string) map[string]string {
item, err := client.Get(key)
if err != nil {
return nil
}
m := map[string]string{}
json.Unmarshal(item.Value, &m)
return m
}
//------------
// string
func GetString(key string) string {
item, err := client.Get(key)
if err != nil {
return ""
}
return string(item.Value)
}
func SetString(key string, value string, expiration int32) {
if expiration == -1 {
expiration = 30 * 24 * 60 * 60 // 30天
}
client.Set(&memcache.Item{Key: key, Value: []byte(value), Expiration: expiration})
}
//-------------------------
// int, 是通过转成string来存的
func GetInt(key string) int {
str := GetString(key)
i, _ := strconv.Atoi(str)
return i
}
func SetInt(key string, value int, expiration int32) {
str := strconv.Itoa(value)
SetString(key, str, expiration)
}
+15 -26
View File
@@ -1,13 +1,11 @@
package netutil package netutil
import ( import (
"os"
"strings" "strings"
"os"
// "path/filepath" // "path/filepath"
. "github.com/leanote/leanote/app/lea"
"io/ioutil"
"net"
"net/http" "net/http"
"io/ioutil"
. "github.com/leanote/leanote/app/lea"
) )
// net的util // net的util
@@ -17,11 +15,11 @@ import (
// 返回文件的完整目录 // 返回文件的完整目录
func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) { func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) {
if url == "" { if url == "" {
return return;
} }
content, err := GetContent(url) content, err := GetContent(url)
if err != nil { if err != nil {
return return;
} }
length = int64(len(content)) length = int64(len(content))
@@ -54,7 +52,7 @@ func GetContent(url string) (content []byte, err error) {
var resp *http.Response var resp *http.Response
resp, err = http.Get(url) resp, err = http.Get(url)
Log(err) Log(err)
if resp != nil && resp.Body != nil { if(resp != nil && resp.Body != nil) {
defer resp.Body.Close() defer resp.Body.Close()
} else { } else {
} }
@@ -64,40 +62,31 @@ func GetContent(url string) (content []byte, err error) {
var buf []byte var buf []byte
buf, err = ioutil.ReadAll(resp.Body) buf, err = ioutil.ReadAll(resp.Body)
if err != nil { if(err != nil) {
Log(err) Log(err)
return return
} }
content = buf content = buf;
err = nil err = nil
return return
} }
// 将url ?, #后面的字符串去掉 // 将url ?, #后面的字符串去掉
func trimQueryParams(url string) string { func trimQueryParams(url string) string {
pos := strings.Index(url, "?") pos := strings.Index(url, "?");
if pos != -1 { if pos != -1 {
url = Substr(url, 0, pos) url = Substr(url, 0, pos);
} }
pos = strings.Index(url, "#") pos = strings.Index(url, "#");
if pos != -1 { if pos != -1 {
url = Substr(url, 0, pos) url = Substr(url, 0, pos);
} }
pos = strings.Index(url, "!") pos = strings.Index(url, "!");
if pos != -1 { if pos != -1 {
url = Substr(url, 0, pos) url = Substr(url, 0, pos);
} }
return url return url;
}
// 通过domain得到ip
func GetIpFromDomain(domain string) string {
ip, _ := net.LookupIP(domain)
if ip != nil && len(ip) > 0 {
return ip[0].String()
}
return ""
} }
+3 -11
View File
@@ -1,8 +1,8 @@
package route package route
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/revel/revel" "github.com/revel/revel"
// "github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"net/url" "net/url"
"strings" "strings"
@@ -11,7 +11,6 @@ import (
// overwite revel RouterFilter // overwite revel RouterFilter
// /api/user/Info => ApiUser.Info() // /api/user/Info => ApiUser.Info()
var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"} var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"}
func RouterFilter(c *revel.Controller, fc []revel.Filter) { func RouterFilter(c *revel.Controller, fc []revel.Filter) {
// 补全controller部分 // 补全controller部分
path := c.Request.Request.URL.Path path := c.Request.Request.URL.Path
@@ -43,18 +42,10 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
} }
*/ */
if route.ControllerName != "Static" { if route.ControllerName != "Static" {
// 检查mongodb 是否lost
db.CheckMongoSessionLost()
// api设置 // api设置
// leanote.com/api/user/get => ApiUser::Get // leanote.com/api/user/get => ApiUser::Get
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了 if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") {
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api") {
route.ControllerName = "Api" + route.ControllerName route.ControllerName = "Api" + route.ControllerName
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
// member设置
route.ControllerName = "Member" + route.ControllerName
} }
// end // end
} }
@@ -85,3 +76,4 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
fc[0](c, fc[1:]) fc[0](c, fc[1:])
} }
+38
View File
@@ -0,0 +1,38 @@
package session
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/lea/memcache"
. "github.com/leanote/leanote/app/lea"
)
// 使用filter
// 很巧妙就使用了memcache来处理session
// revel的session(cookie)只存sessionId, 其它信息存在memcache中
func MSessionFilter(c *revel.Controller, fc []revel.Filter) {
sessionId := c.Session.Id()
// 从memcache中得到cache, 赋给session
cache := revel.Session(memcache.GetMap(sessionId))
Log("memcache")
LogJ(cache)
if cache == nil {
cache = revel.Session{}
cache.Id()
}
c.Session = cache
// Make session vars available in templates as {{.session.xyz}}
c.RenderArgs["session"] = c.Session
fc[0](c, fc[1:])
// 再把session保存之
LogJ(c.Session)
memcache.SetMap(sessionId, c.Session, -1)
// 只留下sessionId
c.Session = revel.Session{revel.SESSION_ID_KEY: sessionId}
}
+208
View File
@@ -0,0 +1,208 @@
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)
}
+23 -35
View File
@@ -2,13 +2,11 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"io/ioutil"
"strings" "strings"
// "time"
) )
/* /*
用golang exec 总是说找不到uglifyjs命令, 需要全部路径 用golang exec 总是说找不到uglifyjs命令, 需要全部路径
而且node, npm要在/usr/bin下, 已建ln 而且node, npm要在/usr/bin下, 已建ln
@@ -54,7 +52,7 @@ func compressJs(filename string) {
to := base + filename + "-min.js" to := base + filename + "-min.js"
cmd := exec.Command(cmdPath, source, "-o", to) cmd := exec.Command(cmdPath, source, "-o", to)
_, err := cmd.CombinedOutput() _, err := cmd.CombinedOutput()
fmt.Println(source)
cmdError(err) cmdError(err)
} }
@@ -82,17 +80,14 @@ func combineJs() {
// 改note-dev->note // 改note-dev->note
func dev() { func dev() {
// 即替换note.js->note-min.js // 即替换note.js->note-min.js
m := map[string]string{"tinymce.dev.js": "tinymce.min.js", m := map[string]string{"note.js": "note-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", "app.js": "app-min.js",
"page.js": "page-min.js", "page.js": "page-min.js",
"common.js": "common-min.js", "common.js": "common-min.js",
"notebook.js": "notebook-min.js", "notebook.js": "notebook-min.js",
"share.js": "share-min.js", "share.js": "share-min.js",
"tag.js": "tag-min.js", "tag.js": "tag-min.js",
"jquery.slimscroll.js": "jquery.slimscroll-min.js", "main.js": "main-min.js",
"jquery.contextmenu.js": "jquery.contextmenu-min.js", "jquery.contextmenu.js": "jquery.contextmenu-min.js",
"editor/editor.js": "editor/editor-min.js", "editor/editor.js": "editor/editor-min.js",
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js", "/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
@@ -107,13 +102,6 @@ func dev() {
for key, value := range m { for key, value := range m {
content = strings.Replace(content, key, value, -1) content = strings.Replace(content, key, value, -1)
} }
// var time = time.Now().Unix() % 1000
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
ioutil.WriteFile(target, []byte(content), os.ModeAppend) ioutil.WriteFile(target, []byte(content), os.ModeAppend)
} }
@@ -121,31 +109,29 @@ func dev() {
func tinymce() { func tinymce() {
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]" // cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]") // cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/bin/sh", "-c", "grunt minify") cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
cmd.Dir = base + "/tinymce_4.1.9" cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
c, err := cmd.CombinedOutput()
fmt.Println("正在build tinymce")
// 必须要先删除
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")
c, _ := cmd2.CombinedOutput()
fmt.Println(string(c))
c, _ = cmd.CombinedOutput()
fmt.Println(string(c)) fmt.Println(string(c))
cmdError(err)
} }
func main() { func main() {
// 压缩tinymce dev();
// tinymce()
dev()
// 其它零散的需要压缩的js // 其它零散的需要压缩的js
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu", otherJss := []string{"tinymce/tinymce", "js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
"js/jquery.ztree.all-3.5", "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/jQuery-slimScroll-1.3.0/jquery.slimscroll",
} }
@@ -156,4 +142,6 @@ func main() {
// 先压缩后合并 // 先压缩后合并
combineJs() combineJs()
// 压缩tinymce
tinymce()
} }
+12 -85
View File
@@ -1,47 +1,30 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"time"
"os" "os"
"strings" "strings"
"time"
) )
type AttachService struct { type AttachService struct {
} }
// add attach // add attach
// api调用时, 添加attach之前是没有note的 func (this *AttachService) AddAttach(attach info.Attach) bool {
// fromApi表示是api添加的, updateNote传过来的, 此时不要incNote's usn, 因为updateNote会inc的
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
attach.CreatedTime = time.Now() attach.CreatedTime = time.Now()
ok = db.Insert(db.Attachs, attach) ok := db.Insert(db.Attachs, attach)
note := noteService.GetNoteById(attach.NoteId.Hex())
// api调用时, 添加attach之前是没有note的
var userId string
if note.NoteId != "" {
userId = note.UserId.Hex()
} else {
userId = attach.UploadUserId.Hex()
}
if ok { if ok {
// 更新笔记的attachs num // 更新笔记的attachs num
this.updateNoteAttachNum(attach.NoteId, 1) this.updateNoteAttachNum(attach.NoteId, 1)
} }
if !fromApi { return ok
// 增长note's usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
}
return
} }
// 更新笔记的附件个数 // 更新笔记的附件个数
@@ -63,45 +46,21 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
// list attachs // list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach { func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{} attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件 if !shareService.HasUpdateNotePerm(noteId, userId) {
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs return attachs
} }
// 笔记是否是自己的
note := noteService.GetNoteByIdAndUserId(noteId, userId)
if note.NoteId == "" {
return attachs
}
// TODO 这里, 优化权限控制
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs) db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
return attachs return attachs
} }
// api调用, 通过noteIds得到note's attachs, 通过noteId归类返回
func (this *AttachService) getAttachsByNoteIds(noteIds []bson.ObjectId) map[string][]info.Attach {
attachs := []info.Attach{}
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.M{"$in": noteIds}}, &attachs)
noteAttchs := make(map[string][]info.Attach)
for _, attach := range attachs {
noteId := attach.NoteId.Hex()
if itAttachs, ok := noteAttchs[noteId]; ok {
noteAttchs[noteId] = append(itAttachs, attach)
} else {
noteAttchs[noteId] = []info.Attach{attach}
}
}
return noteAttchs
}
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool { func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title) return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
} }
// Delete note to delete attas firstly // Delete note to delete attas firstly
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool { func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
@@ -119,12 +78,11 @@ func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
} }
// delete attach // delete attach
// 删除附件为什么要incrNoteUsn ? 因为可能没有内容要修改的
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) { func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
attach := info.Attach{} attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach) db.Get(db.Attachs, attachId, &attach)
if attach.AttachId != "" { if(attach.AttachId != "") {
// 判断是否有权限为笔记添加附件 // 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) { if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
return false, "No Perm" return false, "No Perm"
@@ -135,11 +93,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
attach.Path = strings.TrimLeft(attach.Path, "/") attach.Path = strings.TrimLeft(attach.Path, "/")
err := os.Remove(revel.BasePath + "/" + attach.Path) err := os.Remove(revel.BasePath + "/" + attach.Path)
if err == nil { if err == nil {
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size) return true, "delete file error"
// 修改note Usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
return true, "delete file success"
} }
return false, "delete file error" return false, "delete file error"
} }
@@ -214,35 +168,8 @@ func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
attach.Name = newFilename attach.Name = newFilename
attach.Path = filePath attach.Path = filePath
this.AddAttach(attach, false) this.AddAttach(attach)
} }
return true return true
} }
// 只留下files的数据, 其它的都删除
func (this *AttachService) UpdateOrDeleteAttachApi(noteId, userId string, files []info.NoteFile) bool {
// 现在数据库内的
attachs := this.ListAttachs(noteId, userId)
nowAttachs := map[string]bool{}
if files != nil {
for _, file := range files {
if file.IsAttach && file.FileId != "" {
nowAttachs[file.FileId] = true
}
}
}
for _, attach := range attachs {
fileId := attach.AttachId.Hex()
if !nowAttachs[fileId] {
// 需要删除的
// TODO 权限验证去掉
this.DeleteAttach(fileId, userId)
}
}
return false
}
+20 -40
View File
@@ -5,28 +5,20 @@ import (
// "github.com/leanote/leanote/app/db" // "github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
// "github.com/revel/revel" // "github.com/revel/revel"
"errors"
"fmt"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"fmt"
"strconv" "strconv"
"strings"
) )
// 登录与权限 Login & Register // 登录与权限
type AuthService struct { type AuthService struct {
} }
// 使用bcrypt认证或者Md5认证 // pwd已md5了
// Use bcrypt (Md5 depreciated) func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
func (this *AuthService) Login(emailOrUsername, pwd string) (info.User, error) { userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
emailOrUsername = strings.Trim(emailOrUsername, " ") 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,26 +32,18 @@ func (this *AuthService) Login(emailOrUsername, pwd string) (info.User, error) {
// 1. 添加用户 // 1. 添加用户
// 2. 将leanote共享给我 // 2. 将leanote共享给我
// [ok] // [ok]
func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string) { func (this *AuthService) Register(email, pwd string) (bool, string) {
// 用户是否已存在 // 用户是否已存在
if userService.IsExistsUser(email) { if userService.IsExistsUser(email) {
return false, "userHasBeenRegistered-" + email return false, email + " 已被注册"
}
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)
} }
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
return this.register(user) return this.register(user)
} }
func (this *AuthService) register(user info.User) (bool, string) { func (this *AuthService) register(user info.User) (bool, string) {
if userService.AddUser(user) { if userService.AddUser(user) {
// 添加笔记本, 生活, 学习, 工作 // 添加笔记本, 生活, 学习, 工作
userId := user.UserId.Hex()
notebook := info.Notebook{ notebook := info.Notebook{
Seq: -1, Seq: -1,
UserId: user.UserId} UserId: user.UserId}
@@ -68,12 +52,14 @@ func (this *AuthService) register(user info.User) (bool, string) {
notebook.Title = title notebook.Title = title
notebook.NotebookId = objectId notebook.NotebookId = objectId
notebook.UserId = user.UserId notebook.UserId = user.UserId
notebookService.AddNotebook(notebook) notebookService.AddNotebook(notebook);
} }
email := user.Email
// 添加leanote -> 该用户的共享 // 添加leanote -> 该用户的共享
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId") registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
if registerSharedUserId != "" { if(registerSharedUserId != "") {
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks") registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes") registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds") registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
@@ -81,23 +67,20 @@ func (this *AuthService) register(user info.User) (bool, string) {
// 添加共享笔记本 // 添加共享笔记本
for _, notebook := range registerSharedNotebooks { for _, notebook := range registerSharedNotebooks {
perm, _ := strconv.Atoi(notebook["perm"]) perm, _ := strconv.Atoi(notebook["perm"])
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId) shareService.AddShareNotebook(notebook["notebookId"], perm, registerSharedUserId, email);
} }
// 添加共享笔记 // 添加共享笔记
for _, note := range registerSharedNotes { for _, note := range registerSharedNotes {
perm, _ := strconv.Atoi(note["perm"]) perm, _ := strconv.Atoi(note["perm"])
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId) shareService.AddShareNote(note["noteId"], perm, registerSharedUserId, email);
} }
// 复制笔记 // 复制笔记
for _, noteId := range registerCopyNoteIds { for _, noteId := range registerCopyNoteIds {
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex()) note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
// Log(noteId) noteUpdate := bson.M{"IsBlog": true}
// Log("Copy") noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
// LogJ(note)
noteUpdate := bson.M{"IsBlog": false} // 不要是博客
noteService.UpdateNote(user.UserId.Hex(), note.NoteId.Hex(), noteUpdate, -1)
} }
} }
@@ -105,12 +88,9 @@ func (this *AuthService) register(user info.User) (bool, string) {
// 添加一条userBlog // 添加一条userBlog
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId, blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
Title: user.Username + " 's Blog", Title: user.Username + " 's Blog",
SubTitle: "Love Leanote!", SubTitle: "love leanote!",
AboutMe: "Hello, I am (^_^)", AboutMe: "Hello, I am (^_^)",
CanComment: true,
}) })
// 添加一个单页面
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
} }
return true, "" return true, ""
@@ -123,7 +103,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) { func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
username = thirdType + "-" + thirdUsername username = thirdType + "-" + thirdUsername
i := 1 i := 1
for { for ;; {
if !userService.IsExistsUserByUsername(username) { if !userService.IsExistsUserByUsername(username) {
return return
} }
File diff suppressed because it is too large. Load diff
+67 -136
View File
@@ -1,25 +1,22 @@
package service package service
import ( import (
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"github.com/revel/revel"
"time"
"os" "os"
"os/exec" "os/exec"
"strconv" "fmt"
"strings" "strings"
"time" "strconv"
) )
// 配置服务 // 配置服务
// 只是全局的, 用户的配置没有 // 只是全局的, 用户的配置没有
type ConfigService struct { type ConfigService struct {
adminUserId string
siteUrl string
adminUsername string
// 全局的 // 全局的
GlobalAllConfigs map[string]interface{} GlobalAllConfigs map[string]interface{}
GlobalStringConfigs map[string]string GlobalStringConfigs map[string]string
@@ -28,6 +25,8 @@ type ConfigService struct {
GlobalArrMapConfigs map[string][]map[string]string GlobalArrMapConfigs map[string][]map[string]string
} }
var adminUserId = ""
// appStart时 将全局的配置从数据库中得到作为全局 // appStart时 将全局的配置从数据库中得到作为全局
func (this *ConfigService) InitGlobalConfigs() bool { func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalAllConfigs = map[string]interface{}{} this.GlobalAllConfigs = map[string]interface{}{}
@@ -36,21 +35,19 @@ func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalMapConfigs = map[string]map[string]string{} this.GlobalMapConfigs = map[string]map[string]string{}
this.GlobalArrMapConfigs = map[string][]map[string]string{} this.GlobalArrMapConfigs = map[string][]map[string]string{}
this.adminUsername, _ = revel.Config.String("adminUsername") adminUsername, _ := revel.Config.String("adminUsername")
if this.adminUsername == "" { if adminUsername == "" {
this.adminUsername = "admin" adminUsername = "admin"
} }
this.siteUrl, _ = revel.Config.String("site.url")
userInfo := userService.GetUserInfoByAny(this.adminUsername) userInfo := userService.GetUserInfoByAny(adminUsername)
if userInfo.UserId == "" { if userInfo.UserId == "" {
return false return false
} }
this.adminUserId = userInfo.UserId.Hex() adminUserId = userInfo.UserId.Hex()
configs := []info.Config{} 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 { for _, config := range configs {
if config.IsArr { if config.IsArr {
@@ -68,43 +65,23 @@ func (this *ConfigService) InitGlobalConfigs() bool {
} }
} }
// site URL
if s, ok := this.GlobalStringConfigs["siteUrl"]; !ok || s != "" {
this.GlobalStringConfigs["siteUrl"] = this.siteUrl
}
return true return true
} }
func (this *ConfigService) GetSiteUrl() string {
s := this.GetGlobalStringConfig("siteUrl")
if s != "" {
return s
}
return this.siteUrl
}
func (this *ConfigService) GetAdminUsername() string {
return this.adminUsername
}
func (this *ConfigService) GetAdminUserId() string {
return this.adminUserId
}
// 通用方法 // 通用方法
func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool { func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool {
// 判断是否存在 // 判断是否存在
if _, ok := this.GlobalAllConfigs[key]; !ok { if _, ok := this.GlobalAllConfigs[key]; !ok {
// 需要添加 // 需要添加
config := info.Config{ConfigId: bson.NewObjectId(), config := info.Config{ConfigId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId), // 没用 UserId: bson.ObjectIdHex(userId),
Key: key, Key: key,
IsArr: isArr, IsArr: isArr,
IsMap: isMap, IsMap: isMap,
IsArrMap: isArrMap, IsArrMap: isArrMap,
UpdatedTime: time.Now(), UpdatedTime: time.Now(),
} }
if isArr { if(isArr) {
v, _ := value.([]string) v, _ := value.([]string)
config.ValueArr = v config.ValueArr = v
this.GlobalArrayConfigs[key] = v this.GlobalArrayConfigs[key] = v
@@ -125,7 +102,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
} else { } else {
i := bson.M{"UpdatedTime": time.Now()} i := bson.M{"UpdatedTime": time.Now()}
this.GlobalAllConfigs[key] = value this.GlobalAllConfigs[key] = value
if isArr { if(isArr) {
v, _ := value.([]string) v, _ := value.([]string)
i["ValueArr"] = v i["ValueArr"] = v
this.GlobalArrayConfigs[key] = v this.GlobalArrayConfigs[key] = v
@@ -142,8 +119,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
i["ValueStr"] = v i["ValueStr"] = v
this.GlobalStringConfigs[key] = 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)
} }
} }
@@ -190,7 +166,6 @@ func (this *ConfigService) GetGlobalArrMapConfig(key string) []map[string]string
func (this *ConfigService) IsOpenRegister() bool { func (this *ConfigService) IsOpenRegister() bool {
return this.GetGlobalStringConfig("openRegister") != "" return this.GetGlobalStringConfig("openRegister") != ""
} }
//------- //-------
// 修改共享笔记的配置 // 修改共享笔记的配置
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string, func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
@@ -202,13 +177,13 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
ok = false ok = false
msg = fmt.Sprint(err) msg = fmt.Sprint(err)
} }
}() }();
// 用户是否存在? // 用户是否存在?
if registerSharedUserId == "" { if registerSharedUserId == "" {
ok = true ok = true
msg = "share userId is blank, So it share nothing to register" msg = "share userId is blank, So it share nothing to register"
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "") this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", "")
return return
} else { } else {
user := userService.GetUserInfo(registerSharedUserId) user := userService.GetUserInfo(registerSharedUserId)
@@ -217,7 +192,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "no such user: " + registerSharedUserId msg = "no such user: " + registerSharedUserId
return return
} else { } else {
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId) this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", registerSharedUserId)
} }
} }
@@ -236,7 +211,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such notebook: " + notebookId msg = "The user has no such notebook: " + notebookId
return return
} else { } else {
perm := "0" perm := "0";
if registerSharedNotebookPerms[i] == 1 { if registerSharedNotebookPerms[i] == 1 {
perm = "1" perm = "1"
} }
@@ -244,7 +219,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
} }
} }
} }
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks) this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotebooks", notebooks)
notes := []map[string]string{} notes := []map[string]string{}
// 共享笔记 // 共享笔记
@@ -261,7 +236,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such note: " + noteId msg = "The user has no such note: " + noteId
return return
} else { } else {
perm := "0" perm := "0";
if registerSharedNotePerms[i] == 1 { if registerSharedNotePerms[i] == 1 {
perm = "1" perm = "1"
} }
@@ -269,7 +244,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
} }
} }
} }
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes) this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotes", notes)
// 复制 // 复制
noteIds := []string{} noteIds := []string{}
@@ -290,7 +265,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
} }
} }
} }
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds) this.UpdateGlobalArrayConfig(adminUserId, "registerCopyNoteIds", noteIds)
ok = true ok = true
return return
@@ -302,7 +277,7 @@ func (this *ConfigService) AddBackup(path, remark string) bool {
n := time.Now().Unix() n := time.Now().Unix()
nstr := fmt.Sprintf("%v", n) nstr := fmt.Sprintf("%v", n)
backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark}) backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark})
return this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) return this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
} }
func (this *ConfigService) getBackupDirname() string { func (this *ConfigService) getBackupDirname() string {
@@ -312,14 +287,14 @@ func (this *ConfigService) getBackupDirname() string {
} }
func (this *ConfigService) Backup(remark string) (ok bool, msg string) { func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
binPath := configService.GetGlobalStringConfig("mongodumpPath") binPath := configService.GetGlobalStringConfig("mongodumpPath")
config := revel.Config config := revel.Config;
dbname, _ := config.String("db.dbname") dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host") host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port") port, _ := revel.Config.String("db.port")
username, _ := revel.Config.String("db.username") username, _ := revel.Config.String("db.username")
password, _ := revel.Config.String("db.password") password, _ := revel.Config.String("db.password")
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM // mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-10-25/ -u leanote -p xx
binPath = binPath + " -h " + host + " -d " + dbname + " --port " + port binPath = binPath + " -h " + host + " -d " + dbname + " -port " + port
if username != "" { if username != "" {
binPath += " -u " + username + " -p " + password binPath += " -u " + username + " -p " + password
} }
@@ -334,7 +309,7 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
} }
cmd := exec.Command("/bin/sh", "-c", binPath) cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath) Log(binPath);
b, err := cmd.Output() b, err := cmd.Output()
if err != nil { if err != nil {
msg = fmt.Sprintf("%v", err) msg = fmt.Sprintf("%v", err)
@@ -346,7 +321,6 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
ok = configService.AddBackup(dir, remark) ok = configService.AddBackup(dir, remark)
return ok, msg return ok, msg
} }
// 还原 // 还原
func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) { func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}] backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
@@ -354,7 +328,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
var backup map[string]string var backup map[string]string
for i, backup = range backups { for i, backup = range backups {
if backup["createdTime"] == createdTime { if backup["createdTime"] == createdTime {
break break;
} }
} }
if i == len(backups) { if i == len(backups) {
@@ -369,14 +343,14 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
// mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/ // mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/
binPath := configService.GetGlobalStringConfig("mongorestorePath") binPath := configService.GetGlobalStringConfig("mongorestorePath")
config := revel.Config config := revel.Config;
dbname, _ := config.String("db.dbname") dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host") host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port") port, _ := revel.Config.String("db.port")
username, _ := revel.Config.String("db.username") username, _ := revel.Config.String("db.username")
password, _ := revel.Config.String("db.password") password, _ := revel.Config.String("db.password")
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM // mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
binPath = binPath + " --drop -h " + host + " -d " + dbname + " --port " + port binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
if username != "" { if username != "" {
binPath += " -u " + username + " -p " + password binPath += " -u " + username + " -p " + password
} }
@@ -387,10 +361,10 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
return false, path + " Is Not Exists" return false, path + " Is Not Exists"
} }
binPath += " " + path binPath += " --directoryperdb " + path
cmd := exec.Command("/bin/sh", "-c", binPath) cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath) Log(binPath);
b, err := cmd.Output() b, err := cmd.Output()
if err != nil { if err != nil {
msg = fmt.Sprintf("%v", err) msg = fmt.Sprintf("%v", err)
@@ -408,7 +382,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
var backup map[string]string var backup map[string]string
for i, backup = range backups { for i, backup = range backups {
if backup["createdTime"] == createdTime { if backup["createdTime"] == createdTime {
break break;
} }
} }
if i == len(backups) { if i == len(backups) {
@@ -424,7 +398,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
// 删除之 // 删除之
backups = append(backups[0:i], backups[i+1:]...) backups = append(backups[0:i], backups[i+1:]...)
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
return ok, "" return ok, ""
} }
@@ -434,15 +408,15 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
var backup map[string]string var backup map[string]string
for i, backup = range backups { for i, backup = range backups {
if backup["createdTime"] == createdTime { if backup["createdTime"] == createdTime {
break break;
} }
} }
if i == len(backups) { if i == len(backups) {
return false, "Backup Not Found" return false, "Backup Not Found"
} }
backup["remark"] = remark backup["remark"] = remark;
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups) ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
return ok, "" return ok, ""
} }
@@ -453,7 +427,7 @@ func (this *ConfigService) GetBackup(createdTime string) (map[string]string, boo
var backup map[string]string var backup map[string]string
for i, backup = range backups { for i, backup = range backups {
if backup["createdTime"] == createdTime { if backup["createdTime"] == createdTime {
break break;
} }
} }
if i == len(backups) { if i == len(backups) {
@@ -470,68 +444,68 @@ var port string
func init() { func init() {
revel.OnAppStart(func() { revel.OnAppStart(func() {
/*
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
port = strconv.Itoa(revel.HttpPort) port = strconv.Itoa(revel.HttpPort)
if port != "80" { if port != "80" {
port = ":" + port port = ":" + port
} else { } else {
port = ""; port = "";
} }
*/
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com siteUrl, _ = revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
if strings.HasPrefix(siteUrl, "http://") { if strings.HasPrefix(siteUrl, "http://") {
defaultDomain = siteUrl[len("http://"):] defaultDomain = siteUrl[len("http://"):]
} else if strings.HasPrefix(siteUrl, "https://") { } else if strings.HasPrefix(siteUrl, "https://") {
defaultDomain = siteUrl[len("https://"):] defaultDomain = siteUrl[len("https://"):]
schema = "https://" schema = "https://"
} }
// port localhost:9000
ports := strings.Split(defaultDomain, ":")
if len(ports) == 2 {
port = ports[1]
}
if port == "80" {
port = ""
} else {
port = ":" + port
}
}) })
} }
func (this *ConfigService) GetSchema() string {
return schema
}
func (this *ConfigService) GetSchema() string {
return schema;
}
// 默认 // 默认
func (this *ConfigService) GetDefaultDomain() string { func (this *ConfigService) GetDefaultDomain() string {
return defaultDomain return defaultDomain
} }
// 包含http://
func (this *ConfigService) GetDefaultUrl() string {
return schema + defaultDomain
}
// note // note
func (this *ConfigService) GetNoteDomain() string { func (this *ConfigService) GetNoteDomain() string {
return "/note" subDomain := this.GetGlobalStringConfig("noteSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/note"
} }
func (this *ConfigService) GetNoteUrl() string { func (this *ConfigService) GetNoteUrl() string {
return this.GetNoteDomain() return schema + this.GetNoteDomain();
} }
// blog // blog
func (this *ConfigService) GetBlogDomain() string { func (this *ConfigService) GetBlogDomain() string {
return "/blog" subDomain := this.GetGlobalStringConfig("blogSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/blog"
} }
func (this *ConfigService) GetBlogUrl() string { func (this *ConfigService) GetBlogUrl() string {
return this.GetBlogDomain() return schema + this.GetBlogDomain();
} }
// lea // lea
func (this *ConfigService) GetLeaDomain() string { func (this *ConfigService) GetLeaDomain() string {
return "/lea" subDomain := this.GetGlobalStringConfig("leaSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/lea"
} }
func (this *ConfigService) GetLeaUrl() string { func (this *ConfigService) GetLeaUrl() string {
return schema + this.GetLeaDomain() return schema + this.GetLeaDomain();
} }
func (this *ConfigService) GetUserUrl(domain string) string { func (this *ConfigService) GetUserUrl(domain string) string {
@@ -545,7 +519,6 @@ func (this *ConfigService) GetUserSubUrl(subDomain string) string {
func (this *ConfigService) AllowCustomDomain() bool { func (this *ConfigService) AllowCustomDomain() bool {
return configService.GetGlobalStringConfig("allowCustomDomain") != "" return configService.GetGlobalStringConfig("allowCustomDomain") != ""
} }
// 是否是好的自定义域名 // 是否是好的自定义域名
func (this *ConfigService) IsGoodCustomDomain(domain string) bool { func (this *ConfigService) IsGoodCustomDomain(domain string) bool {
blacks := this.GetGlobalArrayConfig("blackCustomDomains") blacks := this.GetGlobalArrayConfig("blackCustomDomains")
@@ -566,45 +539,3 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
} }
return true return true
} }
// 上传大小
func (this *ConfigService) GetUploadSize(key string) float64 {
f, _ := strconv.ParseFloat(this.GetGlobalStringConfig(key), 64)
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"),
}
}
// 为用户得到全局的配置
// NoteController调用
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
uploadSizeConfigs := this.GetUploadSizeLimit()
config := map[string]interface{}{}
for k, v := range uploadSizeConfigs {
config[k] = v
}
return config
}
// 主页是否是管理员的博客页
func (this *ConfigService) HomePageIsAdminsBlog() bool {
return this.GetGlobalStringConfig("homePage") == ""
}
func (this *ConfigService) GetVersion() string {
return "2.3"
}
+49 -120
View File
@@ -1,19 +1,17 @@
package service package service
import ( import (
"crypto/tls"
"net"
"bytes"
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"html/template" "time"
"strings"
"net/smtp" "net/smtp"
"strconv" "strconv"
"strings" "fmt"
"time" "html/template"
"bytes"
) )
// 发送邮件 // 发送邮件
@@ -22,7 +20,7 @@ type EmailService struct {
tpls map[string]*template.Template tpls map[string]*template.Template
} }
func NewEmailService() *EmailService { func NewEmailService() (*EmailService) {
return &EmailService{tpls: map[string]*template.Template{}} return &EmailService{tpls: map[string]*template.Template{}}
} }
@@ -31,74 +29,12 @@ var host = ""
var emailPort = "" var emailPort = ""
var username = "" var username = ""
var password = "" var password = ""
var ssl = false
func InitEmailFromDb() { func InitEmailFromDb() {
host = configService.GetGlobalStringConfig("emailHost") host = configService.GetGlobalStringConfig("emailHost")
emailPort = configService.GetGlobalStringConfig("emailPort") emailPort = configService.GetGlobalStringConfig("emailPort")
username = configService.GetGlobalStringConfig("emailUsername") username = configService.GetGlobalStringConfig("emailUsername")
password = configService.GetGlobalStringConfig("emailPassword") 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) { func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string) {
@@ -121,14 +57,7 @@ func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string
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, ";") 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 { if err != nil {
e = fmt.Sprint(err) e = fmt.Sprint(err)
@@ -146,16 +75,16 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
return false return false
} }
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject") subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateRegister") tpl := configService.GetGlobalStringConfig("emailTemplateRegister");
if tpl == "" { if(tpl == "") {
return false return false
} }
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token tokenUrl := siteUrl + "/user/activeEmail?token=" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username} // {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))), token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
"user": map[string]interface{}{ "user": map[string]interface{}{
"userId": userInfo.UserId.Hex(), "userId": userInfo.UserId.Hex(),
"email": userInfo.Email, "email": userInfo.Email,
@@ -189,13 +118,13 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
return return
} }
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject") subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail") tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
// 发送邮件 // 发送邮件
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token tokenUrl := siteUrl + "/user/updateEmail?token=" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username} // {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))), token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
"newEmail": email, "newEmail": email,
"user": map[string]interface{}{ "user": map[string]interface{}{
"userId": userInfo.UserId.Hex(), "userId": userInfo.UserId.Hex(),
@@ -215,13 +144,13 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
} }
func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) { func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) {
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject") subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword") tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
// 发送邮件 // 发送邮件
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token tokenUrl := siteUrl + "/findPassword/" + token
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username} // {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl,
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))} "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value) ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
@@ -235,11 +164,11 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st
// 发送邀请链接 // 发送邀请链接
func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool { func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool {
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject") subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateInvite") tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), token2Value := map[string]interface{}{"siteUrl": siteUrl,
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username, "registerUrl": siteUrl + "/register?from=" + userInfo.Username,
"content": content, "content": content,
"user": map[string]interface{}{ "user": map[string]interface{}{
"username": userInfo.Username, "username": userInfo.Username,
@@ -258,8 +187,8 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str
// 发送评论 // 发送评论
func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComment, userId, content string) bool { func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComment, userId, content string) bool {
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject") subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateComment") tpl := configService.GetGlobalStringConfig("emailTemplateComment");
// title := "评论提醒" // title := "评论提醒"
@@ -296,7 +225,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
// {blog.id} {blog.title} {blog.url} // {blog.id} {blog.title} {blog.url}
// {commentUser.userId} {commentUser.username} {commentUser.email} // {commentUser.userId} {commentUser.username} {commentUser.email}
// {commentedUser.userId} {commentedUser.username} {commentedUser.email} // {commentedUser.userId} {commentedUser.username} {commentedUser.email}
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(), token2Value := map[string]interface{}{"siteUrl": siteUrl, "blogUrl": configService.GetBlogUrl(),
"blog": map[string]string{ "blog": map[string]string{
"id": note.NoteId.Hex(), "id": note.NoteId.Hex(),
"title": note.Title, "title": note.Title,
@@ -328,6 +257,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
return ok return ok
} }
// 验证模板是否正确 // 验证模板是否正确
func (this *EmailService) ValidTpl(str string) (ok bool, msg string){ func (this *EmailService) ValidTpl(str string) (ok bool, msg string){
defer func() { defer func() {
@@ -335,9 +265,9 @@ func (this *EmailService) ValidTpl(str string) (ok bool, msg string) {
ok = false ok = false
msg = fmt.Sprint(err) msg = fmt.Sprint(err)
} }
}() }();
header := configService.GetGlobalStringConfig("emailTemplateHeader") header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter") footer := configService.GetGlobalStringConfig("emailTemplateFooter");
str = strings.Replace(str, "{{header}}", header, -1) str = strings.Replace(str, "{{header}}", header, -1)
str = strings.Replace(str, "{{footer}}", footer, -1) str = strings.Replace(str, "{{footer}}", footer, -1)
_, err := template.New("tpl name").Parse(str) _, err := template.New("tpl name").Parse(str)
@@ -356,7 +286,7 @@ func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template
ok = false ok = false
msg = fmt.Sprint(err) msg = fmt.Sprint(err)
} }
}() }();
var err error var err error
var has bool var has bool
@@ -382,16 +312,16 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
ok = false ok = false
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容, msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容,
} }
}() }();
var tpl *template.Template var tpl *template.Template
values["siteUrl"] = configService.GetSiteUrl() values["siteUrl"] = siteUrl;
// subject // subject
if subject != "" { if subject != "" {
ok, msg, tpl = this.getTpl(subject) ok, msg, tpl = this.getTpl(subject)
if !ok { if(!ok) {
return return
} }
var buffer bytes.Buffer var buffer bytes.Buffer
@@ -406,13 +336,13 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
} }
// content // content
header := configService.GetGlobalStringConfig("emailTemplateHeader") header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter") footer := configService.GetGlobalStringConfig("emailTemplateFooter");
body = strings.Replace(body, "{{header}}", header, -1) body = strings.Replace(body, "{{header}}", header, -1)
body = strings.Replace(body, "{{footer}}", footer, -1) body = strings.Replace(body, "{{footer}}", footer, -1)
values["subject"] = o values["subject"] = o
ok, msg, tpl = this.getTpl(body) ok, msg, tpl = this.getTpl(body)
if !ok { if(!ok) {
return return
} }
var buffer2 bytes.Buffer var buffer2 bytes.Buffer
@@ -429,14 +359,14 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
// 发送email给用户 // 发送email给用户
// 需要记录 // 需要记录
func (this *EmailService) SendEmailToUsers(users []info.User, subject, body string) (ok bool, msg string) { 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" msg = "no users"
return return
} }
// 尝试renderHtml // 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{}) ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if !ok { if(!ok) {
Log(msg) Log(msg)
return return
} }
@@ -451,8 +381,8 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m) ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m)
ok = ok2 ok = ok2
msg = msg2 msg = msg2
if ok2 { if(ok2) {
sendOk, msg := this.SendEmail(user.Email, subject2, body2) sendOk, msg := this.SendEmail(user.Email, subject2, body2);
this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下 this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下
// 记录到Email Log // 记录到Email Log
if sendOk { if sendOk {
@@ -470,14 +400,14 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
} }
func (this *EmailService) SendEmailToEmails(emails []string, subject, body string) (ok bool, msg string) { 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" msg = "no emails"
return return
} }
// 尝试renderHtml // 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{}) ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if !ok { if(!ok) {
Log(msg) Log(msg)
return return
} }
@@ -490,8 +420,8 @@ func (this *EmailService) SendEmailToEmails(emails []string, subject, body strin
m := map[string]interface{}{} m := map[string]interface{}{}
m["email"] = email m["email"] = email
ok, msg, subject, body = this.renderEmail(subject, body, m) ok, msg, subject, body = this.renderEmail(subject, body, m)
if ok { if(ok) {
sendOk, msg := this.SendEmail(email, subject, body) sendOk, msg := this.SendEmail(email, subject, body);
this.AddEmailLog(email, subject, body, sendOk, msg) this.AddEmailLog(email, subject, body, sendOk, msg)
// 记录到Email Log // 记录到Email Log
if sendOk { if sendOk {
@@ -500,7 +430,7 @@ func (this *EmailService) SendEmailToEmails(emails []string, subject, body strin
Log("no " + email) Log("no " + email)
} }
} else { } else {
Log(msg) Log(msg);
} }
} }
// }() // }()
@@ -513,7 +443,6 @@ 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()} log := info.EmailLog{LogId: bson.NewObjectId(), Email: email, Subject: subject, Body: body, Ok: ok, Msg: msg, CreatedTime: time.Now()}
db.Insert(db.EmailLogs, log) db.Insert(db.EmailLogs, log)
} }
// 展示邮件日志 // 展示邮件日志
func (this *EmailService) DeleteEmails(ids []string) bool { func (this *EmailService) DeleteEmails(ids []string) bool {
@@ -532,7 +461,7 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
if email != "" { if email != "" {
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}} query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
} }
q := db.EmailLogs.Find(query) q := db.EmailLogs.Find(query);
// 总记录数 // 总记录数
count, _ := q.Count() count, _ := q.Count()
// 列表 // 列表
+16 -84
View File
@@ -1,18 +1,14 @@
package service package service
import ( import (
"encoding/base64"
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel" "github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"io/ioutil" "time"
"net/http"
"os" "os"
"strings" "strings"
"time"
) )
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001" const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
@@ -21,7 +17,7 @@ type FileService struct {
} }
// add Image // add Image
func (this *FileService) AddImage(image info.File, albumId, userId string, needCheckSize bool) (ok bool, msg string) { func (this *FileService) AddImage(image info.File, albumId, userId string) bool {
image.CreatedTime = time.Now() image.CreatedTime = time.Now()
if albumId != "" { if albumId != "" {
image.AlbumId = bson.ObjectIdHex(albumId) image.AlbumId = bson.ObjectIdHex(albumId)
@@ -31,8 +27,7 @@ func (this *FileService) AddImage(image info.File, albumId, userId string, needC
} }
image.UserId = bson.ObjectIdHex(userId) image.UserId = bson.ObjectIdHex(userId)
ok = db.Insert(db.Files, image) return db.Insert(db.Files, image)
return
} }
// list images // list images
@@ -43,7 +38,7 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
if albumId != "" { if albumId != "" {
q["AlbumId"] = bson.ObjectIdHex(albumId) q["AlbumId"] = bson.ObjectIdHex(albumId);
} else { } else {
q["IsDefaultAlbum"] = true q["IsDefaultAlbum"] = true
} }
@@ -53,7 +48,7 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
// LogJ(q) // LogJ(q)
count := db.Count(db.Files, q) count := db.Count(db.Files, q);
db.Files. db.Files.
Find(q). Find(q).
@@ -92,7 +87,7 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
file := info.File{} file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file) db.GetByIdAndUserId(db.Files, fileId, userId, &file)
if file.FileId != "" { if(file.FileId != "") {
if db.DeleteByIdAndUserId(db.Files, fileId, userId) { if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
// delete image // delete image
// TODO // TODO
@@ -119,53 +114,6 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title) return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
} }
func (this *FileService) GetFileBase64(userId, fileId string) (str string, mine string) {
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
if err := recover(); err != nil {
fmt.Println(err) // 这里的err其实就是panic传入的内容,55
}
}()
path := this.GetFile(userId, fileId)
if path == "" {
return "", ""
}
path = revel.BasePath + "/" + strings.TrimLeft(path, "/")
ff, err := ioutil.ReadFile(path)
if err != nil {
return "", ""
}
e64 := base64.StdEncoding
maxEncLen := e64.EncodedLen(len(ff))
encBuf := make([]byte, maxEncLen)
e64.Encode(encBuf, ff)
mime := http.DetectContentType(ff)
str = string(encBuf)
return str, mime
}
// 得到图片base64, 图片要在之前添加data:image/png;base64,
func (this *FileService) GetImageBase64(userId, fileId string) string {
str, mime := this.GetFileBase64(userId, fileId)
if str == "" {
return ""
}
switch mime {
case "image/gif", "image/jpeg", "image/pjpeg", "image/png", "image/tiff":
return fmt.Sprintf("data:%s;base64,%s", mime, str)
default:
}
return "data:image/png;base64," + str
}
// 获取文件路径 // 获取文件路径
// 要判断是否具有权限 // 要判断是否具有权限
// userId是否具有fileId的访问权限 // userId是否具有fileId的访问权限
@@ -199,16 +147,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
return path 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}}) { if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
return path return path
} }
@@ -227,7 +166,6 @@ func (this *FileService) GetFile(userId, fileId string) string {
return path return path
} }
} }
*/
} }
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId // 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
@@ -242,17 +180,17 @@ func (this *FileService) GetFile(userId, fileId string) string {
return "" return ""
} }
// 复制共享的笔记时, 复制其中的图片到我本地
// 复制图片 // 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) { func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了 // 是否已经复制过了
file2 := info.File{} file2 := info.File{}
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2) db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
if file2.FileId != "" { if file2.FileId != "" {
return true, file2.FileId.Hex() return true, file2.FileId.Hex();
} }
// 复制之 // 复制之
file := info.File{} file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file) db.GetByIdAndUserId(db.Files, fileId, userId, &file)
@@ -261,20 +199,18 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
} }
_, ext := SplitFilename(file.Name) _, ext := SplitFilename(file.Name)
guid := NewGuid() newFilename := NewGuid() + ext
newFilename := guid + ext
// TODO 统一目录格式 dir := "files/" + toUserId + "/images"
// dir := "files/" + toUserId + "/images"
dir := "files/" + GetRandomFilePath(toUserId, guid) + "/images"
filePath := dir + "/" + newFilename filePath := dir + "/" + newFilename
err := os.MkdirAll(revel.BasePath+dir, 0755) err := os.MkdirAll(dir, 0755)
if err != nil { if err != nil {
return false, "" return false, ""
} }
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath) _, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
if err != nil { if err != nil {
Log(err)
return false, "" return false, ""
} }
@@ -283,10 +219,10 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
Path: filePath, Path: filePath,
Size: file.Size, Size: file.Size,
FromFileId: file.FileId} FromFileId: file.FileId}
id := bson.NewObjectId() id := bson.NewObjectId();
fileInfo.FileId = id fileInfo.FileId = id
fileId = id.Hex() fileId = id.Hex()
Ok, _ := this.AddImage(fileInfo, "", toUserId, false) Ok := this.AddImage(fileInfo, "", toUserId)
if Ok { if Ok {
return Ok, id.Hex() return Ok, id.Hex()
@@ -296,9 +232,5 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
// 是否是我的文件 // 是否是我的文件
func (this *FileService) IsMyFile(userId, fileId string) bool { func (this *FileService) IsMyFile(userId, fileId string) bool {
// 如果有问题会panic
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
return false
}
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)}) return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
} }
-225
View File
@@ -1,225 +0,0 @@
package service
import (
"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"
)
// 用户组, 用户组用户管理
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,
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 !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 {
/*
// 得到我的分组
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())
groups[i] = group
}
return groups
}
// 仅仅得到所有分组
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)
m := map[bson.ObjectId]bool{}
for _, groupId := range groupIds {
m[groupId] = true
}
// 我的组
myGroups := this.GetGroups(userId)
for _, group := range myGroups {
if !m[group.GroupId] {
groupIds = append(groupIds, group.GroupId)
}
}
return groupIds
}
// 获取包含此用户的组对象数组
// 获取该用户所属组, 和我的组
func (this *GroupService) GetGroupsContainOf(userId string) []info.Group {
// 我的组
myGroups := this.GetGroups(userId)
myGroupMap := map[bson.ObjectId]bool{}
for _, group := range myGroups {
myGroupMap[group.GroupId] = true
}
// 所属组
groupIds := this.GetBelongToGroupIds(userId)
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"_id": bson.M{"$in": groupIds}}, &groups)
for _, group := range groups {
if !myGroupMap[group.GroupId] {
myGroups = append(myGroups, group)
}
}
return myGroups
}
// 得到分组, shareService用
func (this *GroupService) GetGroup(userId, groupId string) info.Group {
// 得到分组s
group := info.Group{}
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
return group
}
// 得到某分组下的用户
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)
if len(groupUsers) == 0 {
return nil
}
userIds := make([]bson.ObjectId, len(groupUsers))
for i, each := range groupUsers {
userIds[i] = each.UserId
}
// 得到userInfos
return userService.ListUserInfosByUserIds(userIds)
}
// 得到我所属的所有分组ids
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)
if len(groupUsers) == 0 {
return nil
}
groupIds := make([]bson.ObjectId, len(groupUsers))
for i, each := range groupUsers {
groupIds[i] = each.GroupId
}
return groupIds
}
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
}
// 判断组中是否包含指定用户
func (this *GroupService) IsExistsGroupUser(userId, groupId string) (ok bool) {
// 如果我拥有这个组, 那也行
if this.isMyGroup(userId, groupId) {
return true
}
return db.Has(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId), "GroupId": bson.ObjectIdHex(groupId)})
}
// 为group添加用户
// 用户是否已存在?
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)}), ""
}
+2 -3
View File
@@ -1,8 +1,8 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
// "time" // "time"
@@ -33,8 +33,7 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
// TODO // TODO
l := len(history.Histories) l := len(history.Histories)
if l >= maxSize { if l >= maxSize {
// history.Histories = history.Histories[l-maxSize:] // BUG, 致使都是以前的 history.Histories = history.Histories[l-maxSize:]
history.Histories = history.Histories[:maxSize]
} }
newHistory := []info.EachHistory{eachHistory} newHistory := []info.EachHistory{eachHistory}
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前 newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
+17 -89
View File
@@ -1,8 +1,8 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"regexp" "regexp"
@@ -13,7 +13,7 @@ type NoteImageService struct {
} }
// 通过id, userId得到noteIds // 通过id, userId得到noteIds
func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId { func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
noteImages := []info.NoteImage{} noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages) db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages)
@@ -29,18 +29,11 @@ func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId {
return nil return nil
} }
// TODO 这个web可以用, 但api会传来, 不用用了
// 解析内容中的图片, 建立图片与note的关系 // 解析内容中的图片, 建立图片与note的关系
// <img src="/file/outputImage?fileId=12323232" /> // <img src="/file/outputImage?fileId=12323232" />
// 图片必须是我的, 不然不添加 // 图片必须是我的, 不然不添加
// imgSrc 防止博客修改了, 但内容删除了 func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content string) bool { reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
// 让主图成为内容的一员
if imgSrc != "" {
content = "<img src=\"" + imgSrc + "\" >" + content
}
// life 添加getImage
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的 find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
// 删除旧的 // 删除旧的
@@ -52,8 +45,8 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
hasAdded := make(map[string]bool) hasAdded := make(map[string]bool)
if find != nil && len(find) > 0 { if find != nil && len(find) > 0 {
for _, each := range find { for _, each := range find {
if each != nil && len(each) == 3 { if each != nil && len(each) == 2 {
fileId = each[2] // 现在有两个子表达式了 fileId = each[1]
// 之前没能添加过的 // 之前没能添加过的
if _, ok := hasAdded[fileId]; !ok { if _, ok := hasAdded[fileId]; !ok {
Log(fileId) Log(fileId)
@@ -73,13 +66,17 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径 // 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string { func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
/* 弃用之
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content // 得到fromNoteId的noteImages, 如果为空, 则直接返回content
noteImages := []info.NoteImage{} noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, &noteImages) db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, &noteImages)
if len(noteImages) == 0 { if len(noteImages) == 0 {
return content; return content;
} }
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
for _, noteImage := range noteImages { for _, noteImage := range noteImages {
imageId := noteImage.ImageId.Hex() imageId := noteImage.ImageId.Hex()
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId) ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
@@ -87,88 +84,19 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
replaceMap[imageId] = newImageId replaceMap[imageId] = newImageId
} }
} }
*/
// 因为很多图片上传就会删除, 所以直接从内容中查看图片id进行复制 if len(replaceMap) > 0 {
// 替换之
// <img src="/file/outputImage?fileId=12323232" /> reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
content = reg.ReplaceAllStringFunc(content, func(each string) string { content = reg.ReplaceAllStringFunc(content, func(each string) string {
// each=outputImage?fileId=541bd2f599c37b4f3r000003 // each=outputImage?fileId=541bd2f599c37b4f3r000003
// each = getImage?fileId=541bd2f599c37b4f3r000003
fileId := each[len(each)-24:] // 得到后24位, 也即id fileId := each[len(each)-24:] // 得到后24位, 也即id
if replaceFileId, ok := replaceMap[fileId]; ok {
if _, ok := replaceMap[fileId]; !ok {
if bson.IsObjectIdHex(fileId) {
ok2, newImageId := fileService.CopyImage(fromUserId, fileId, toUserId)
if ok2 {
replaceMap[fileId] = newImageId
} else {
replaceMap[fileId] = ""
}
} else {
replaceMap[fileId] = ""
}
}
replaceFileId := replaceMap[fileId]
if replaceFileId != "" {
if each[0] == 'o' {
return "outputImage?fileId=" + replaceFileId return "outputImage?fileId=" + replaceFileId
} }
return "getImage?fileId=" + replaceFileId
}
return each return each
}) });
return content
} }
// return content;
func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[string][]info.File {
noteNoteImages := []info.NoteImage{}
db.ListByQ(db.NoteImages, bson.M{"NoteId": bson.M{"$in": noteIds}}, &noteNoteImages)
// 得到imageId, 再去files表查所有的Files
imageIds := []bson.ObjectId{}
// 图片1 => N notes
imageIdNotes := map[string][]string{} // imageId => [noteId1, noteId2, ...]
for _, noteImage := range noteNoteImages {
imageId := noteImage.ImageId
imageIds = append(imageIds, imageId)
imageIdHex := imageId.Hex()
noteId := noteImage.NoteId.Hex()
if notes, ok := imageIdNotes[imageIdHex]; ok {
imageIdNotes[imageIdHex] = append(notes, noteId)
} else {
imageIdNotes[imageIdHex] = []string{noteId}
}
}
// 得到所有files
files := []info.File{}
db.ListByQ(db.Files, bson.M{"_id": bson.M{"$in": imageIds}}, &files)
// 建立note->file关联
noteImages := make(map[string][]info.File)
for _, file := range files {
fileIdHex := file.FileId.Hex() // == imageId
// 这个fileIdHex有哪些notes呢?
if notes, ok := imageIdNotes[fileIdHex]; ok {
for _, noteId := range notes {
if files, ok2 := noteImages[noteId]; ok2 {
noteImages[noteId] = append(files, file)
} else {
noteImages[noteId] = []info.File{file}
}
}
}
}
return noteImages
} }
File diff suppressed because it is too large. Load diff
+30 -125
View File
@@ -2,14 +2,12 @@ package service
import ( import (
// "fmt" // "fmt"
"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/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"sort" "sort"
"strings"
"time" "time"
// "html"
) )
// 笔记本 // 笔记本
@@ -43,8 +41,6 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}} newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
newNotebooks.NotebookId = each.NotebookId newNotebooks.NotebookId = each.NotebookId
newNotebooks.Title = each.Title newNotebooks.Title = each.Title
// newNotebooks.Title = html.EscapeString(each.Title)
newNotebooks.Title = strings.Replace(strings.Replace(each.Title, "<script>", "", -1), "</script", "", -1)
newNotebooks.Seq = each.Seq newNotebooks.Seq = each.Seq
newNotebooks.UserId = each.UserId newNotebooks.UserId = each.UserId
newNotebooks.ParentNotebookId = each.ParentNotebookId newNotebooks.ParentNotebookId = each.ParentNotebookId
@@ -105,34 +101,13 @@ func (this *NotebookService) GetNotebookById(notebookId string) info.Notebook {
db.Get(db.Notebooks, notebookId, &notebook) db.Get(db.Notebooks, notebookId, &notebook)
return notebook return notebook
} }
func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOrUrlTitle string) info.Notebook {
notebook := info.Notebook{}
if IsObjectId(notebookIdOrUrlTitle) {
db.Get(db.Notebooks, notebookIdOrUrlTitle, &notebook)
} else {
db.GetByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(notebookIdOrUrlTitle)}, &notebook)
}
return notebook
}
// 同步的方法
func (this *NotebookService) GeSyncNotebooks(userId string, afterUsn, maxEntry int) []info.Notebook {
notebooks := []info.Notebook{}
q := db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}})
q.Sort("Usn").Limit(maxEntry).All(&notebooks)
return notebooks
}
// 得到用户下所有的notebook // 得到用户下所有的notebook
// 排序好之后返回 // 排序好之后返回
// [ok] // [ok]
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks { func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
userNotebooks := []info.Notebook{} userNotebooks := []info.Notebook{}
orQ := []bson.M{ db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId)}).All(&userNotebooks)
bson.M{"IsDeleted": false},
bson.M{"IsDeleted": bson.M{"$exists": false}},
}
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "$or": orQ}).All(&userNotebooks)
if len(userNotebooks) == 0 { if len(userNotebooks) == 0 {
return nil return nil
@@ -156,58 +131,20 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
} }
// 添加 // 添加
func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Notebook) { // [ok]
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
if notebook.NotebookId == "" {
notebook.NotebookId = bson.NewObjectId()
}
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook", notebook.NotebookId.Hex())
notebook.Usn = userService.IncrUsn(notebook.UserId.Hex())
now := time.Now()
notebook.CreatedTime = now
notebook.UpdatedTime = now
err := db.Notebooks.Insert(notebook) err := db.Notebooks.Insert(notebook)
if err != nil { if err != nil {
return false, notebook panic(err)
}
return true, notebook
}
// 更新笔记, api
func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parentNotebookId string, seq, usn int) (bool, string, info.Notebook) {
if notebookId == "" {
return false, "notebookIdNotExists", info.Notebook{}
}
// 先判断usn是否和数据库的一样, 如果不一样, 则冲突, 不保存
notebook := this.GetNotebookById(notebookId)
// 不存在
if notebook.NotebookId == "" {
return false, "notExists", notebook
} else if notebook.Usn != usn {
return false, "conflict", notebook
}
notebook.Usn = userService.IncrUsn(userId)
notebook.Title = title
updates := bson.M{"Title": title, "Usn": notebook.Usn, "Seq": seq, "UpdatedTime": time.Now()}
if parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId) {
updates["ParentNotebookId"] = bson.ObjectIdHex(parentNotebookId)
} else { } else {
updates["ParentNotebookId"] = ""
} }
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates) return true
if ok {
return ok, "", this.GetNotebookById(notebookId)
}
return false, "", notebook
} }
// 判断是否是blog // 判断是否是blog
func (this *NotebookService) IsBlog(notebookId string) bool { func (this *NotebookService) IsBlog(notebookId string) bool {
notebook := info.Notebook{} notebook := info.Notebook{}
db.GetByQWithFields(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, []string{"IsBlog"}, &notebook) db.GetByQWithFields(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, []string{"IsBlog"}, &notebook);
return notebook.IsBlog return notebook.IsBlog
} }
@@ -227,34 +164,23 @@ func (this *NotebookService) UpdateNotebook(notebook info.Notebook) bool {
// 更新笔记本标题 // 更新笔记本标题
// [ok] // [ok]
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool { func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
usn := userService.IncrUsn(userId) return db.UpdateByIdAndUserIdField(db.Notebooks, notebookId, userId, "Title", title)
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Title": title, "Usn": usn})
} }
// 更新notebook // 更新notebook
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool { func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
needUpdate["UpdatedTime"] = time.Now() needUpdate["UpdatedTime"] = time.Now();
needUpdate["Usn"] = userService.IncrUsn(userId)
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
}
// ToBlog or Not // 如果有IsBlog之类的, 需要特殊处理
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool { if isBlog, ok := needUpdate["IsBlog"]; ok {
updates := bson.M{"IsBlog": isBlog, "Usn": userService.IncrUsn(userId)} // 设为blog/取消, 把它下面所有的note都设为isBlog
// 笔记本 if is, ok2 := isBlog.(bool); ok2 {
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
// 更新笔记
q := bson.M{"UserId": bson.ObjectIdHex(userId), q := bson.M{"UserId": bson.ObjectIdHex(userId),
"NotebookId": bson.ObjectIdHex(notebookId)} "NotebookId": bson.ObjectIdHex(notebookId)}
data := bson.M{"IsBlog": isBlog} data := bson.M{"IsBlog": is}
if isBlog { if is {
data["PublicTime"] = time.Now() data["PublicTime"] = time.Now()
} else {
data["HasSelfDefined"] = false
} }
// usn
data["Usn"] = userService.IncrUsn(userId)
db.UpdateByQMap(db.Notes, q, data) db.UpdateByQMap(db.Notes, q, data)
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId // noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
@@ -268,31 +194,21 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool
} }
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog}) db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
} }
}
}
// 重新计算tags return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
go (func() {
blogService.ReCountBlogTags(userId)
})()
return true
} }
// 查看是否有子notebook // 查看是否有子notebook
// 先查看该notebookId下是否有notes, 没有则删除 // 先查看该notebookId下是否有notes, 没有则删除
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) { func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
if db.Count(db.Notebooks, bson.M{ if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
"ParentNotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
"UserId": bson.ObjectIdHex(userId),
"IsDeleted": false,
}) == 0 { // 无
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId), "UserId": bson.ObjectIdHex(userId),
"IsTrash": false, "IsTrash": false}) == 0 { // 不包含trash
"IsDeleted": false}) == 0 { // 不包含trash return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
// 不是真删除 1/20, 为了同步笔记本
ok := db.UpdateByQMap(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, bson.M{"IsDeleted": true, "Usn": userService.IncrUsn(userId)})
return ok, ""
// return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
} }
return false, "笔记本下有笔记" return false, "笔记本下有笔记"
} else { } else {
@@ -300,18 +216,6 @@ func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, st
} }
} }
// API调用, 删除笔记本, 不作笔记控制
func (this *NotebookService) DeleteNotebookForce(userId, notebookId string, usn int) (bool, string) {
notebook := this.GetNotebookById(notebookId)
// 不存在
if notebook.NotebookId == "" {
return false, "notExists"
} else if notebook.Usn != usn {
return false, "conflict"
}
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
}
// 排序 // 排序
// 传入 notebookId => Seq // 传入 notebookId => Seq
// 为什么要传入userId, 防止修改其它用户的信息 (恶意) // 为什么要传入userId, 防止修改其它用户的信息 (恶意)
@@ -322,7 +226,7 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
} }
for notebookId, seq := range notebookId2Seqs { for notebookId, seq := range notebookId2Seqs {
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) { if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), bson.ObjectIdHex(userId), "Seq", seq) {
return false return false
} }
} }
@@ -330,14 +234,15 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
return true return true
} }
// 排序和设置父
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool { func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
userIdO := bson.ObjectIdHex(userId)
ok := false ok := false
// 如果没parentNotebookId, 则parentNotebookId设空 // 如果没parentNotebookId, 则parentNotebookId设空
if parentNotebookId == "" { if(parentNotebookId == "") {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)}) ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", "");
} else { } else {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": bson.ObjectIdHex(parentNotebookId), "Usn": userService.IncrUsn(userId)}) ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", bson.ObjectIdHex(parentNotebookId));
} }
if !ok { if !ok {
@@ -346,7 +251,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
// 排序 // 排序
for seq, notebookId := range siblings { for seq, notebookId := range siblings {
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) { if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), userIdO, "Seq", seq) {
return false return false
} }
} }
@@ -359,7 +264,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了) // trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool { func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
notebookIdO := bson.ObjectIdHex(notebookId) notebookIdO := bson.ObjectIdHex(notebookId)
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false, "IsDeleted": false}) count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false})
Log(count) Log(count)
Log(notebookId) Log(notebookId)
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count) return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
+2 -8
View File
@@ -1,10 +1,10 @@
package service package service
import ( 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/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
) )
// 找回密码 // 找回密码
@@ -34,7 +34,6 @@ func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
return return
} }
// 重置密码时
// 修改密码 // 修改密码
// 先验证 // 先验证
func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) { func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) {
@@ -47,13 +46,8 @@ func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) {
return ok, msg return ok, msg
} }
passwd := GenPwd(pwd)
if passwd == "" {
return false, "GenerateHash error"
}
// 修改密码之 // 修改密码之
ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", passwd) ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", Md5(pwd))
// 删除token // 删除token
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd) tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
+1 -21
View File
@@ -1,8 +1,8 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"time" "time"
@@ -17,7 +17,6 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId}, return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now()}) bson.M{key: value, "UpdatedTime": time.Now()})
} }
// 注销时清空session // 注销时清空session
func (this *SessionService) Clear(sessionId string) bool { func (this *SessionService) Clear(sessionId string) bool {
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId}) return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
@@ -46,12 +45,10 @@ func (this *SessionService) LoginTimesIsOver(sessionId string) bool {
session := this.Get(sessionId) session := this.Get(sessionId)
return session.LoginTimes > 5 return session.LoginTimes > 5
} }
// 登录成功后清空错误次数 // 登录成功后清空错误次数
func (this *SessionService) ClearLoginTimes(sessionId string) bool { func (this *SessionService) ClearLoginTimes(sessionId string) bool {
return this.Update(sessionId, "LoginTimes", 0) return this.Update(sessionId, "LoginTimes", 0)
} }
// 增加错误次数 // 增加错误次数
func (this *SessionService) IncrLoginTimes(sessionId string) bool { func (this *SessionService) IncrLoginTimes(sessionId string) bool {
session := this.Get(sessionId) session := this.Get(sessionId)
@@ -72,20 +69,3 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
Log(ok) Log(ok)
return ok return ok
} }
//-----------
// API
func (this *SessionService) GetUserId(sessionId string) string {
session := this.Get(sessionId)
// 更新updateTime, 避免过期
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{"UpdatedTime": time.Now()})
return session.UserId
}
// 登录成功后设置userId
func (this *SessionService) SetUserId(sessionId, userId string) bool {
this.Get(sessionId)
ok := this.Update(sessionId, "UserId", userId)
return ok
}
+92 -345
View File
@@ -1,22 +1,19 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea" . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
"sort"
"time" "time"
"sort"
) )
// 共享Notebook, Note服务 // 共享Notebook, Note服务
type ShareService struct { type ShareService struct {
} }
//----------------------------------- //-----------------
// 返回shareNotebooks, sharedUserInfos
// info.ShareNotebooksByUser, []info.User
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据 // 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!! // 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
@@ -30,60 +27,23 @@ type ShareService struct {
// 3 每个层按seq进行排序 // 3 每个层按seq进行排序
// 4 按用户分组 // 4 按用户分组
// [ok] // [ok]
// 谁共享给了我的Query
func (this *ShareService) getOrQ(userId string) bson.M {
// 得到我和和我参与的组织
groupIds := groupService.GetMineAndBelongToGroupIds(userId)
q := bson.M{}
if len(groupIds) > 0 {
orQ := []bson.M{
bson.M{"ToUserId": bson.ObjectIdHex(userId)},
bson.M{"ToGroupId": bson.M{"$in": groupIds}},
}
// 不是trash的
q["$or"] = orQ
} else {
q["ToUserId"] = bson.ObjectIdHex(userId)
}
return q
}
// 得到共享给我的笔记本和用户(谁共享给了我)
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) { func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
myUserId := userId //-------------
// 查询HasShareNote表得到所有其它用户信息
hasShareNotes := []info.HasShareNote{}
db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes);
// 得到共享给我的用户s信息 userIds := make([]bson.ObjectId, len(hasShareNotes))
// 得到我参与的组织 for i, each := range hasShareNotes {
q := this.getOrQ(userId) userIds[i] = each.UserId
// 不查hasShareNotes
// 直接查shareNotes, shareNotebooks表得到userId
userIds1 := []bson.ObjectId{}
db.Distinct(db.ShareNotes, q, "UserId", &userIds1)
userIds2 := []bson.ObjectId{}
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
userIds := append(userIds1, userIds2...)
userInfos := userService.GetUserInfosOrderBySeq(userIds)
// 不要我的id
for i, userInfo := range userInfos {
if userInfo.UserId.Hex() == myUserId {
userInfos = append(userInfos[:i], userInfos[i+1:]...)
break
}
} }
userInfos := userService.GetUserInfosOrderBySeq(userIds);
//-------------------- //--------------------
// 得到他们共享给我的notebooks // 得到他们共享给我的notebooks
// 这里可能会得到重复的记录
// 权限: 笔记本分享给个人 > 笔记本分享给组织
shareNotebooks := []info.ShareNotebook{} shareNotebooks := []info.ShareNotebook{}
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shareNotebooks) // 按ToUserId降序排序, 那么有ToUserId的在前面 db.ShareNotebooks.Find(bson.M{"ToUserId": bson.ObjectIdHex(userId)}).All(&shareNotebooks)
if len(shareNotebooks) == 0 { if len(shareNotebooks) == 0 {
return nil, userInfos return nil, userInfos
@@ -92,16 +52,13 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
shareNotebooksLen := len(shareNotebooks) shareNotebooksLen := len(shareNotebooks)
// 找到了所有的notbookId, 那么找notebook表得到其详细信息 // 找到了所有的notbookId, 那么找notebook表得到其详细信息
notebookIds := []bson.ObjectId{} notebookIds := make([]bson.ObjectId, shareNotebooksLen)
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen) shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
for _, each := range shareNotebooks { for i, each := range shareNotebooks {
// 之后的就不要了, 只留权限高的
if _, ok := shareNotebooksMap[each.NotebookId]; !ok {
// 默认的是没有notebookId的 // 默认的是没有notebookId的
notebookIds = append(notebookIds, each.NotebookId) notebookIds[i] = each.NotebookId
shareNotebooksMap[each.NotebookId] = each shareNotebooksMap[each.NotebookId] = each
} }
}
// 1, 2 // 1, 2
subNotebooks := notebookService.GetNotebooksByNotebookIds(notebookIds) subNotebooks := notebookService.GetNotebooksByNotebookIds(notebookIds)
@@ -113,18 +70,13 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
// 先建立userId => [] // 先建立userId => []
for _, eachSub := range subShareNotebooks { for _, eachSub := range subShareNotebooks {
userId := eachSub.Notebook.UserId userId := eachSub.Notebook.UserId
// 我自己的, 算了
if userId.Hex() == myUserId {
continue
}
if _, ok := shareNotebooksByUsersMap[userId]; ok { if _, ok := shareNotebooksByUsersMap[userId]; ok {
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub) shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
} else { } else {
shareNotebooksByUsersMap[userId] = []info.ShareNotebooks{eachSub} shareNotebooksByUsersMap[userId] = []info.ShareNotebooks{eachSub}
} }
} }
shareNotebooksByUser := info.ShareNotebooksByUser{} shareNotebooksByUser := info.ShareNotebooksByUser{};
for userId, eachShareNotebooks := range shareNotebooksByUsersMap { for userId, eachShareNotebooks := range shareNotebooksByUsersMap {
// 4, 按用户排序 // 4, 按用户排序
shareNotebooksByUser[userId.Hex()] = sortSubShareNotebooks(eachShareNotebooks) shareNotebooksByUser[userId.Hex()] = sortSubShareNotebooks(eachShareNotebooks)
@@ -173,15 +125,11 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
// 得到共享笔记本下的notes // 得到共享笔记本下的notes
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string, func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
page, pageSize int, sortField string, isAsc bool) []info.ShareNoteWithPerm { page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId // 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
q := this.getOrQ(myUserId)
q["NotebookId"] = bson.ObjectIdHex(notebookId)
q["UserId"] = bson.ObjectIdHex(sharedUserId)
shareNotebook := info.ShareNotebook{} shareNotebook := info.ShareNotebook{}
db.GetByQ(db.ShareNotebooks, db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
q, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
&shareNotebook)
if shareNotebook.NotebookId == "" { if shareNotebook.NotebookId == "" {
return nil return nil
@@ -190,7 +138,7 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
perm := shareNotebook.Perm perm := shareNotebook.Perm
// 2 得到该notebook下分页显示所有的notes // 2 得到该notebook下分页显示所有的notes
_, notes := noteService.ListNotes(sharedUserId, notebookId, false, page, pageSize, sortField, isAsc, false) _, notes := noteService.ListNotes(sharedUserId, notebookId, false, page, pageSize, sortField, isAsc, false);
// 3 添加权限信息 // 3 添加权限信息
// 3.1 如果该notebook自己有其它权限信息, 比如1, 那么覆盖notebook的权限信息 // 3.1 如果该notebook自己有其它权限信息, 比如1, 那么覆盖notebook的权限信息
@@ -198,24 +146,12 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
for i, note := range notes { for i, note := range notes {
noteIds[i] = note.NoteId noteIds[i] = note.NoteId
} }
// 笔记的权限 notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId);
shareNotes := []info.ShareNote{}
delete(q, "NotebookId")
q["NoteId"] = bson.M{"$in": noteIds}
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限
notePerms := map[bson.ObjectId]int{}
for _, each := range shareNotes {
if _, ok := notePerms[each.NoteId]; !ok {
notePerms[each.NoteId] = each.Perm
}
}
Log("笔记权限")
LogJ(notePerms)
// 3.2 组合 // 3.2 组合
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes)) notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
for i, each := range notes { for i, each := range notes {
thisPerm := perm thisPerm := perm;
if selfPerm, ok := notePerms[each.NoteId]; ok { if selfPerm, ok := notePerms[each.NoteId]; ok {
thisPerm = selfPerm thisPerm = selfPerm
} }
@@ -226,38 +162,31 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
} }
// 得到note的perm信息 // 得到note的perm信息
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int { func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
// shareNotes := []info.ShareNote{} shareNotes := []info.ShareNote{}
// db.ListByQ(db.ShareNotes, db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
// bson.M{
// "NoteId": bson.M{"$in": noteIds}, notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
// "UserId": bson.ObjectIdHex(sharedUserId), for _, each := range shareNotes {
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes) notesPerm[each.NoteId] = each.Perm
// }
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
// for _, each := range shareNotes { return notesPerm
// notesPerm[each.NoteId] = each.Perm }
// }
//
// return notesPerm
//}
// 得到默认的单个的notes 共享集 // 得到默认的单个的notes 共享集
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit // 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
// 可以这样! 到时将零散的共享noteId放在用户基本数据中 // 可以这样! 到时将零散的共享noteId放在用户基本数据中
// 这里不好排序 // 这里不好排序
func (this *ShareService) ListShareNotes(myUserId, sharedUserId string, func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
pageNumber, pageSize int, sortField string, isAsc bool) []info.ShareNoteWithPerm { pageNumber, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc) skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
shareNotes := []info.ShareNote{} shareNotes := []info.ShareNote{}
q := this.getOrQ(myUserId)
q["UserId"] = bson.ObjectIdHex(sharedUserId)
db.ShareNotes. db.ShareNotes.
Find(q). Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限 // Sort(sortFieldR).
Skip(skipNum). Skip(skipNum).
Limit(pageSize). Limit(pageSize).
All(&shareNotes) All(&shareNotes)
@@ -271,20 +200,15 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
noteIds[i] = each.NoteId noteIds[i] = each.NoteId
} }
notes := noteService.ListNotesByNoteIds(noteIds) notes := noteService.ListNotesByNoteIds(noteIds)
notesMap := map[bson.ObjectId]info.Note{} notesMap := make(map[bson.ObjectId]info.Note, len(notes))
for _, each := range notes { for _, each := range notes {
notesMap[each.NoteId] = each notesMap[each.NoteId] = each
} }
// 将shareNotes与notes结合起来 // 将shareNotes与notes结合起来
notesWithPerm := []info.ShareNoteWithPerm{} notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的 for i, each := range shareNotes {
for _, each := range shareNotes { notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
if !hasAdded[each.NoteId] {
// 待优化
notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm})
hasAdded[each.NoteId] = true
}
} }
return notesWithPerm return notesWithPerm
} }
@@ -297,7 +221,7 @@ func (this *ShareService) notes2NotesWithPerm(notes []info.Note) {
// [ok] // [ok]
func (this *ShareService) AddShareNotebook1(shareNotebook info.ShareNotebook) bool { func (this *ShareService) AddShareNotebook1(shareNotebook info.ShareNotebook) bool {
// 添加一条记录说明两者存在关系 // 添加一条记录说明两者存在关系
this.AddHasShareNote(shareNotebook.UserId.Hex(), shareNotebook.ToUserId.Hex()) this.AddHasShareNote(shareNotebook.UserId.Hex(), shareNotebook.ToUserId.Hex());
shareNotebook.CreatedTime = time.Now() shareNotebook.CreatedTime = time.Now()
return db.Insert(db.ShareNotebooks, shareNotebook) return db.Insert(db.ShareNotebooks, shareNotebook)
@@ -310,19 +234,15 @@ func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId,
if toUserId == "" { if toUserId == "" {
return false, "无该用户", "" return false, "无该用户", ""
} }
return this.AddShareNotebookToUserId(notebookId, perm, userId, toUserId)
}
// 第三方注册时没有email
func (this *ShareService) AddShareNotebookToUserId(notebookId string, perm int, userId, toUserId string) (bool, string, string) {
// 添加一条记录说明两者存在关系 // 添加一条记录说明两者存在关系
this.AddHasShareNote(userId, toUserId) this.AddHasShareNote(userId, toUserId);
// 先删除之 // 先删除之
db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId), db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId), "UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId), "ToUserId": bson.ObjectIdHex(toUserId),
}) });
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId), shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId), UserId: bson.ObjectIdHex(userId),
@@ -347,19 +267,15 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
if toUserId == "" { if toUserId == "" {
return false, "无该用户", "" return false, "无该用户", ""
} }
return this.AddShareNoteToUserId(noteId, perm, userId, toUserId)
}
// 第三方测试没有userId
func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId, toUserId string) (bool, string, string) {
// 添加一条记录说明两者存在关系 // 添加一条记录说明两者存在关系
this.AddHasShareNote(userId, toUserId) this.AddHasShareNote(userId, toUserId);
// 先删除之 // 先删除之
db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId), "UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId), "ToUserId": bson.ObjectIdHex(toUserId),
}) });
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId), shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId), UserId: bson.ObjectIdHex(userId),
@@ -371,23 +287,18 @@ func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId,
} }
// updatedUserId是否有查看userId noteId的权限? // updatedUserId是否有查看userId noteId的权限?
// userId是所有者
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool { func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) if !db.Has(db.ShareNotes,
q["UserId"] = bson.ObjectIdHex(userId) bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
q["NoteId"] = bson.ObjectIdHex(noteId)
if !db.Has(db.ShareNotes, q) {
// noteId的notebookId是否被共享了? // noteId的notebookId是否被共享了?
notebookId := noteService.GetNotebookId(noteId) notebookId := noteService.GetNotebookId(noteId)
if notebookId.Hex() == "" { if notebookId.Hex() == "" {
return false return false
} }
delete(q, "NoteId")
q["NotebookId"] = notebookId
// 判断notebook是否被共享 // 判断notebook是否被共享
if !db.Has(db.ShareNotebooks, q) { if !db.Has(db.ShareNotebooks,
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
return false return false
} else { } else {
return true return true
@@ -399,57 +310,55 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool
// updatedUserId是否有修改userId noteId的权限? // updatedUserId是否有修改userId noteId的权限?
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool { func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) // 1. noteId是否被共享了?
q["UserId"] = bson.ObjectIdHex(userId) // 得到该note share的信息
q["NoteId"] = bson.ObjectIdHex(noteId) /*
UserId bson.ObjectId `bson:"UserId"`
// note的权限 ToUserId bson.ObjectId `bson:"ToUserId"`
shares := []info.ShareNote{} NoteId bson.ObjectId `bson:"NoteId"`
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织 Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
for _, share := range shares { */
return share.Perm == 1 // 第1个权限最大 if !db.Has(db.ShareNotes,
} bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) {
// noteId的notebookId是否被共享了?
// notebook的权限
notebookId := noteService.GetNotebookId(noteId) notebookId := noteService.GetNotebookId(noteId)
if notebookId.Hex() == "" { if notebookId.Hex() == "" {
return false return false
} }
delete(q, "NoteId") // 判断notebook是否被共享
q["NotebookId"] = notebookId if !db.Has(db.ShareNotebooks,
shares2 := []info.ShareNotebook{} bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) {
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
for _, share := range shares2 {
return share.Perm == 1 // 第1个权限最大
}
return false return false
} else {
return true
}
} else {
return true
}
} }
// updatedUserId是否有修改userId notebookId的权限? // updatedUserId是否有修改userId notebookId的权限?
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool { func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3)) // 判断notebook是否被共享
q["UserId"] = bson.ObjectIdHex(userId) if !db.Has(db.ShareNotebooks,
q["NotebookId"] = bson.ObjectIdHex(notebookId) bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
shares2 := []info.ShareNotebook{}
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
for _, share := range shares2 {
return share.Perm == 1 // 第1个权限最大
}
return false return false
} else {
return true
}
} }
// 共享note, notebook时使用 // 共享note, notebook时使用
func (this *ShareService) AddHasShareNote(userId, toUserId string) bool { func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
db.Insert(db.HasShareNotes, info.HasShareNote{UserId: bson.ObjectIdHex(userId), ToUserId: bson.ObjectIdHex(toUserId)}) db.Insert(db.HasShareNotes, info.HasShareNote{UserId: bson.ObjectIdHex(userId), ToUserId: bson.ObjectIdHex(toUserId)})
return true return true;
} }
// userId是否被共享了noteId // userId是否被共享了noteId
func (this *ShareService) HasSharedNote(noteId, myUserId string) bool { func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)}) return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
} }
// noteId的notebook是否共享了给我 // noteId的notebook是否共享了给我
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool { func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
notebookId := noteService.GetNotebookId(noteId) notebookId := noteService.GetNotebookId(noteId)
@@ -463,17 +372,12 @@ func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId strin
} }
// 得到共享的笔记内容 // 得到共享的笔记内容
// 并返回笔记的权限!!! // 首先要判断这个note是否我被共享了
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) { func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
noteContent = info.NoteContent{} noteContent = info.NoteContent{}
// 是否单独共享了该notebook // 是否单独共享了该notebook
// 或者, 其notebook共享了我 // 或者, 其notebook共享了我
// Log(this.HasSharedNote(noteId, myUserId)) if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
// Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
if this.HasReadPerm(sharedUserId, myUserId, noteId) {
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
db.Get(db.NoteContents, noteId, &noteContent) db.Get(db.NoteContents, noteId, &noteContent)
} else { } else {
} }
@@ -487,15 +391,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo { func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
// 得到shareNote信息, 得到所有的ToUserId // 得到shareNote信息, 得到所有的ToUserId
shareNotes := []info.ShareNote{} shareNotes := []info.ShareNote{}
db.ListByQLimit(db.ShareNotes, db.ListByQLimit(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}, &shareNotes, 100)
bson.M{
"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.M{"$exists": false},
}, &shareNotes, 100)
// Log("<<>>>>")
// Log(len(shareNotes))
if len(shareNotes) == 0 { if len(shareNotes) == 0 {
return nil return nil
@@ -554,11 +450,7 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
shareNotebooks := []info.ShareNotebook{} shareNotebooks := []info.ShareNotebook{}
db.ListByQLimit(db.ShareNotebooks, db.ListByQLimit(db.ShareNotebooks,
bson.M{ bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)},
"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.M{"$exists": false},
},
&shareNotebooks, 100) &shareNotebooks, 100)
if len(shareNotebooks) == 0 { if len(shareNotebooks) == 0 {
@@ -592,6 +484,7 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
return shareUserInfos return shareUserInfos
} }
//---------------- //----------------
// 改变note share权限 // 改变note share权限
func (this *ShareService) UpdateShareNotePerm(noteId string, perm int, userId, toUserId string) bool { func (this *ShareService) UpdateShareNotePerm(noteId string, perm int, userId, toUserId string) bool {
@@ -622,7 +515,6 @@ func (this *ShareService) DeleteShareNoteAll(noteId string, userId string) bool
return db.DeleteAll(db.ShareNotes, return db.DeleteAll(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}) bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)})
} }
// 删除share notebook // 删除share notebook
func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserId string) bool { func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserId string) bool {
return db.DeleteAll(db.ShareNotebooks, return db.DeleteAll(db.ShareNotebooks,
@@ -632,9 +524,9 @@ func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserI
// 删除userId分享给toUserId的所有 // 删除userId分享给toUserId的所有
func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool { func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool {
query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)} query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)}
db.DeleteAll(db.ShareNotebooks, query) db.DeleteAll(db.ShareNotebooks, query);
db.DeleteAll(db.ShareNotes, query) db.DeleteAll(db.ShareNotes, query);
db.DeleteAll(db.HasShareNotes, query) db.DeleteAll(db.HasShareNotes, query);
return true return true
} }
@@ -642,10 +534,10 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
// 用户userId是否有修改noteId的权限 // 用户userId是否有修改noteId的权限
func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool { func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" { if noteId == "" || userId == "" {
return false return false;
} }
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
LogJ(note) LogJ(note);
if note.UserId != "" { if note.UserId != "" {
noteUserId := note.UserId.Hex() noteUserId := note.UserId.Hex()
if noteUserId != userId { if noteUserId != userId {
@@ -653,20 +545,20 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if this.HasUpdatePerm(noteUserId, userId, noteId) { if this.HasUpdatePerm(noteUserId, userId, noteId) {
return true return true
} else { } else {
return false return false;
} }
} else { } else {
return true return true
} }
} else { } else {
return false return false;
} }
} }
// 用户userId是否有查看noteId的权限 // 用户userId是否有修改noteId的权限
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool { func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" { if noteId == "" || userId == "" {
return false return false;
} }
note := noteService.GetNoteById(noteId) note := noteService.GetNoteById(noteId)
if note.UserId != "" { if note.UserId != "" {
@@ -676,157 +568,12 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if this.HasReadPerm(noteUserId, userId, noteId) { if this.HasReadPerm(noteUserId, userId, noteId) {
return true return true
} else { } else {
return false return false;
} }
} else { } else {
return true return true
} }
} else { } else {
return false return false;
} }
} }
//----------------
// 用户分组
// 得到笔记分享给的groups
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
groups := groupService.GetGroupsContainOf(userId)
// 得到有分享的分组
shares := []info.ShareNote{}
db.ListByQ(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
mapShares := map[bson.ObjectId]info.ShareNote{}
for _, share := range shares {
mapShares[share.ToGroupId] = share
}
// 所有的groups都有share, 但没有share的group没有shareId
shares2 := make([]info.ShareNote, len(groups))
for i, group := range groups {
share, ok := mapShares[group.GroupId]
if !ok {
share = info.ShareNote{}
}
share.ToGroup = group
shares2[i] = share
}
return shares2
}
// 共享笔记给分组
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
return false
}
// 先删除之
this.DeleteShareNoteGroup(userId, noteId, groupId)
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotes, shareNote)
}
// 删除
func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
//-------
// 得到笔记本分享给的groups
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
groups := groupService.GetGroupsContainOf(userId)
// 得到有分享的分组
shares := []info.ShareNotebook{}
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
mapShares := map[bson.ObjectId]info.ShareNotebook{}
for _, share := range shares {
mapShares[share.ToGroupId] = share
}
LogJ(shares)
// 所有的groups都有share, 但没有share的group没有shareId
shares2 := make([]info.ShareNotebook, len(groups))
for i, group := range groups {
share, ok := mapShares[group.GroupId]
if !ok {
share = info.ShareNotebook{}
}
share.ToGroup = group
shares2[i] = share
}
return shares2
}
// 共享笔记给分组
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
return false
}
// 先删除之
this.DeleteShareNotebookGroup(userId, notebookId, groupId)
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId), // 冗余字段
ToGroupId: bson.ObjectIdHex(groupId),
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotebooks, shareNotebook)
}
// 删除
func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
//--------------------
// 删除组时, 删除所有的
//--------------------
func (this *ShareService) DeleteAllShareNotebookGroup(groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
func (this *ShareService) DeleteAllShareNoteGroup(groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
//--------------------
// 删除组内用户时, 删除其分享的
//--------------------
func (this *ShareService) DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
func (this *ShareService) DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
}
+1 -1
View File
@@ -1,8 +1,8 @@
package service package service
import ( import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info" "github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea" // . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
// "time" // "time"
Loaded 100 of 3025 files, more files were not shown because too many files have changed in this diff. Show more