Compare commits

..
11 Commits
Author SHA1 Message Date
binnchx fb484b2132 Merge remote-tracking branch 'origin/dev' into dev-binnchx 2015-01-22 23:18:20 +08:00
binnchx 4d5a3ffd0f .gitignore is now working 2015-01-22 23:16:26 +08:00
binnchx f78eb4db49 add share note 2015-01-22 23:13:58 +08:00
binnchx c35aa1eaa4 ignore app.conf 2015-01-11 22:34:17 +08:00
binnchx 96b094844e rm file 2015-01-11 22:06:09 +08:00
binnchx 9af13bcc32 Merge remote-tracking branch 'origin/dev' into dev-binnchx
Conflicts:
2015-01-11 22:04:18 +08:00
binnchx 29215a1d64 modify git ignore 2015-01-11 21:29:54 +08:00
binnchx d828a10e7b add conf file 2015-01-11 21:29:26 +08:00
binnchx a851aaa399 commit sharing note 2015-01-11 17:59:07 +08:00
binnchx a393bb8723 Merge branch 'master' into dev-binnchx 2015-01-03 21:25:34 +08:00
binnchx 599e54de5b share note to unregistered users
share note to unregistered users
2015-01-03 17:57:52 +08:00
3232 changed files with 136271 additions and 244746 deletions

No files matched your search

+3 -3
View File
@@ -2,9 +2,9 @@
pkg
bin2
bin/i18n
bin/leanote*
bin/leanote-linux
bin/leanote-mac
bin/release
bin/test.sh
bin/tmp
bin/test
bin/src
@@ -16,4 +16,4 @@ app/tmp/main.go
.project
public/config.codekit
files
/node_modules
conf/app.conf
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>leanote-public</name>
<comment>leanote, your own cloud note!</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.googlecode.goclipse.goBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>goclipse.goNature</nature>
</natures>
</projectDescription>
-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
it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Leanote is licensed under the GPL v2.
leanote is licensed under the GPL v2.
life(life@leanote.com, lifephp@gmail.com)
+86 -162
View File
@@ -1,189 +1,113 @@
# Leanote
[![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)
# Leanote
## 1. Introduction
Leanote, not just a notepad!
Leanote, not 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 management: The flexible and versatile notebook-note-tagging system of Leanote makes it an ideal tool for knowledge management.
* Sharing: Share your knowledge, thoughts and experiences with friends via Leanote. Invite your friends to join your notepad in the cloud.
* Cooperating: Collaborate with colleagues to improve skills, fertilize ideas and brainstorm on the fly.
* Blogging: Publish your work and make Leanote your personal blog.
* Knowledge: Manage your knowledge in leanote. leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
* Share: Share your knowledge with your friends in leanote. You can invite your friends to join your notepad in the cloud so you can share knowledge.
* Cooperation: Collaborate with friends to improve your skills.
* Blog: Publish your knowledge and make leanote your blog.
**Other Features**
* Markdown syntax support
* Distraction-free writing mode
* `Vim` and `Emacs` editing mode
* Export notes to PDFs
* Batch note operation
* Customizable themes for blogging
## 2. Why we create Leanote
We have been using the popular note-taking software/service `Evernote` as our knowledge management tool on a daily basis. Benefited from and inspired by `Evernote`, we decided to create a brand-new tool that provides everything `Evernote` has to offer, plus a bunch of new features that `Evernote` failed to deliver, such as:
* A more powerful editor: `Evernote`'s editor lacks the functionalities of **document navigation**, **syntax based code rendering** (as a programmer, syntax highlighted code rendering is a necessity), **image resizing** and so forth.
* Everybody loves *markdown*, however `Evernote` simply wouldn't add it despite of years' of requests from users. So we will do the favor and bring a *markdown* enabled editor to you, guess what, it is also rendered in real-time!
* If you a developer and miss the `Vim` or `Emacs` ways of writing, we offer you the choice of `Vim` and `Emacs` editting modes. Equipped with *markdown* syntax for text formatting, you will never need to touch your mouse while writing.
* We love managing knowledge and thoughts as much as sharing them, so everybody has their own note account (`Evernote`, `Onenote`, `Google doc`, `Wiz note` etc.) and social media account (`Facebook`, `Wordpress`, blogs, etc.). But why can’t those two be one? Leanote makes this first step to bridge the private note-taking and public knowledge sharing seamlessly.
* A complete and all-platform (sorry Windows phone) covering software suite: that includes Leanote Web & Server (this repository), [Desktop app](https://github.com/leanote/desktop-app), [iOS](https://github.com/leanote/leanote-ios), [Android](https://github.com/leanote/leanote-android). And they are all open source!
## 2. Why we created leanote
To be honest, our inspiration comes from Evernote. We use Evernote to manage our knowledge everyday. But we find that:
* Evernote's editor can't meet our needs, it does not have document navigation, it does not render code properly (as a programmer, syntax highlighted code rendering is a basic need), it cannot resize images and so forth
* We like markdown, but Evernote does not support it.
* We want to share our knowledge, so all of us have our blogs (e.g. on Wordpress) and our Evernote accounts, but why can not those two be one!
* ......
## 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).
More information about how to install leanote please see:
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
Interested in our product and want to try it out from your web browser? Welcome to sign up on https://leanote.com.
### 3.1. Download leanote
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.
Leanote V1.0.2-beta has been released. Binaries:
More information about how to install Leanote please see:
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.2.tar.gz)
* Leanote binary installation tutorial:
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
* [Mac and Linux](https://github.com/leanote/leanote/wiki/leanote-binary-installation-on-Mac-and-Linux-(En))
* Leanote source installation tutorial:
* [Windows](https://github.com/leanote/leanote/wiki/leanote-source-installation-on-Windows-(En))
* [Mac and Linux](https://github.com/leanote/leanote/wiki/Leanote-source-installation-on-Mac-and-Linux-(En))
Or you can clone [Leanote bin repository](https://github.com/leanote/leanote-bin) (Recommend)
## 4. Documentation
### 3.2. 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.
Leanote is written in go using [revel](https://revel.github.io/) and [MongoDB](https://www.mongodb.org). Thus, you need to first install MongoDB.
For more tips please have a look at [our wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
### 3.3. Import initial MongoDB data
The mongodb data is in `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
The initial database contains two users:
```
user2 username: admin, password: abc123 (administrator)
user3 username: demo, password: demo@leanote.com (this user is for demo)
```
### 3.4. Configuration
Modify `[PATH_TO_LEANOTE]/conf/app.conf`. Available configuration options are:
``mongodb`` **required**
```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
``app.secret`` **required** **important**
The secret key used for cryptographic operations (revel.Sign).
FOR SECURITY, YOU MUST CHANGE IT!!
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
### 3.5. Run leanote
```
$> cd PATH_TO_LEANOTE/bin
$> sudo sh run.sh
```
## 4. How to develop leanote
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
## 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
## Docs
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
Like or dislike Leanote, please leave your comments and suggestions to help us improve it.
If you encounter any issue, we suggest you first do a search in the issues section to see whether a solution already exists, or open up a new one otherwise.
We’d like to acknowledge the contributions made by our [developers and contributors](https://github.com/leanote/leanote/graphs/contributors) to
this project. Leanote won’t exist without your hard work. Your help is much appreciated.
## 7. Join us
Please feel free to fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
If you find any problems or have any good ideas, feature requests, please submit here [issues](https://github.com/leanote/leanote/issues).
## 8. Donation
If you like our product, consider supporting us via [donate us](http://leanote.org/#donate).
We acknowledge the donations make by all the [donators](http://leanote.leanote.com/post/leanote-donation-list).
## 9. Related projects
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [Download](http://app.leanote.com)
* [Leanote iOS](https://github.com/leanote/leanote-ios), [Download From App Store](https://itunes.apple.com/en/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/leanote/leanote-android), development phase
You are welcome to join us.
## 10. Contacts
* Email: leanote@leanote.com
* [Leanote BBS](http://bbs.leanote.com)
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
* QQ Groups: 326073529, 256076853, 158716820
## Discussion
* [leanote bbs](http://bbs.leanote.com)
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
* QQ Group: 158716820
-----------------------------------------------------------------------
[中文](README_zh.md)
# Leanote
## 1. 介绍
Leanote, 不只是笔记!
**特性**
* 高效笔记:Leanote 有易操作的界面, 包含一款富文本编辑器和Markdown编辑器,让您的笔记记录更轻松和高效。对高阶用户,我们还提供`Vim` 和`Emacs` 编辑模式,助推你的写作速度更上层楼。
* 知识管理: Leanote 灵活而强大的“笔记本-笔记-标签”系统,让它成为你个人知识管理的利器。
* 分享: 你可以通过Leanote同好友分享知识、想法和经历, 邀请好友加入你的笔记簿,通过云端交流信息。
* 协作: Leanote协助你与同事之间相互协作,激荡新思路,随时随地头脑风暴。
* 博客: Leanote也可以作为你的个人博客, 把你的知识传播的更远!
**其它特性**
* 支持Markdown编辑
* 写作模式
* `Vim` 及 `Emacs` 编辑模式
* 支持PDF导出
* 支持批量操作
* 博客自定义主题, 实现高度定制化
## 2. 为什么我们要创建Leanote?
我们都曾是`Evernote`的忠实粉丝, 一直以来`Evernote`都是我们日常知识管理的有效工具。于是我们决定重新创造一款工具,提供`Evernote`所能提供的功能,同时弥补`Evernote`的不足,比如:
* 功能更强的文本编辑器:`Evernote`的编辑器不能满足我们的需求, 不能实现文档导航、不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放等。
* `Evernote` 不支持所有人都喜爱的markdown语法,于是我们为Leanote配备了一款可以实时渲染的markdown编辑器。
* 如果你是一名开发者,觉得手指怀念`Vim` 或 `Emacs` 了,那么我们还提供给你`Vim` 和 `Emacs` 写作模式,配合*markdown*的格式编辑,写作的时候再也不用去碰鼠标了。
* 知识积累和知识分享同样重要,因此大家都有自己的笔记账号和社交账号。但为什么这两者不能合二为一呢? Leanote 做到了将二者无缝衔接。
* 一套完整的、全平台覆盖的软件套装,包括了web、桌面、安卓、IOS设备,而且全部开源!
* 还有...
## 3. 获取Leanote
Leanote云笔记产品包括: Leanote Web & Server(即本仓库), 桌面客户端, IOS, android. 4端全部开源!
如果想试用我们的产品,欢迎在 https://leanote.com 上注册, Leanote团队为你提供稳定可靠的服务。
担心服务厂商如何处理你的个人数据吗?你可以下载Leanote安装在自己的服务器上, 通过Leanote客户端连接与自建服务同步数据。
这里详细整理了Leanote二进版和Leanote开发版的安装教程, 请移步至:
* Leanote二进制详细安装教程:
* [Windows](https://github.com/leanote/leanote/wiki/Leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B---Windows)
* [Mac, Linux](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* Leanote源码详细安装教程:
* [Windows](https://github.com/leanote/leanote/wiki/Leanote-%E6%BA%90%E7%A0%81%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B----Windows)
* [Mac, Linux](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
## 4. 相关文档
更多详细的安装说明、问题处理和配置说明文档,请查看 [wiki](https://github.com/leanote/leanote/wiki)。
## 5. 如何对Leanote进行二次开发
如果您有兴趣基于Leanote二次开发,请查看 [How-to-develop-Leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)。
## 6. 贡献者
在此对向Leanote贡献力量的[贡献者们](https://github.com/leanote/leanote/graphs/contributors) 表示感谢。Leanote因有你们而更完美!
## 7. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到Leanote。
有任何问题或建议, 请先搜索[issue](https://github.com/leanote/leanote/issues)区是否已经有解决方法。如果没有,欢迎提交新issue。
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善Leanote。
## 8. 捐赠
如果您喜欢我们的产品,请考虑支持我们, [捐赠Leanote](http://leanote.org/#donate)。
感谢[这些捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
## 9. 其它相关项目
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
* [Leanote iOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
* [Leanote Android](https://github.com/leanote/leanote-android), 开发阶段
欢迎加入我们!
## 联系&加入我们
* Email: leanote@leanote.com
* [Leanote 社区](http://bbs.leanote.com)
* [QQ群](http://leanote.leanote.com/post/Leanote-groups)
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
+113
View File
@@ -0,0 +1,113 @@
# Leanote产品
## 1. 介绍
Leanote, 不只是笔记!
![leanote.png](leanote.png "")
**特性**
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
* 协作: 在分享的同时也可以与好友一起协作知识.
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
## 2. 为什么我们要创建leanote?
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
* 我们是markdown的爱好者, 可是evernote竟然没有.
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
* 还有...
## 3.安装leanote
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
### 3.1. 下载leanote
Leanote V1.0-beta.2 已发布, 二进制文件(暂时没有windows版的):
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz)
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
### 3.2. 安装 MongodbDB
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
### 3.3. 导入初始数据
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
```
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
```
初始数据包含两个用户:
```
user2 username: admin, password: abc123 (管理员, 重要!)
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
```
### 3.4. 配置
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
``mongodb`` **必须配置!**
```Shell
db.host=localhost
db.port=27017
db.dbname=leanote
db.username=
db.password=
```
``app.secret`` **重要**
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
### 3.5. 运行leanote
```
$> cd PATH_TO_LEANOTE/bin
$> sudo sh run.sh
```
## 4. 如何对leanote进行二次开发
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
## 5. 贡献者
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
## 6. 加入我们
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
## 相关文档
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
## 讨论
* [leanote 社区](http://bbs.leanote.com)
* QQ群: 158716820
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
----------------------------------------------------------------
[English](README.md)
-19
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")
}
+5 -10
View File
@@ -2,11 +2,11 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "encoding/json"
"github.com/leanote/leanote/app/info"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
// Album controller
@@ -14,17 +14,12 @@ type Album struct {
BaseController
}
// 图片管理, iframe
func (c Album) Index() revel.Result {
c.SetLocale()
return c.RenderTemplate("album/index.html")
}
// all albums by userId
func (c Album) GetAlbums() revel.Result {
re := albumService.GetAlbums(c.GetUserId())
return c.RenderJson(re)
}
func (c Album) DeleteAlbum(albumId string) revel.Result {
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
return c.RenderJson(info.Re{Ok: re, Msg: msg})
@@ -39,7 +34,7 @@ func (c Album) AddAlbum(name string) revel.Result {
UserId: c.GetObjectUserId()}
re := albumService.AddAlbum(album)
if re {
if(re) {
return c.RenderJson(album)
} else {
return c.RenderJson(false)
+32 -31
View File
@@ -2,18 +2,18 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"archive/tar"
"compress/gzip"
"fmt"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
"io"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"strings"
"time"
"io"
"fmt"
"archive/tar"
"compress/gzip"
)
// 附件
@@ -57,19 +57,17 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
return re
}
// > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize")
maxFileSize := configService.GetUploadSize("uploadAttachSize");
if maxFileSize <= 0 {
maxFileSize = 1000
}
if float64(len(data)) > maxFileSize*float64(1024*1024) {
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
return re
}
// 生成上传路径
// filePath := "files/" + c.GetUserId() + "/attachs"
newGuid := NewGuid()
filePath := "files/" + GetRandomFilePath(c.GetUserId(), newGuid) + "/attachs"
filePath := "files/" + c.GetUserId() + "/attachs"
dir := revel.BasePath + "/" + filePath
err = os.MkdirAll(dir, 0755)
if err != nil {
@@ -78,8 +76,8 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
// 生成新的文件名
filename := handel.Filename
_, ext := SplitFilename(filename) // .doc
filename = newGuid + ext
toPath := dir + "/" + filename
filename = NewGuid() + ext
toPath := dir + "/" + filename;
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
return re
@@ -99,15 +97,15 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
Type: fileType,
Size: filesize}
id := bson.NewObjectId()
id := bson.NewObjectId();
fileInfo.AttachId = id
fileId = id.Hex()
Ok, resultMsg = attachService.AddAttach(fileInfo, false)
Ok, resultMsg = attachService.AddAttach(fileInfo)
if resultMsg != "" {
resultMsg = c.Message(resultMsg)
}
fileInfo.Path = "" // 不要返回
fileInfo.Path = ""; // 不要返回
if Ok {
resultMsg = "success"
}
@@ -131,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
// 下载附件
// 权限判断
func (c Attach) Download(attachId string) revel.Result {
attach := attachService.GetAttach(attachId, c.GetUserId()) // 得到路径
func (c Attach) Download(attachId, token string) revel.Result {
if c.GetUserId() == "" && token == "" {
return c.RenderText("你需要从分享页面下载附件!")
}
sessionId := c.Session.Id()
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
path := attach.Path
if token != "" && attach.Path == "" {
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
}
if path == "" {
return c.RenderText("")
}
@@ -167,16 +174,10 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
filename = "all.tar.gz"
}
dir := revel.BasePath + "/files/attach_all"
if !MkdirAll(dir) {
return c.RenderText("error")
}
// file write
fw, err := os.Create(dir + "/" + filename)
fw, err := os.Create(revel.BasePath + "/files/" + filename)
if err != nil {
return c.RenderText("error")
return c.RenderText("")
}
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
@@ -218,10 +219,10 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
}
} // for
// tw.Close()
// gw.Close()
// fw.Close()
// file, _ := os.Open(dir + "/" + filename)
// 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
}
+25 -41
View File
@@ -1,11 +1,11 @@
package controllers
import (
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
// "strconv"
// "strconv"
"fmt"
)
// 用户登录/注销/找回密码
@@ -41,42 +41,41 @@ func (c Auth) Login(email, from string) revel.Result {
func (c Auth) doLogin(email, pwd string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
userInfo, err := authService.Login(email, pwd)
if err != nil {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
} else {
fmt.Println(sessionId)
userInfo := authService.Login(email, pwd)
if userInfo.Email != "" {
c.SetSession(userInfo)
sessionService.ClearLoginTimes(sessionId)
return c.RenderJson(info.Re{Ok: true})
} else {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
}
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
}
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
var msg = ""
// > 5次需要验证码, 直到登录成功
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
msg = "captchaError"
} else {
userInfo, err := authService.Login(email, pwd)
if err != nil {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
sessionService.IncrLoginTimes(sessionId)
} 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)})
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
}
// 注销
func (c Auth) Logout() revel.Result {
sessionId := c.Session.Id()
@@ -87,17 +86,8 @@ func (c Auth) Logout() revel.Result {
// 体验一下
func (c Auth) Demo() revel.Result {
email := configService.GetGlobalStringConfig("demoUsername")
pwd := configService.GetGlobalStringConfig("demoPassword")
userInfo, err := authService.Login(email, pwd)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
} else {
c.SetSession(userInfo)
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
return c.Redirect("/note")
}
return nil
}
//--------
@@ -119,17 +109,15 @@ func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
return c.Redirect("/index")
}
re := info.NewRe()
re := info.NewRe();
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
email = strings.ToLower(email)
// 注册
re.Ok, re.Msg = authService.Register(email, pwd, iu)
@@ -144,7 +132,6 @@ func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
//--------
// 找回密码
func (c Auth) FindPassword() revel.Result {
c.SetLocale()
c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword")
return c.RenderTemplate("home/find_password.html")
@@ -155,16 +142,14 @@ func (c Auth) DoFindPassword(email string) revel.Result {
re.Ok = true
return c.RenderJson(re)
}
// 点击链接后, 先验证之
func (c Auth) FindPassword2(token string) revel.Result {
c.SetLocale()
c.RenderArgs["title"] = c.Message("findPassword")
c.RenderArgs["subTitle"] = c.Message("findPassword")
if token == "" {
return c.RenderTemplate("find_password2_timeout.html")
}
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd)
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
if !ok {
return c.RenderTemplate("home/find_password2_timeout.html")
}
@@ -175,13 +160,12 @@ func (c Auth) FindPassword2(token string) revel.Result {
return c.RenderTemplate("home/find_password2.html")
}
// 找回密码修改密码
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
re := info.NewRe()
re := info.NewRe();
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
// 修改之
+23 -40
View File
@@ -1,18 +1,17 @@
package controllers
import (
"encoding/json"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
"bytes"
"encoding/json"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
"math"
"strconv"
"strings"
"bytes"
)
// 公用Controller, 其它Controller继承它
@@ -20,11 +19,6 @@ type BaseController struct {
*revel.Controller
}
// 覆盖revel.Message
func (c *BaseController) Message(message string, args ...interface{}) (value string) {
return i18n.Message(c.Request.Locale, message, args...)
}
func (c BaseController) GetUserId() string {
if userId, ok := c.Session["UserId"]; ok {
return userId
@@ -62,7 +56,7 @@ func (c BaseController) GetUsername() string {
// 得到用户信息
func (c BaseController) GetUserInfo() info.User {
if userId, ok := c.Session["UserId"]; ok && userId != "" {
return userService.GetUserInfo(userId)
return userService.GetUserInfo(userId);
/*
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
@@ -90,13 +84,6 @@ func (c BaseController) GetUserInfo() 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无关
func (c BaseController) GetSession(key string) string {
v, ok := c.Session[key]
@@ -145,7 +132,7 @@ func (c BaseController) UpdateSession(key, value string) {
// 返回json
func (c BaseController) Json(i interface{}) string {
// b, _ := json.MarshalIndent(i, "", " ")
// b, _ := json.MarshalIndent(i, "", " ")
b, _ := json.Marshal(i)
return string(b)
}
@@ -163,9 +150,9 @@ func (c BaseController) GetPage() int {
// 判断是否含有某参数
func (c BaseController) Has(key string) bool {
if _, ok := c.Params.Values[key]; ok {
return true
return true;
}
return false
return false;
}
/*
@@ -175,32 +162,28 @@ func (c Blog) GetPage(page, count int, list interface{}) info.Page {
*/
func (c BaseController) GetTotalPage(page, count int) int {
return int(math.Ceil(float64(count) / float64(page)))
return int(math.Ceil(float64(count)/float64(page)))
}
//-------------
func (c BaseController) E404() revel.Result {
c.RenderArgs["title"] = "404"
c.RenderArgs["title"] = "404";
return c.NotFound("", nil)
}
// 设置本地
func (c BaseController) SetLocale() string {
locale := string(c.Request.Locale) // zh-CN
// lang := locale
// if strings.Contains(locale, "-") {
// pos := strings.Index(locale, "-")
// lang = locale[0:pos]
// }
// if lang != "zh" && lang != "en" {
// lang = "en"
// }
lang := locale
if !i18n.HasLang(locale) {
lang = i18n.GetDefaultLang()
if strings.Contains(locale, "-") {
pos := strings.Index(locale, "-")
lang = locale[0:pos]
}
c.RenderArgs["locale"] = lang
c.RenderArgs["siteUrl"] = configService.GetSiteUrl()
if lang != "zh" && lang != "en" {
lang = "en";
}
c.RenderArgs["locale"] = lang;
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
@@ -213,7 +196,7 @@ func (c BaseController) SetLocale() string {
func (c BaseController) SetUserInfo() info.User {
userInfo := c.GetUserInfo()
c.RenderArgs["userInfo"] = userInfo
if userInfo.Username == configService.GetAdminUsername() {
if(userInfo.Username == configService.GetAdminUsername()) {
c.RenderArgs["isAdmin"] = true
}
return userInfo
@@ -235,7 +218,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
var buffer bytes.Buffer
tpl.Template.Render(&buffer, c.RenderArgs)
return buffer.String()
return buffer.String();
}
// json, result
@@ -244,7 +227,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
func (c BaseController) RenderRe(re info.Re) revel.Result {
oldMsg := re.Msg
if re.Msg != "" {
if strings.Contains(re.Msg, "-") {
if(strings.Contains(re.Msg, "-")) {
msgAndValues := strings.Split(re.Msg, "-")
if len(msgAndValues) == 2 {
re.Msg = c.Message(msgAndValues[0], msgAndValues[1])
+29 -73
View File
@@ -59,7 +59,7 @@ func (c Blog) render(templateName string, themePath string) revel.Result {
c.setPreviewUrl()
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"]
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"];
}
return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
}
@@ -113,8 +113,8 @@ func (c Blog) setPreviewUrl() {
themeId := c.Session["themeId"]
theme := themeService.GetTheme(userId, themeId)
// siteUrl := configService.GetSiteUrl()
blogUrl := "/preview" // blog.leanote.com
siteUrl := configService.GetSiteUrl()
blogUrl := siteUrl + "/preview" // blog.leanote.com
indexUrl = blogUrl + "/" + userIdOrEmail
cateUrl = blogUrl + "/cate/" + userIdOrEmail // /notebookId
@@ -143,8 +143,8 @@ func (c Blog) setPreviewUrl() {
// 各种地址设置
func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
// 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com
// host := c.Request.Request.Host
// var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
host := c.Request.Request.Host
var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
// staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com
// life.leanote.com, lealife.com
siteUrl := configService.GetSiteUrl()
@@ -168,20 +168,20 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
// 其它static js
c.RenderArgs["jQueryUrl"] = "/js/jquery-1.9.0.min.js"
c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js"
c.RenderArgs["prettifyJsUrl"] = "/js/google-code-prettify/prettify.js"
c.RenderArgs["prettifyCssUrl"] = "/js/google-code-prettify/prettify.css"
c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js"
c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css"
c.RenderArgs["blogCommonJsUrl"] = "/public/blog/js/common.js"
c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js"
c.RenderArgs["shareCommentCssUrl"] = "/public/blog/css/share_comment.css"
c.RenderArgs["shareCommentJsUrl"] = "/public/blog/js/share_comment.js"
c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css"
c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js"
c.RenderArgs["fontAwesomeUrl"] = "/css/font-awesome-4.2.0/css/font-awesome.css"
c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css"
c.RenderArgs["bootstrapCssUrl"] = "/css/bootstrap.css"
c.RenderArgs["bootstrapJsUrl"] = "/js/bootstrap-min.js"
c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css"
c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js"
}
// 笔记本分类
@@ -200,73 +200,29 @@ func (c Blog) getCates(userBlog info.UserBlog) {
}
var i = 0
cates := make([]*info.Cate, len(notebooks))
cates := make([]map[string]string, len(notebooks))
// 先要保证已有的是正确的排序
cateIds := userBlog.CateIds
has := map[string]bool{} // cateIds中有的
cateMap := map[string]*info.Cate{}
if cateIds != nil && len(cateIds) > 0 {
for _, cateId := range cateIds {
if n, ok := notebooksMap[cateId]; ok {
parentNotebookId := ""
if n.ParentNotebookId != "" {
parentNotebookId = n.ParentNotebookId.Hex()
}
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: n.NotebookId.Hex(), ParentCateId: parentNotebookId}
cateMap[cates[i].CateId] = cates[i]
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": n.NotebookId.Hex()}
i++
has[cateId] = true
}
}
}
// 之后添加没有排序的
// 之后
for _, n := range notebooks {
id := n.NotebookId.Hex()
if !has[id] {
parentNotebookId := ""
if n.ParentNotebookId != "" {
parentNotebookId = n.ParentNotebookId.Hex()
}
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: id, ParentCateId: parentNotebookId}
cateMap[cates[i].CateId] = cates[i]
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": id}
i++
}
}
// LogJ(">>")
// LogJ(cates)
// 建立层级
hasParent := map[string]bool{} // 有父的cate
for _, cate := range cates {
parentCateId := cate.ParentCateId
if parentCateId != "" {
if parentCate, ok := cateMap[parentCateId]; ok {
// Log("________")
// LogJ(parentCate)
// LogJ(cate)
if parentCate.Children == nil {
parentCate.Children = []*info.Cate{cate}
} else {
parentCate.Children = append(parentCate.Children, cate)
}
hasParent[cate.CateId] = true
}
}
}
// 得到没有父的cate, 作为第一级cate
catesTree := []*info.Cate{}
for _, cate := range cates {
if !hasParent[cate.CateId] {
catesTree = append(catesTree, cate)
}
}
c.RenderArgs["cates"] = cates
c.RenderArgs["catesTree"] = catesTree
}
// 单页
@@ -348,10 +304,9 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
// 得到主题信息
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
c.RenderArgs["themeInfo"] = themeInfo
// Log(">>")
// Log(userBlog.Style)
// Log(userBlog.ThemeId.Hex())
Log(">>")
Log(userBlog.Style)
Log(userBlog.ThemeId.Hex())
return true, userBlog
}
@@ -507,7 +462,6 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re
// 进入某个用户的博客
var blogPageSize = 5
var searchBlogPageSize = 30
// 分类 /cate/xxxxxxxx?notebookId=1212
func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
// 自定义域名
@@ -586,14 +540,19 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
}
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
var ok = false
fmt.Println("before test...");
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
fmt.Println("404 occur");
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
fmt.Println("after test0...");
// 分页的话, 需要分页信息, totalPage, curPage
page := c.GetPage()
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
blogs2 := blogService.FixBlogs(blogs)
c.RenderArgs["posts"] = blogs2
c.setPaging(pageInfo)
@@ -601,6 +560,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
c.RenderArgs["curIsIndex"] = true
return c.render("index.html", userBlog.ThemePath)
}
@@ -822,7 +782,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
return c.RenderJsonP(callback, re)
}
func (c Blog) GetComments(noteId string, callback string) revel.Result {
func (c Blog) GetComments(noteId string) revel.Result {
// 评论
userId := c.GetUserId()
page := c.GetPage()
@@ -835,10 +795,6 @@ func (c Blog) GetComments(noteId string, callback string) revel.Result {
result["commentUserInfo"] = commentUserInfo
re.Item = result
if callback != "" {
return c.RenderJsonP(callback, result)
}
return c.RenderJson(re)
}
+14 -15
View File
@@ -2,17 +2,17 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/captcha"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
// "strconv"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
// "strconv"
"net/http"
)
@@ -22,7 +22,6 @@ type Captcha struct {
}
type Ca string
func (r Ca) Apply(req *revel.Request, resp *revel.Response) {
resp.WriteHeader(http.StatusOK, "image/png")
}
@@ -33,11 +32,11 @@ func (c Captcha) Get() revel.Result {
image.WriteTo(c.Response.Out)
sessionId := c.Session["_ID"]
// LogJ(c.Session)
// Log("------")
// Log(str)
// Log(sessionId)
Log("..")
// LogJ(c.Session)
// Log("------")
// Log(str)
// Log(sessionId)
Log("..")
sessionService.SetCaptcha(sessionId, str)
return c.Render()
+35 -51
View File
@@ -2,16 +2,16 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"fmt"
"github.com/leanote/leanote/app/info"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/lea/netutil"
"gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
// "strconv"
// "strconv"
"strings"
"fmt"
)
// 首页
@@ -22,7 +22,7 @@ type File struct {
// 上传的是博客logo
// TODO logo不要设置权限, 另外的目录
func (c File) UploadBlogLogo() revel.Result {
re := c.uploadImage("blogLogo", "")
re := c.uploadImage("blogLogo", "");
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
@@ -34,9 +34,8 @@ func (c File) UploadBlogLogo() revel.Result {
// 拖拉上传, pasteImage
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
func (c File) PasteImage(noteId string) revel.Result {
re := c.uploadImage("pasteImage", "")
re := c.uploadImage("pasteImage", "");
if noteId != "" {
userId := c.GetUserId()
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
@@ -52,14 +51,13 @@ func (c File) PasteImage(noteId string) revel.Result {
}
}
}
}
return c.RenderJson(re)
}
// 头像设置
func (c File) UploadAvatar() revel.Result {
re := c.uploadImage("logo", "")
re := c.uploadImage("logo", "");
c.RenderArgs["fileUrlPath"] = re.Id
c.RenderArgs["resultCode"] = re.Code
@@ -68,7 +66,7 @@ func (c File) UploadAvatar() revel.Result {
if re.Ok {
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
if re.Ok {
c.UpdateSession("Logo", re.Id)
c.UpdateSession("Logo", re.Id);
}
}
@@ -77,7 +75,7 @@ func (c File) UploadAvatar() revel.Result {
// leaui image plugin upload image
func (c File) UploadImageLeaui(albumId string) revel.Result {
re := c.uploadImage("", albumId)
re := c.uploadImage("", albumId);
return c.RenderJson(re)
}
@@ -102,19 +100,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
return re
}
defer file.Close()
// 生成上传路径
newGuid := NewGuid()
userId := c.GetUserId()
if from == "logo" || from == "blogLogo" {
fileUrlPath = "public/upload/" + Digest3(userId) + "/" + userId + "/images/logo"
if(from == "logo" || from == "blogLogo") {
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
} else {
// fileUrlPath = "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath = "files/" + GetRandomFilePath(userId, newGuid) + "/images"
fileUrlPath = "files/" + c.GetUserId() + "/images"
}
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
@@ -123,19 +114,18 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
// 生成新的文件名
filename := handel.Filename
var ext string
var ext string;
if from == "pasteImage" {
handel.Filename = c.Message("unTitled")
ext = ".png" // TODO 可能不是png类型
ext = ".png"; // TODO 可能不是png类型
} else {
_, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
resultMsg = "Please upload image"
return re
}
}
filename = newGuid + ext
filename = NewGuid() + ext
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
@@ -143,25 +133,25 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
}
var maxFileSize float64
if from == "logo" {
maxFileSize = configService.GetUploadSize("uploadAvatarSize")
if(from == "logo") {
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
} else if from == "blogLogo" {
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize")
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
} else {
maxFileSize = configService.GetUploadSize("uploadImageSize")
maxFileSize = configService.GetUploadSize("uploadImageSize");
}
if maxFileSize <= 0 {
maxFileSize = 1000
}
// > 2M?
if float64(len(data)) > maxFileSize*float64(1024*1024) {
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
resultCode = 0
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
return re
}
toPath := dir + "/" + filename
toPath := dir + "/" + filename;
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
LogJ(err)
@@ -181,18 +171,17 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
Path: fileUrlPath,
Size: filesize}
id := bson.NewObjectId()
id := bson.NewObjectId();
fileInfo.FileId = id
fileId = id.Hex()
if from == "logo" || from == "blogLogo" {
fileId = fileUrlPath
if(from == "logo" || from == "blogLogo") {
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
}
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
resultMsg = c.Message(resultMsg)
fileInfo.Path = "" // 不要返回
fileInfo.Path = ""; // 不要返回
re.Item = fileInfo
return re
@@ -215,13 +204,13 @@ func (c File) DeleteImage(fileId string) revel.Result {
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
return c.RenderJson(re)
}
//-----------
// 输出image
// 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId) // 得到路径
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
sessionId := c.Session.Id()
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
if path == "" {
return c.RenderText("")
}
@@ -238,17 +227,12 @@ func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
return c.RenderJson(re)
}
// 复制外网的图片
// 复制外网的图片, 成公共图片 放在/upload下
// 都要好好的计算大小
func (c File) CopyHttpImage(src string) revel.Result {
re := info.NewRe()
// 生成上传路径
newGuid := NewGuid()
userId := c.GetUserId()
// fileUrlPath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/images"
fileUrlPath := "files/" + GetRandomFilePath(userId, newGuid) + "/images"
dir := revel.BasePath + "/" + fileUrlPath
fileUrlPath := "upload/" + c.GetUserId() + "/images"
dir := revel.BasePath + "/public/" + fileUrlPath
err := os.MkdirAll(dir, 0755)
if err != nil {
return c.RenderJson(re)
@@ -266,11 +250,11 @@ func (c File) CopyHttpImage(src string) revel.Result {
Path: fileUrlPath + "/" + filename,
Size: filesize}
id := bson.NewObjectId()
id := bson.NewObjectId();
fileInfo.FileId = id
re.Id = id.Hex()
// re.Item = fileInfo.Path
re.Item = fileInfo.Path
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
return c.RenderJson(re)
+9 -9
View File
@@ -1,9 +1,9 @@
package controllers
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
)
// 首页
@@ -13,21 +13,21 @@ type Index struct {
}
func (c Index) Default() revel.Result {
if configService.HomePageIsAdminsBlog() {
if configService.HomePageIsAdminsBlog(){
blog := Blog{c.BaseController}
return blog.Index(configService.GetAdminUsername())
return blog.Index(configService.GetAdminUsername());
}
return c.Index()
}
// leanote展示页, 没有登录的, 或已登录明确要进该页的
func (c Index) Index() revel.Result {
c.SetUserInfo()
c.RenderArgs["title"] = "leanote"
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
c.SetLocale()
lang := c.SetLocale()
return c.RenderTemplate("home/index.html")
return c.RenderTemplate("home/index_" + lang + ".html");
}
// 建议
@@ -37,8 +37,8 @@ func (c Index) Suggestion(addr, suggestion string) revel.Result {
// 发给我
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)
}
+153 -214
View File
@@ -2,20 +2,17 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "encoding/json"
"gopkg.in/mgo.v2/bson"
"os"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"os/exec"
"regexp"
"strings"
"time"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
"fmt"
// "bytes"
// "os"
// "time"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "bytes"
// "os"
)
type Note struct {
@@ -25,9 +22,9 @@ type Note struct {
// 笔记首页, 判断是否已登录
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
// 否则, 转向登录页面
func (c Note) Index(noteId, online string) revel.Result {
func (c Note) Index(noteId string) revel.Result {
c.SetLocale()
userInfo := c.GetUserAndBlogUrl()
userInfo := c.GetUserInfo()
userId := userInfo.UserId.Hex()
@@ -52,11 +49,10 @@ func (c Note) Index(noteId, online string) revel.Result {
hasRightNoteId := false
if IsObjectId(noteId) {
note := noteService.GetNoteById(noteId)
if note.NoteId != "" {
var noteOwner = note.UserId.Hex()
noteContent = noteService.GetNoteContent(noteId, noteOwner)
if note.NoteId != "" {
hasRightNoteId = true
c.RenderArgs["curNoteId"] = noteId
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
@@ -67,13 +63,13 @@ func (c Note) Index(noteId, online string) revel.Result {
// 不要获取notebook下的笔记
// 在前端下发请求
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
c.RenderArgs["curSharedUserId"] = noteOwner
c.RenderArgs["curSharedUserId"] = noteOwner;
// 没有读写权限
} else {
hasRightNoteId = false
}
} else {
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false)
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false);
// 如果指定了某笔记, 则该笔记放在首位
lenNotes := len(notes)
@@ -84,7 +80,7 @@ func (c Note) Index(noteId, online string) revel.Result {
for _, note := range notes {
if note.NoteId.Hex() != noteId {
if i == lenNotes { // 防止越界
break
break;
}
notes2[i] = note
i++
@@ -96,14 +92,14 @@ func (c Note) Index(noteId, online string) revel.Result {
}
// 得到最近的笔记
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
c.RenderArgs["latestNotes"] = latestNotes
}
// 没有传入笔记
// 那么得到最新笔记
if !hasRightNoteId {
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
if len(notes) > 0 {
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
@@ -128,9 +124,10 @@ func (c Note) Index(noteId, online string) revel.Result {
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
// return c.RenderTemplate("note/note.html")
if isDev, _ := revel.Config.Bool("mode.dev"); isDev && online == "" {
// return c.RenderTemplate("note/note.html")
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
return c.RenderTemplate("note/note-dev.html")
} else {
return c.RenderTemplate("note/note.html")
@@ -141,13 +138,13 @@ func (c Note) Index(noteId, online string) revel.Result {
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
// 否则, 转向登录页面
func (c Note) ListNotes(notebookId string) revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false);
return c.RenderJson(notes)
}
// 得到trash
func (c Note) ListTrashNotes() revel.Result {
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false);
return c.RenderJson(notes)
}
@@ -162,12 +159,30 @@ func (c Note) GetNoteContent(noteId string) revel.Result {
return c.RenderJson(noteContent)
}
// 更新note或content
// 肯定会传userId(谁的), NoteId
// 会传Title, Content, Tags, 一种或几种
type NoteOrContent struct {
NotebookId string
NoteId string
UserId string
Title string
Desc string
ImgSrc string
Tags []string
Content string
Abstract string
IsNew bool
IsMarkdown bool
FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
}
// 这里不能用json, 要用post
func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result {
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
// 新添加note
if noteOrContent.IsNew {
userId := c.GetObjectUserId()
// myUserId := userId
userId := c.GetObjectUserId();
// myUserId := userId
// 为共享新建?
if noteOrContent.FromUserId != "" {
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
@@ -177,17 +192,17 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
Title: noteOrContent.Title,
Tags: strings.Split(noteOrContent.Tags, ","),
Tags: noteOrContent.Tags,
Desc: noteOrContent.Desc,
ImgSrc: noteOrContent.ImgSrc,
IsBlog: noteOrContent.IsBlog,
IsMarkdown: noteOrContent.IsMarkdown,
}
};
noteContent := info.NoteContent{NoteId: note.NoteId,
UserId: userId,
IsBlog: note.IsBlog,
Content: noteOrContent.Content,
Abstract: noteOrContent.Abstract}
Abstract: noteOrContent.Abstract};
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
return c.RenderJson(note)
@@ -199,102 +214,61 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
// Desc前台传来
if c.Has("Desc") {
needUpdateNote = true
noteUpdate["Desc"] = noteOrContent.Desc
noteUpdate["Desc"] = noteOrContent.Desc;
}
if c.Has("ImgSrc") {
needUpdateNote = true
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc;
}
if c.Has("Title") {
needUpdateNote = true
noteUpdate["Title"] = noteOrContent.Title
noteUpdate["Title"] = noteOrContent.Title;
}
if c.Has("Tags") {
if c.Has("Tags[]") {
needUpdateNote = true
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",")
noteUpdate["Tags"] = noteOrContent.Tags;
}
// web端不控制
if needUpdateNote {
noteService.UpdateNote(c.GetUserId(),
noteOrContent.NoteId, noteUpdate, -1)
noteService.UpdateNote(noteOrContent.UserId, c.GetUserId(),
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)
Log(contentOk)
Log(contentMsg)
if c.Has("Content") {
noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
}
return c.RenderJson(true)
}
// 删除note/ 删除别人共享给我的笔记
// userId 是note.UserId
func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result {
if !isShared {
for _, noteId := range noteIds {
trashService.DeleteNote(noteId, c.GetUserId())
}
return c.RenderJson(true)
func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
if(!isShared) {
return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
}
for _, noteId := range noteIds {
trashService.DeleteSharedNote(noteId, c.GetUserId())
}
return c.RenderJson(true)
return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
}
// 删除trash, 已弃用, 用DeleteNote
// 删除trash
func (c Note) DeleteTrash(noteId string) revel.Result {
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()))
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()));
}
// 移动note
func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result {
userId := c.GetUserId()
for _, noteId := range noteIds {
noteService.MoveNote(noteId, notebookId, userId)
}
return c.RenderJson(true)
func (c Note) MoveNote(noteId, notebookId string) revel.Result {
return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
}
// 复制note
func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds))
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopyNote(noteId, notebookId, userId)
}
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJson(re)
func (c Note) CopyNote(noteId, notebookId string) revel.Result {
return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
}
// 复制别人共享的笔记给我
func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) revel.Result {
copyNotes := make([]info.Note, len(noteIds))
userId := c.GetUserId()
for i, noteId := range noteIds {
copyNotes[i] = noteService.CopySharedNote(noteId, notebookId, fromUserId, userId)
}
re := info.NewRe()
re.Ok = true
re.Item = copyNotes
return c.RenderJson(re)
func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result {
return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
}
//------------
@@ -304,105 +278,50 @@ func (c Note) SearchNote(key string) revel.Result {
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
return c.RenderJson(blogs)
}
// 通过tags搜索
func (c Note) SearchNoteByTags(tags []string) revel.Result {
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
return c.RenderJson(blogs)
}
// 生成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来验证之
appKeyTrue, _ := revel.Config.String("app.secret")
if appKeyTrue != appKey {
return c.RenderText("auth error")
return c.RenderText("")
}
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
return c.RenderText("no note")
return c.RenderText("")
}
c.SetLocale()
noteUserId := note.UserId.Hex()
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["content"] = contentStr
c.RenderArgs["content"] = content.Content
c.RenderArgs["userInfo"] = userInfo
userBlog := blogService.GetUserBlog(noteUserId)
c.RenderArgs["userBlog"] = userBlog
return c.RenderTemplate("file/pdf.html")
return c.RenderTemplate("html2Image/index.html")
}
// 导出成PDF
func (c Note) ExportPdf(noteId string) revel.Result {
func (c Note) Html2Image(noteId string) revel.Result {
re := info.NewRe()
userId := c.GetUserId()
note := noteService.GetNoteById(noteId)
if note.NoteId == "" {
re.Msg = "No Note"
return c.RenderText("error")
return c.RenderJson(re)
}
noteUserId := note.UserId.Hex()
@@ -411,71 +330,91 @@ func (c Note) ExportPdf(noteId string) revel.Result {
// 是否是有权限协作的
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
re.Msg = "No Perm"
return c.RenderText("No Perm")
return c.RenderJson(re)
}
}
// path 判断是否需要重新生成之
guid := NewGuid()
fileUrlPath := "files/export_pdf"
dir := revel.BasePath + "/" + fileUrlPath
if !MkdirAll(dir) {
return c.RenderText("error, no dir")
fileUrlPath := "/upload/" + noteUserId + "/images/weibo"
dir := revel.BasePath + "/public/" + fileUrlPath
if !ClearDir(dir) {
re.Msg = "No Dir"
return c.RenderJson(re)
}
filename := guid + ".pdf"
filename := note.NoteId.Hex() + ".png";
path := dir + "/" + filename
// leanote.com的secret
appKey, _ := revel.Config.String("app.secretLeanote")
if appKey == "" {
appKey, _ = revel.Config.String("app.secret")
// cookie
cookieName := revel.CookiePrefix + "_SESSION"
cookie, err := c.Request.Cookie(cookieName)
cookieStr := cookie.String()
cookieValue := ""
if err == nil && len(cookieStr) > len(cookieName) {
cookieValue = cookieStr[len(cookieName)+1:]
}
appKey, _ := revel.Config.String("app.secret")
cookieDomain, _ := revel.Config.String("cookie.domain")
// 生成之
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
// 默认路径
url := configService.GetSiteUrl() + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
binPath := configService.GetGlobalStringConfig("toImageBinPath")
if binPath == "" {
binPath = "/usr/local/bin/wkhtmltopdf"
return c.RenderJson(re);
}
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 + "\""
}
cc := binPath + " \"" + url + "\" \"" + path + "\" \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
cmd := exec.Command("/bin/sh", "-c", cc)
_, err := cmd.Output()
if err != nil {
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
}
file, err := os.Open(path)
if err != nil {
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
}
// http://stackoverflow.com/questions/8588818/chrome-pdf-display-duplicate-headers-received-from-the-server
// filenameReturn = strings.Replace(filenameReturn, ",", "-", -1)
filenameReturn := note.Title
filenameReturn = FixFilename(filenameReturn)
if filenameReturn == "" {
filenameReturn = "Untitled.pdf"
Log(cc);
b, err := cmd.Output()
if err == nil {
re.Ok = true
re.Id = fileUrlPath + "/" + filename
} else {
filenameReturn += ".pdf"
re.Msg = string(b)
Log("error:......")
Log(string(b))
}
return c.RenderBinary(file, filenameReturn, revel.Attachment, time.Now()) // revel.Attachment
return c.RenderJson(re)
/*
// 这里速度慢, 生成不完全(图片和内容都不全)
content := noteService.GetNoteContent(noteId, noteUserId)
userInfo := userService.GetUserInfo(noteUserId);
c.SetLocale()
c.RenderArgs["blog"] = note
c.RenderArgs["content"] = content.Content
c.RenderArgs["userInfo"] = userInfo
userBlog := blogService.GetUserBlog(noteUserId)
c.RenderArgs["userBlog"] = userBlog
html := c.RenderTemplateStr("html2Image/index.html") // Result类型的
contentFile := dir + "/html";
fout, err := os.Create(contentFile)
if err != nil {
return c.RenderJson(re)
}
fout.WriteString(html);
fout.Close()
cc := "/Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/c.js \"" + contentFile + "\" \"" + path + "\""
cmd := exec.Command("/bin/sh", "-c", cc)
b, err := cmd.Output()
if err == nil {
re.Ok = true
re.Id = fileUrlPath + "/" + filename
} else {
Log(string(b))
}
*/
}
// 设置/取消Blog; 置顶
func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
for _, noteId := range noteIds {
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
}
return c.RenderJson(true)
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
return c.RenderJson(re)
}
+9 -12
View File
@@ -1,12 +1,12 @@
package controllers
import (
"github.com/revel/revel"
"encoding/json"
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// . "github.com/leanote/leanote/app/lea"
// "io/ioutil"
)
type Notebook struct {
@@ -34,19 +34,17 @@ func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.
Title: title,
Seq: -1,
UserId: c.GetObjectUserId()}
if parentNotebookId != "" {
if(parentNotebookId != "") {
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
}
re := notebookService.AddNotebook(notebook)
re, notebook := notebookService.AddNotebook(notebook)
if re {
if(re) {
return c.RenderJson(notebook)
} else {
return c.RenderJson(false)
}
}
// 修改标题
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
@@ -54,9 +52,9 @@ func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
// 排序
// 无用
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
// return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
// }
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
}
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
type DragNotebooksInfo struct {
@@ -64,7 +62,6 @@ type DragNotebooksInfo struct {
ParentNotebookId string
Siblings []string
}
// 传过来的data是JSON.stringfy数据
func (c Notebook) DragNotebooks(data string) revel.Result {
info := DragNotebooksInfo{}
+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")
}
+17 -17
View File
@@ -2,13 +2,13 @@ package controllers
import (
"github.com/revel/revel"
// "strings"
// "time"
// "strings"
// "time"
// "encoding/json"
// "github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/lea/blog"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/lea/blog"
// "gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "math"
@@ -23,7 +23,7 @@ type Preview struct {
// 得到要预览的主题绝对路径
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
if themeId != "" {
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了, 待优化, 有时会取不到
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
} else {
themeId = c.Session["themeId"] // 直接从session中获取
}
@@ -47,7 +47,7 @@ func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
return c.E404()
}
return c.Blog.Index(c.GetUserId())
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
}
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
@@ -61,43 +61,43 @@ func (c Preview) Tags(userIdOrEmail string) revel.Result {
return c.E404()
}
return c.Blog.Tags(c.GetUserId())
// if tag == "" {
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// }
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// if tag == "" {
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// }
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Cate(userIdOrEmail, notebookId)
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Post(userIdOrEmail, noteId)
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Single(userIdOrEmail, singleId)
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
if !c.getPreviewThemeAbsolutePath("") {
return c.E404()
}
return c.Blog.Search(c.GetUserId(), keywords)
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
}
+100 -39
View File
@@ -2,30 +2,33 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
"github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "time"
)
type Share struct {
BaseController
}
const AttachToken = 2
// 添加共享note
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享
myEmail := c.GetEmail()
myEmail := c.GetEmail();
for _, email := range emails {
if email == "" {
continue
continue;
}
if myEmail != email {
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email)
if(myEmail != email) {
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email);
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else {
@@ -36,17 +39,19 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
return c.RenderJson(status)
}
// 添加共享notebook
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
// 自己不能给自己添加共享
myEmail := c.GetEmail()
myEmail := c.GetEmail();
for _, email := range emails {
if email == "" {
continue
continue;
}
if myEmail != email {
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email)
if(myEmail != email) {
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email);
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
} else {
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
@@ -62,11 +67,11 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
// 表示是默认笔记本, 不是某个特定notebook的共享
var notes []info.ShareNoteWithPerm
if notebookId == "" {
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false)
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false);
return c.RenderJson(notes)
} else {
// 有notebookId的
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false))
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false));
}
}
@@ -90,7 +95,7 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
c.RenderArgs["isNote"] = true
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex()
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
c.RenderArgs["title"] = note.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
@@ -105,7 +110,7 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
c.RenderArgs["isNote"] = false
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex()
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
c.RenderArgs["title"] = notebook.Title
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
@@ -114,79 +119,135 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
//------------
// 改变share note 权限
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId))
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId));
}
// 改变share notebook 权限
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId))
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId));
}
//---------------
// 删除share note
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId))
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId));
}
// 删除share notebook
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId))
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId));
}
// 删除share note, 被共享方删除
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()))
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()));
}
// 删除share notebook, 被共享方删除
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()))
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()));
}
// 删除fromUserId分享给我的所有note, notebook
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()))
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
}
//-------------
// 用户组
// 将笔记分享给分组
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
re := info.NewRe()
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm)
return c.RenderJson(re)
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
return c.RenderJson(re);
}
// 删除
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
re := info.NewRe()
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId)
return c.RenderJson(re)
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
return c.RenderJson(re);
}
// 更新, 也是一样, 先删后加
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
return c.AddShareNoteGroup(noteId, groupId, perm)
}
//------
// 将笔记分享给分组
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
re := info.NewRe()
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm)
return c.RenderJson(re)
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
return c.RenderJson(re);
}
// 删除
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
re := info.NewRe()
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId)
return c.RenderJson(re)
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
return c.RenderJson(re);
}
// 更新, 也是一样, 先删后加
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
return c.AddShareNotebookGroup(notebookId, groupId, perm)
}
//生成笔记分享密码及更新到db
func (c Share) GenShareLinkPass(noteId string) revel.Result {
pass, ok := shareService.GenSharePass(noteId)
re := info.Re{Ok : true, Item : pass, List: ok}
return c.RenderJson(re);
}
func (c Share) QuerySharePass(noteId string) revel.Result {
pass := shareService.QuerySharePass(noteId)
re := info.Re{Ok : true, Item : pass}
return c.RenderJson(re);
}
//展示分享笔记
func (c Share) ShowShareNote(noteId string) revel.Result {
note := noteService.GetNoteById(noteId)
//
c.RenderArgs["noteId"] = noteId
username := userService.GetUsernameById(note.UserId)
c.RenderArgs["userName"] = username
c.RenderArgs["isMarkDown"] = note.IsMarkdown
// c.RenderArgs["timestamp"] = time.Now().Unix()
c.SetLocale()
return c.RenderTemplate("share/show_share_note.html")
}
//验证分享密码
func (c Share) Verify4ShareNote(noteId string, sharePass int) revel.Result {
ok, note, noteContent := shareService.Verify4ShareNote(noteId, sharePass)
attaches := []info.Attach{}
if ok && note.AttachNum > 0 {
attaches = attachService.ListAttachs(noteId, "")
}
token := tokenService.NewToken(noteId, noteId, AttachToken)
//插入笔记作为链接中的附件
noteAttachIds := map[string]bool{}
noteContent.Content, noteAttachIds = shareService.AppendToken4URL(token, noteContent.Content)
//过滤掉插入笔记的附件
filteredAttaches := []info.Attach{}
if len(noteAttachIds) > 0 && len(attaches) > 0 {
for _, attach := range attaches {
if !noteAttachIds[attach.AttachId.Hex()] {
filteredAttaches = append(filteredAttaches, attach)
}
}
} else {
filteredAttaches = attaches
}
sessionId := c.Session.Id()
sessionService.SetToken(sessionId, token)
re := info.Re{Ok : ok, Item: note, List: filteredAttaches, Id: token, Msg: noteContent.Content}
return c.RenderJson(re)
}
-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)
}
+69 -33
View File
@@ -2,16 +2,16 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/info"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
"github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
"strconv"
)
@@ -29,59 +29,59 @@ func (c User) Account(tab int) revel.Result {
// 修改用户名, 需要重置session
func (c User) UpdateUsername(username string) revel.Result {
re := info.NewRe()
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
re := info.NewRe();
if(c.GetUsername() == "demo") {
re.Msg = "cannotUpdateDemo"
return c.RenderRe(re)
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
if re.Ok {
if(re.Ok) {
c.UpdateSession("Username", username)
}
return c.RenderRe(re)
return c.RenderRe(re);
}
// 修改密码
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewRe()
if c.GetUserId() == configService.GetGlobalStringConfig("demoUserId") {
re := info.NewRe();
if(c.GetUsername() == "demo") {
re.Msg = "cannotUpdateDemo"
return c.RenderRe(re)
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
return c.RenderRe(re)
return c.RenderRe(re);
}
// 更新主题
func (c User) UpdateTheme(theme string) revel.Result {
re := info.NewRe()
re := info.NewRe();
re.Ok = userService.UpdateTheme(c.GetUserId(), theme)
if re.Ok {
c.UpdateSession("Theme", theme)
}
return c.RenderJson(re)
return c.RenderJson(re);
}
// 发送邀请链接
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
re := info.NewRe()
if content == "" || !IsEmail(toEmail) {
return c.RenderJson(re)
return c.RenderJson(re);
}
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
return c.RenderJson(re)
return c.RenderJson(re);
}
//---------------------------
@@ -93,10 +93,25 @@ func (c User) ReSendActiveEmail() revel.Result {
return c.RenderJson(re)
}
// 修改Email发送激活邮箱
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
re := info.NewRe()
if(c.GetUsername() == "demo") {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re);
}
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re);
}
re.Ok, re.Msg = emailService.UpdateEmailSendActiveEmail(c.GetUserInfo(), email)
return c.RenderRe(re)
}
// 通过点击链接
// 修改邮箱
func (c User) UpdateEmail(token string) revel.Result {
c.SetUserInfo()
c.SetUserInfo();
ok, msg, email := userService.UpdateEmail(token)
@@ -115,13 +130,13 @@ func (c User) UpdateEmail(token string) revel.Result {
// 注册后激活邮箱
func (c User) ActiveEmail(token string) revel.Result {
c.SetUserInfo()
c.SetUserInfo();
ok, msg, email := userService.ActiveEmail(token)
// 需要修改session
if ok {
c.UpdateSession("Verified", "1")
c.UpdateSession("Verified", "1");
}
c.RenderArgs["title"] = "验证邮箱"
@@ -132,15 +147,36 @@ func (c User) ActiveEmail(token string) revel.Result {
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 {
re := info.NewRe()
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth)
if re.Ok {
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth))
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth))
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth))
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth));
LogJ(c.Session)
}
@@ -151,9 +187,9 @@ func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin)
if re.Ok {
if leftIsMin {
c.UpdateSession("LeftIsMin", "1")
c.UpdateSession("LeftIsMin", "1");
} else {
c.UpdateSession("LeftIsMin", "0")
c.UpdateSession("LeftIsMin", "0");
}
}
return c.RenderJson(re)
+13 -13
View File
@@ -1,15 +1,15 @@
package admin
import (
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"github.com/leanote/leanote/app/controllers"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
@@ -20,23 +20,23 @@ type AdminBaseController struct {
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc
return sorterField, isAsc;
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc
return sorterField, isAsc;
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc
return sorterField, isAsc;
}
}
@@ -47,7 +47,7 @@ func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc
return sorterField, isAsc;
}
func (c AdminBaseController) updateConfig(keys []string) {
+5 -5
View File
@@ -2,7 +2,7 @@ package admin
import (
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
)
@@ -15,16 +15,16 @@ type AdminBlog struct {
// admin 主页
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"})
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["blogs"] = blogs
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/blog/list.html")
return c.RenderTemplate("admin/blog/list.html");
}
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
re := info.NewRe()
re.Ok = blogService.SetRecommend(noteId, recommend)
re.Ok = blogService.SetRecommend(noteId, recommend);
return c.RenderJson(re)
}
+2 -2
View File
@@ -21,7 +21,7 @@ func (c Admin) Index() revel.Result {
c.RenderArgs["countNote"] = noteService.CountNote("")
c.RenderArgs["countBlog"] = noteService.CountBlog("")
return c.RenderTemplate("admin/index.html")
return c.RenderTemplate("admin/index.html");
}
// 模板
@@ -35,5 +35,5 @@ func (c Admin) T(t string) revel.Result {
}
func (c Admin) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view)
return c.RenderTemplate("admin/" + view);
}
+6 -6
View File
@@ -1,13 +1,13 @@
package admin
import (
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"archive/tar"
"compress/gzip"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"io"
"os"
"io"
"time"
)
@@ -22,12 +22,12 @@ func (c AdminData) Index() revel.Result {
// 逆序之
backups2 := make([]map[string]string, len(backups))
j := 0
for i := len(backups) - 1; i >= 0; i-- {
for i := len(backups)-1; i >= 0; i-- {
backups2[j] = backups[i]
j++
}
c.RenderArgs["backups"] = backups2
return c.RenderTemplate("admin/data/index.html")
return c.RenderTemplate("admin/data/index.html");
}
func (c AdminData) Backup() revel.Result {
+23 -26
View File
@@ -1,11 +1,11 @@
package admin
import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strconv"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"strings"
"strconv"
)
// admin 首页
@@ -25,7 +25,7 @@ func (c AdminEmail) Blog() revel.Result {
newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html")
return c.RenderTemplate("admin/setting/blog.html");
}
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe()
@@ -41,17 +41,14 @@ func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
func (c AdminEmail) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html")
return c.RenderTemplate("admin/setting/demo.html");
}
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword)
if err != nil {
return c.RenderJson(info.Re{Ok: false})
}
userInfo := authService.Login(demoUsername, demoPassword)
if userInfo.UserId == "" {
re.Msg = "The User is Not Exists"
re.Msg = "The User is Not Exists";
return c.RenderJson(re)
}
@@ -66,7 +63,7 @@ func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
// 长微博的bin路径phantomJs
func (c AdminEmail) ToImage() revel.Result {
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
return c.RenderTemplate("admin/setting/toImage.html")
return c.RenderTemplate("admin/setting/toImage.html");
}
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
re := info.NewRe()
@@ -74,13 +71,12 @@ func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
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.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
return c.RenderJson(re)
}
@@ -133,13 +129,13 @@ func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmai
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
}
sendEmails = strings.Replace(sendEmails, "\r", "", -1)
emails := strings.Split(sendEmails, "\n")
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody)
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody);
return c.RenderJson(re)
}
@@ -157,7 +153,7 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
}
emails = strings.Replace(emails, "\r", "", -1)
@@ -166,13 +162,14 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
users := userService.ListUserInfosByEmails(emailsArr)
LogJ(emailsArr)
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
return c.RenderJson(re)
}
// send Email dialog
func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
func (c AdminEmail) SendEmailDialog(emails string) revel.Result{
emailsArr := strings.Split(emails, ",")
emailsNl := strings.Join(emailsArr, "\n")
@@ -180,7 +177,7 @@ func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
c.RenderArgs["str"] = configService.GlobalStringConfigs
c.RenderArgs["map"] = configService.GlobalMapConfigs
return c.RenderTemplate("admin/email/emailDialog.html")
return c.RenderTemplate("admin/email/emailDialog.html");
}
func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilterBlackList, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
@@ -196,19 +193,19 @@ func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilter
if saveAsOldEmail {
oldEmails := configService.GetGlobalMapConfig("oldEmails")
oldEmails[latestEmailSubject] = latestEmailBody
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails)
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
}
users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified)
if users == nil || len(users) == 0 {
if(users == nil || len(users) == 0) {
re.Ok = false
re.Msg = "no users"
return c.RenderJson(re)
}
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
if !re.Ok {
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
if(!re.Ok) {
return c.RenderJson(re)
}
@@ -227,10 +224,10 @@ func (c AdminEmail) DeleteEmails(ids string) revel.Result {
func (c AdminEmail) List(sorter, keywords string) revel.Result {
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"})
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords)
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"});
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["emails"] = emails
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/email/list.html")
return c.RenderTemplate("admin/email/list.html");
}
+15 -19
View File
@@ -2,10 +2,10 @@ package admin
import (
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
"fmt"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"strings"
"fmt"
)
// admin 首页
@@ -25,7 +25,7 @@ func (c AdminSetting) Blog() revel.Result {
newTags := configService.GetGlobalArrayConfig("newTags")
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
return c.RenderTemplate("admin/setting/blog.html")
return c.RenderTemplate("admin/setting/blog.html");
}
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
re := info.NewRe()
@@ -42,7 +42,7 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result {
re := info.NewRe()
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds)
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds);
return c.RenderJson(re)
}
@@ -51,18 +51,14 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
func (c AdminSetting) Demo() revel.Result {
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
return c.RenderTemplate("admin/setting/demo.html")
return c.RenderTemplate("admin/setting/demo.html");
}
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
re := info.NewRe()
userInfo, err := authService.Login(demoUsername, demoPassword)
if err != nil {
fmt.Println(err)
return c.RenderJson(info.Re{Ok: false})
}
userInfo := authService.Login(demoUsername, demoPassword)
if userInfo.UserId == "" {
re.Msg = "The User is Not Exists"
re.Msg = "The User is Not Exists";
return c.RenderJson(re)
}
@@ -73,15 +69,15 @@ func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
return c.RenderJson(re)
}
func (c AdminSetting) ExportPdf(path string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
return c.RenderJson(re)
// ToImage
// 长微博的bin路径phantomJs
func (c AdminSetting) ToImage() revel.Result {
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
return c.RenderTemplate("admin/setting/toImage.html");
}
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
func (c AdminSetting) DoToImage(toImageBinPath string) revel.Result {
re := info.NewRe()
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
return c.RenderJson(re)
}
@@ -94,7 +90,7 @@ func (c AdminSetting) SubDomain() revel.Result {
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
return c.RenderTemplate("admin/setting/subDomain.html")
return c.RenderTemplate("admin/setting/subDomain.html");
}
func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, blackSubDomains, allowCustomDomain, blackCustomDomains string) revel.Result {
re := info.NewRe()
@@ -2,9 +2,9 @@ package admin
import (
"github.com/revel/revel"
// "encoding/json"
// "encoding/json"
"github.com/leanote/leanote/app/info"
// "io/ioutil"
// "io/ioutil"
)
// Upgrade controller
@@ -14,7 +14,7 @@ type AdminUpgrade struct {
func (c AdminUpgrade) UpgradeBlog() revel.Result {
upgradeService.UpgradeBlog()
return nil
return nil;
}
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
@@ -22,9 +22,3 @@ func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
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)
}
+12 -13
View File
@@ -1,9 +1,9 @@
package admin
import (
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "time"
. "github.com/leanote/leanote/app/lea"
// "time"
"github.com/leanote/leanote/app/info"
)
@@ -15,33 +15,32 @@ type AdminUser struct {
// admin 主页
var userPageSize = 10
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
pageNumber := c.GetPage()
if userPageSize == 0 {
pageSize = userPageSize
}
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"})
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords)
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
c.RenderArgs["pageInfo"] = pageInfo
c.RenderArgs["users"] = users
c.RenderArgs["keywords"] = keywords
return c.RenderTemplate("admin/user/list.html")
return c.RenderTemplate("admin/user/list.html");
}
func (c AdminUser) Add() revel.Result {
return c.RenderTemplate("admin/user/add.html")
return c.RenderTemplate("admin/user/add.html");
}
// 添加
func (c AdminUser) Register(email, pwd string) revel.Result {
re := info.NewRe()
re := info.NewRe();
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
// 注册
@@ -54,13 +53,13 @@ func (c AdminUser) Register(email, pwd string) revel.Result {
func (c AdminUser) ResetPwd(userId string) revel.Result {
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
return c.RenderTemplate("admin/user/reset_pwd.html")
return c.RenderTemplate("admin/user/reset_pwd.html");
}
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
re := info.NewRe()
re := info.NewRe();
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderRe(re)
return c.RenderRe(re);
}
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
return c.RenderRe(re)
+7 -8
View File
@@ -1,11 +1,11 @@
package admin
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "strings"
// "strings"
)
var userService *service.UserService
@@ -42,7 +42,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
@@ -50,13 +50,12 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
},
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail": 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 {
@@ -67,7 +66,7 @@ func needValidate(controller, method string) bool {
return true
} else {
// controller不在这里的, 肯定要验证
return true
return true;
}
}
func AuthInterceptor(c *revel.Controller) revel.Result {
@@ -111,7 +110,7 @@ func InitService() {
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService = service.AlbumS
albumService= service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
-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就是这样, 历史原因)
-69
View File
@@ -1,69 +0,0 @@
package api
import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// "strconv"
)
// 用户登录后生成一个token, 将这个token保存到session中
// 以后每次的请求必须带这个token, 并从session中获取userId
// 用户登录/注销/找回密码
type ApiAuth struct {
ApiBaseContrller
}
// 登录
// [ok]
// 成功返回 {Ok: true, Item: token }
// 失败返回 {Ok: false, Msg: ""}
func (c ApiAuth) Login(email, pwd string) revel.Result {
var msg = ""
userInfo, err := authService.Login(email, pwd)
if err == nil {
token := bson.NewObjectId().Hex()
sessionService.SetUserId(token, userInfo.UserId.Hex())
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
} else {
// 登录错误, 则错误次数++
msg = "wrongUsernameOrPassword"
}
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
}
// 注销
// [Ok]
func (c ApiAuth) Logout() revel.Result {
token := c.getToken()
sessionService.Clear(token)
re := info.NewApiRe()
re.Ok = true
return c.RenderJson(re)
}
// 注册
// [Ok]
// 成功后并不返回用户ID, 需要用户重新登录
func (c ApiAuth) Register(email, pwd string) revel.Result {
re := info.NewApiRe()
if !configService.IsOpenRegister() {
re.Msg = "notOpenRegister" // 未开放注册
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re)
}
// 注册
re.Ok, re.Msg = authService.Register(email, pwd, "")
return c.RenderJson(re)
}
-189
View File
@@ -1,189 +0,0 @@
package api
import (
"github.com/revel/revel"
"gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"os"
// "fmt"
"io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
// 公用Controller, 其它Controller继承它
type ApiBaseContrller struct {
controllers.BaseController // 不能用*BaseController
}
// 得到token, 这个token是在AuthInterceptor设到Session中的
func (c ApiBaseContrller) getToken() string {
return c.Session["_token"]
}
// userId
// _userId是在AuthInterceptor设置的
func (c ApiBaseContrller) getUserId() string {
return c.Session["_userId"]
}
// 得到用户信息
func (c ApiBaseContrller) getUserInfo() info.User {
userId := c.Session["_userId"]
if userId == "" {
return info.User{}
}
return userService.GetUserInfo(userId)
}
// 上传附件
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
userId := c.getUserId()
// 判断是否有权限为笔记添加附件
// 如果笔记还没有添加是不是会有问题
/*
if !shareService.HasUpdateNotePerm(noteId, userId) {
return
}
*/
file, handel, err := c.Request.FormFile(name)
if err != nil {
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return
}
// > 5M?
maxFileSize := configService.GetUploadSize("uploadAttachSize")
if maxFileSize <= 0 {
maxFileSize = 1000
}
if float64(len(data)) > maxFileSize*float64(1024*1024) {
msg = "fileIsTooLarge"
return
}
// 生成上传路径
newGuid := NewGuid()
// filePath := "files/" + Digest3(userId) + "/" + userId + "/" + Digest2(newGuid) + "/attachs"
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)
}
-154
View File
@@ -1,154 +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"
"time"
// "github.com/leanote/leanote/app/types"
"io/ioutil"
// "fmt"
// "math"
"os"
// "path"
// "strconv"
)
type ApiUser struct {
ApiBaseContrller
}
// 获取用户信息
// [OK]
func (c ApiUser) Info() revel.Result {
re := info.NewApiRe()
userInfo := c.getUserInfo()
if userInfo.UserId == "" {
return c.RenderJson(re)
}
apiUser := info.ApiUser{
UserId: userInfo.UserId.Hex(),
Username: userInfo.Username,
Email: userInfo.Email,
Logo: userInfo.Logo,
Verified: userInfo.Verified,
}
return c.RenderJson(apiUser)
}
// 修改用户名
// [OK]
func (c ApiUser) UpdateUsername(username string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
return c.RenderJson(re)
}
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
return c.RenderJson(re)
}
// 修改密码
// [OK]
func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
re := info.NewApiRe()
if c.GetUsername() == "demo" {
re.Msg = "cannotUpdateDemo"
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
return c.RenderJson(re)
}
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
return c.RenderJson(re)
}
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
return c.RenderJson(re)
}
// 获得同步状态
// [OK]
func (c ApiUser) GetSyncState() revel.Result {
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
return c.RenderJson(ret)
}
// 头像设置
// 参数file=文件
// 成功返回{Logo: url} 头像新url
// [OK]
func (c ApiUser) UpdateLogo() revel.Result {
ok, msg, url := c.uploadImage()
if ok {
ok = userService.UpdateAvatar(c.getUserId(), url)
return c.RenderJson(map[string]string{"Logo": url})
} else {
re := info.NewApiRe()
re.Msg = msg
return c.RenderJson(re)
}
}
// 上传图片
func (c ApiUser) uploadImage() (ok bool, msg, url string) {
var fileUrlPath = ""
ok = false
file, handel, err := c.Request.FormFile("file")
if err != nil {
return
}
defer file.Close()
// 生成上传路径
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
return
}
// 生成新的文件名
filename := handel.Filename
var ext string
_, ext = SplitFilename(filename)
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
msg = "notImage"
return
}
filename = NewGuid() + ext
data, err := ioutil.ReadAll(file)
if err != nil {
LogJ(err)
return
}
// > 5M?
if len(data) > 5*1024*1024 {
msg = "fileIsTooLarge"
return
}
toPath := dir + "/" + filename
err = ioutil.WriteFile(toPath, data, 0777)
if err != nil {
LogJ(err)
return
}
ok = true
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
return
}
+27
View File
@@ -0,0 +1,27 @@
package api
import (
"github.com/revel/revel"
// "encoding/json"
// "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/info"
// "github.com/leanote/leanote/app/types"
// "io/ioutil"
// "fmt"
// "math"
// "os"
// "path"
// "strconv"
)
type ApiUser struct {
*revel.Controller
}
// 修改用户名, 需要重置session
func (c ApiUser) Info() revel.Result {
Log("APIUser");
return c.RenderTemplate("home/index.html");
// return nil;
}
-144
View File
@@ -1,144 +0,0 @@
package api
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
)
var userService *service.UserService
var noteService *service.NoteService
var trashService *service.TrashService
var notebookService *service.NotebookService
var noteContentHistoryService *service.NoteContentHistoryService
var authService *service.AuthService
var shareService *service.ShareService
var blogService *service.BlogService
var tagService *service.TagService
var pwdService *service.PwdService
var tokenService *service.TokenService
var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var noteImageService *service.NoteImageService
var fileService *service.FileService
var attachService *service.AttachService
var configService *service.ConfigService
var emailService *service.EmailService
var sessionService *service.SessionService
var pageSize = 1000
var defaultSortField = "UpdatedTime"
var leanoteUserId = "admin" // 不能更改
// 状态
const (
S_DEFAULT = iota // 0
S_NOT_LOGIN // 1
S_WRONG_USERNAME_PASSWORD // 2
S_WRONG_CAPTCHA // 3
S_NEED_CAPTCHA // 4
S_NOT_OPEN_REGISTER // 4
)
// 拦截器
// 不需要拦截的url
var commonUrl = map[string]map[string]bool{"ApiAuth": map[string]bool{"Login": true,
"Register": true,
},
// 文件的操作也不用登录, userId会从session中获取
"ApiFile": map[string]bool{"GetImage": true,
"GetAttach": true,
"GetAllAttachs": true,
},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
// 在commonUrl里
if _, ok2 := v[method]; ok2 {
return false
}
return true
} else {
// controller不在这里的, 肯定要验证
return true
}
}
// 这里得到token, 若不是login, logout等公用操作, 必须验证是否已登录
func AuthInterceptor(c *revel.Controller) revel.Result {
// 得到token /api/user/info?userId=xxx&token=xxxxx
token := c.Params.Values.Get("token")
noToken := false
if token == "" {
// 若无, 则取sessionId
token = c.Session.Id()
noToken = true
}
c.Session["_token"] = token
// 全部变成首字大写
var controller = strings.Title(c.Name)
var method = strings.Title(c.MethodName)
// 验证是否已登录
// 通过sessionService判断该token下是否有userId, 并返回userId
userId := sessionService.GetUserId(token)
if noToken && userId == "" {
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
// 客户端
userId, _ = c.Session["UserId"]
}
c.Session["_userId"] = userId
// 是否需要验证?
if !needValidate(controller, method) {
return nil
}
if userId != "" {
return nil // 已登录
}
// 没有登录, 返回错误的信息, 需要登录
re := info.NewApiRe()
re.Msg = "NOTLOGIN"
return c.RenderJson(re)
}
func init() {
// interceptors
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiFile{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNote{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiTag{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNotebook{})
}
// 最外层init.go调用
// 获取service, 单例
func InitService() {
notebookService = service.NotebookS
noteService = service.NoteS
noteContentHistoryService = service.NoteContentHistoryS
trashService = service.TrashS
shareService = service.ShareS
userService = service.UserS
tagService = service.TagS
blogService = service.BlogS
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService = service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
authService = service.AuthS
configService = service.ConfigS
emailService = service.EmailS
sessionService = service.SessionS
}
+6 -6
View File
@@ -1,10 +1,10 @@
package controllers
import (
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/lea/blog"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"strings"
)
@@ -48,7 +48,8 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"FindPasswordUpdate": true,
"Suggestion": true,
},
"Note": map[string]bool{"ToPdf": true},
"Note": map[string]bool{"ToImage": true},
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
@@ -68,7 +69,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
},
"Oauth": map[string]bool{"GithubCallback": true},
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
"Attach": map[string]bool{"Download": true /*, "DownloadAll": true*/},
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
}
func needValidate(controller, method string) bool {
@@ -146,10 +147,9 @@ func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Album{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
revel.OnAppStart(func() {
+13 -13
View File
@@ -1,15 +1,15 @@
package member
import (
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
"github.com/leanote/leanote/app/controllers"
// "github.com/revel/revel"
// "gopkg.in/mgo.v2/bson"
// "encoding/json"
. "github.com/leanote/leanote/app/lea"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"github.com/leanote/leanote/app/controllers"
// "io/ioutil"
// "fmt"
// "math"
// "strconv"
"strings"
)
@@ -20,23 +20,23 @@ type MemberBaseController struct {
// 得到sorterField 和 isAsc
// okSorter = ['email', 'username']
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
sorter := ""
c.Params.Bind(&sorter, "sorter")
if sorter == "" {
return sorterField, isAsc
return sorterField, isAsc;
}
// sorter形式 email-up, email-down
s2 := strings.Split(sorter, "-")
if len(s2) != 2 {
return sorterField, isAsc
return sorterField, isAsc;
}
// 必须是可用的sorter
if okSorter != nil && len(okSorter) > 0 {
if !InArray(okSorter, s2[0]) {
return sorterField, isAsc
return sorterField, isAsc;
}
}
@@ -47,7 +47,7 @@ func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter
isAsc = false
}
c.RenderArgs["sorter"] = sorter
return sorterField, isAsc
return sorterField, isAsc;
}
func (c MemberBaseController) updateConfig(keys []string) {
+15 -17
View File
@@ -74,7 +74,7 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
userInfo := userService.GetUserInfo(userId)
c.RenderArgs["userInfo"] = userInfo
c.RenderArgs["title"] = c.Message("Posts")
c.RenderArgs["title"] = "Posts"
pageNumber := c.GetPage()
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
@@ -85,8 +85,6 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
c.RenderArgs["userAndBlog"] = userAndBlog
c.common()
return c.RenderTemplate("member/blog/list.html")
}
@@ -99,8 +97,7 @@ func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
// 修改笔记的urlTitle
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Update Post Abstract")
c.RenderArgs["title"] = "Update Post Abstract"
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
if !note.Note.IsBlog {
return c.E404()
@@ -110,6 +107,7 @@ func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
return c.RenderTemplate("member/blog/update_abstract.html")
}
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
re := info.NewRe()
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
return c.RenderJson(re)
@@ -118,24 +116,24 @@ func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string)
// 基本信息设置
func (c MemberBlog) Base() revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Blog Base Info")
c.RenderArgs["title"] = "Blog Base Info"
return c.RenderTemplate("member/blog/base.html")
}
func (c MemberBlog) Comment() revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Comment")
c.RenderArgs["title"] = "Comment"
return c.RenderTemplate("member/blog/comment.html")
}
func (c MemberBlog) Paging() revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Paging")
c.RenderArgs["title"] = "Paging"
return c.RenderTemplate("member/blog/paging.html")
}
func (c MemberBlog) Cate() revel.Result {
userBlog := c.common()
c.RenderArgs["title"] = c.Message("Category")
c.RenderArgs["title"] = "Cate"
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
notebooksMap := map[string]info.Notebook{}
@@ -192,10 +190,10 @@ func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.R
}
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Add Single")
c.RenderArgs["title"] = "Add Single"
c.RenderArgs["singleId"] = singleId
if singleId != "" {
c.RenderArgs["title"] = c.Message("Update Single")
c.RenderArgs["title"] = "Update Single"
c.RenderArgs["single"] = blogService.GetSingle(singleId)
}
return c.RenderTemplate("member/blog/add_single.html")
@@ -221,7 +219,7 @@ func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result
func (c MemberBlog) Single() revel.Result {
c.common()
c.RenderArgs["title"] = c.Message("Single")
c.RenderArgs["title"] = "Cate"
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
return c.RenderTemplate("member/blog/single.html")
@@ -236,7 +234,7 @@ func (c MemberBlog) Theme() revel.Result {
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
c.RenderArgs["title"] = c.Message("Theme")
c.RenderArgs["title"] = "Theme"
return c.RenderTemplate("member/blog/theme.html")
}
@@ -253,7 +251,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
}
c.common()
c.RenderArgs["title"] = c.Message("Update Theme")
c.RenderArgs["title"] = "Upate Theme"
c.RenderArgs["isNew"] = isNew
// 先复制之
@@ -445,8 +443,8 @@ func (c MemberBlog) ImportTheme() revel.Result {
if err != nil {
re.Msg = fmt.Sprintf("%v", err)
return c.RenderJson(re)
}
}
defer file.Close()
// 生成上传路径
userId := c.GetUserId()
@@ -462,7 +460,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
var ext string
_, ext = SplitFilename(filename)
if ext != ".zip" {
re.Msg = "Please upload zip file"
re.Msg = "请上传zip文件"
return c.RenderJson(re)
}
@@ -474,7 +472,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
// > 10M?
if len(data) > 10*1024*1024 {
re.Msg = "File is big than 10M"
re.Msg = "文件大于10M"
return c.RenderJson(re)
}
@@ -1,8 +1,8 @@
package member
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
)
// 分组管理
@@ -14,9 +14,9 @@ type MemberGroup struct {
func (c MemberGroup) Index() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = c.Message("My Group")
c.RenderArgs["title"] = "My Group"
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
return c.RenderTemplate("member/group/index.html")
return c.RenderTemplate("member/group/index.html");
}
// 添加分组
@@ -13,14 +13,14 @@ type MemberIndex struct {
// admin 主页
func (c MemberIndex) Index() revel.Result {
c.SetUserInfo()
c.RenderArgs["title"] = c.Message("Leanote Member Center")
c.RenderArgs["title"] = "Leanote Member Center"
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
c.SetLocale()
return c.RenderTemplate("member/index.html")
return c.RenderTemplate("member/index.html");
}
// 模板
@@ -33,5 +33,5 @@ func (c MemberIndex) T(t string) revel.Result {
}
func (c MemberIndex) GetView(view string) revel.Result {
return c.RenderTemplate("admin/" + view)
return c.RenderTemplate("admin/" + view);
}
+14 -8
View File
@@ -13,28 +13,34 @@ type MemberUser struct {
func (c MemberUser) Username() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = c.Message("Username")
return c.RenderTemplate("member/user/username.html")
c.RenderArgs["title"] = "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")
c.RenderArgs["title"] = "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")
c.RenderArgs["title"] = "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["title"] = "Avatar"
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
return c.RenderTemplate("member/user/avatar.html")
return c.RenderTemplate("member/user/avatar.html");
}
func (c MemberUser) AddAccount() revel.Result {
c.SetUserInfo()
c.SetLocale()
c.RenderArgs["title"] = "Add Account"
return c.RenderTemplate("member/user/add_account.html");
}
+7 -8
View File
@@ -1,11 +1,11 @@
package member
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
// "strings"
// "strings"
)
var userService *service.UserService
@@ -44,7 +44,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"FindPassword2": true,
"FindPasswordUpdate": true,
"Suggestion": true,
},
},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,
@@ -52,13 +52,12 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
},
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail": 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 {
@@ -69,7 +68,7 @@ func needValidate(controller, method string) bool {
return true
} else {
// controller不在这里的, 肯定要验证
return true
return true;
}
}
func AuthInterceptor(c *revel.Controller) revel.Result {
@@ -114,7 +113,7 @@ func InitService() {
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
albumService = service.AlbumS
albumService= service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
+2
View File
@@ -0,0 +1,2 @@
包括基本信息设置
博客设置
+3 -37
View File
@@ -2,11 +2,10 @@ package db
import (
"fmt"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"strings"
)
// Init mgo and the common DAO
@@ -29,7 +28,7 @@ var Groups *mgo.Collection
var GroupUsers *mgo.Collection
var Tags *mgo.Collection
var NoteTags *mgo.Collection
//var TagNotes *mgo.Collection
var TagCounts *mgo.Collection
var UserBlogs *mgo.Collection
@@ -63,26 +62,10 @@ func Init(url, dbname string) {
config := revel.Config
if url == "" {
url, ok = config.String("db.url")
if !ok {
url, ok = config.String("db.urlEnv")
if ok {
Log("get db conf from urlEnv: " + url)
}
} else {
Log("get db conf from db.url: " + url)
}
if ok {
// get dbname from urlEnv
urls := strings.Split(url, "/")
dbname = urls[len(urls)-1]
}
}
if dbname == "" {
dbname, _ = config.String("db.dbname")
}
// get db config from host, port, username, password
if !ok {
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
@@ -133,7 +116,7 @@ func Init(url, dbname string) {
// tag
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
@@ -355,20 +338,3 @@ func Err(err error) bool {
}
return true
}
// 检查mognodb是否lost connection
// 每个请求之前都要检查!!
func CheckMongoSessionLost() {
// fmt.Println("检查CheckMongoSessionLostErr")
err := Session.Ping()
if err != nil {
Log("Lost connection to db!")
Session.Refresh()
err = Session.Ping()
if err == nil {
Log("Reconnect to db successful.")
} else {
Log("重连失败!!!! 警告")
}
}
}
+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}
}
-9
View File
@@ -37,7 +37,6 @@ type Post struct {
LikeNum int
IsMarkdown bool
}
// 归档
type ArchiveMonth struct {
Month int
@@ -48,11 +47,3 @@ type Archive struct {
MonthAchives []ArchiveMonth
Posts []*Post
}
type Cate struct {
CateId string
ParentCateId string
Title string
UrlTitle string
Children []*Cate
}
+1 -1
View File
@@ -19,7 +19,7 @@ type UserBlogBase struct {
Logo string `Logo`
Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题
// AboutMe string `AboutMe` // 关于我
// AboutMe string `AboutMe` // 关于我
}
type UserBlogComment struct {
+1 -25
View File
@@ -41,10 +41,7 @@ type Note struct {
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted` // 删除位
SharePass int `SharePass` //分享笔记的密码
}
// 内容
@@ -80,24 +77,3 @@ type NoteContentHistory struct {
UserId bson.ObjectId `bson:"UserId"` // 所属者
Histories []EachHistory `Histories`
}
// 为了NoteController接收参数
// 更新note或content
// 肯定会传userId(谁的), NoteId
// 会传Title, Content, Tags, 一种或几种
type NoteOrContent struct {
NotebookId string
NoteId string
UserId string
Title string
Desc string
ImgSrc string
Tags string
Content string
Abstract string
IsNew bool
IsMarkdown bool
FromUserId string // 为共享而新建
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
}
-4
View File
@@ -19,10 +19,6 @@ type Notebook struct {
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
CreatedTime time.Time `CreatedTime,omitempty`
UpdatedTime time.Time `UpdatedTime,omitempty`
// 2015/1/15, 更新序号
Usn int `Usn` // UpdateSequenceNum
IsDeleted bool `IsDeleted`
}
// 仅仅是为了返回前台
+2 -1
View File
@@ -1,6 +1,7 @@
package info
import ()
import (
)
// controller ajax返回
type Re struct {
+2 -3
View File
@@ -13,9 +13,8 @@ type Session struct {
LoginTimes int `LoginTimes` // 登录错误时间
Captcha string `Captcha` // 验证码
UserId string `UserId` // API时有值UserId
Token string `Token` //attach token
TokenTime time.Time `TokenTime` //token生成时间
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
}
-14
View File
@@ -2,7 +2,6 @@ package info
import (
"gopkg.in/mgo.v2/bson"
"time"
)
// 这里主要是为了统计每个tag的note数目
@@ -22,18 +21,6 @@ type Tag struct {
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` // 谁的
@@ -41,7 +28,6 @@ type TagCount struct {
IsBlog bool `IsBlog` // 是否是博客的tag统计
Count int `Count` // 统计数量
}
/*
type TagsCounts []TagCount
func (this TagsCounts) Len() int {
+1 -1
View File
@@ -14,7 +14,7 @@ type Theme struct {
Version string `Version`
Author string `Author`
AuthorUrl string `AuthorUrl`
Path string `Path` // 文件夹路径, public/upload/54d7620d99c37b030600002c/themes/54d867c799c37b533e000001
Path string `Path` // 文件夹路径
Info map[string]interface{} `Info` // 所有信息
IsActive bool `IsActive` // 是否在用
-11
View File
@@ -52,10 +52,6 @@ type User struct {
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 {
@@ -70,13 +66,6 @@ type UserAccount struct {
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
}
// note主页需要
type UserAndBlogUrl struct {
User
BlogUrl string `BlogUrl`
PostUrl string `PostUrl`
}
// 用户与博客信息结合, 公开
type UserAndBlog struct {
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
+1
View File
@@ -4,6 +4,7 @@ import (
"math"
)
// 分页数据
type Page struct {
CurPage int // 当前页码
+40 -99
View File
@@ -1,26 +1,26 @@
package app
import (
"encoding/json"
"fmt"
"github.com/revel/revel"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/service"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/controllers"
"github.com/leanote/leanote/app/controllers/admin"
"github.com/leanote/leanote/app/controllers/api"
"github.com/leanote/leanote/app/controllers/member"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
_ "github.com/leanote/leanote/app/lea/binder"
"github.com/leanote/leanote/app/lea/i18n"
"github.com/leanote/leanote/app/lea/session"
"github.com/leanote/leanote/app/lea/memcache"
"github.com/leanote/leanote/app/lea/route"
"github.com/leanote/leanote/app/service"
"github.com/revel/revel"
"reflect"
"fmt"
"html/template"
"math"
"net/url"
"reflect"
"strconv"
"strings"
"strconv"
"time"
"encoding/json"
"net/url"
)
func init() {
@@ -32,17 +32,16 @@ func init() {
// AuthFilter, // Invoke the action.
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie.
// revel.SessionFilter, // Restore and write the session cookie.
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
// session.SessionFilter, // leanote session
session.SessionFilter, // leanote session
// session.MSessionFilter, // leanote memcache session
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
// revel.I18nFilter, // Resolve the requested language
i18n.I18nFilter, // Resolve the requested language by leanote
revel.I18nFilter, // Resolve the requested language
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
@@ -51,29 +50,17 @@ func init() {
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
return template.HTML(str)
}
revel.TemplateFuncs["trim"] = func(str string) string {
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
str = strings.Trim(str, "\n")
str = strings.Trim(str, "&nbsp;")
// 以下两个空格不一样
str = strings.Trim(str, " ")
str = strings.Trim(str, " ")
return str
}
revel.TemplateFuncs["add"] = func(i int) string {
i = i + 1
i = i + 1;
return fmt.Sprintf("%v", i)
}
revel.TemplateFuncs["sub"] = func(i int) int {
i = i - 1
i = i - 1;
return i
}
// 增加或减少
revel.TemplateFuncs["incr"] = func(n, i int) int {
n = n + i
n = n + i;
return n
}
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
@@ -148,60 +135,17 @@ func init() {
}
classes += " label-post"
var url = tagPostUrl + "/" + tag
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
if i != lenTags-1 {
var url = tagPostUrl + "/" + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
revel.TemplateFuncs["blogTagsForExport"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
tagStr := ""
lenTags := len(tags)
for i, tag := range tags {
str := tag
var classes = "label"
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
classes += " label-" + tag
} else {
classes += " label-default"
}
classes += " label-post"
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>"
if i != lenTags-1 {
tagStr += " "
}
}
return template.HTML(tagStr)
}
revel.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
if !ok {
return ""
}
return template.HTML(i18n.Message(str, message, args...))
}
// 不用revel的msg
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
str := i18n.Message(locale, key)
if strings.HasPrefix(str, "???") {
str = key
}
return template.HTML(str)
}
// lea++
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, typeStr string) template.HTML {
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
if tags == nil || len(tags) == 0 {
return ""
}
@@ -210,12 +154,10 @@ func init() {
lenTags := len(tags)
tagPostUrl := "http://lea.leanote.com/"
if typeStr == "recommend" {
tagPostUrl += "?tag="
} else if typeStr == "latest" {
tagPostUrl += "latest?tag="
if isRecommend {
tagPostUrl += "?tag=";
} else {
tagPostUrl += "subscription?tag="
tagPostUrl += "latest?tag=";
}
for i, tag := range tags {
@@ -230,9 +172,9 @@ func init() {
classes += " label-default"
}
classes += " label-post"
var url = tagPostUrl + tag
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
if i != lenTags-1 {
var url = tagPostUrl + url.QueryEscape(tag)
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
if i != lenTags - 1 {
tagStr += " "
}
}
@@ -265,12 +207,12 @@ func init() {
return ""
}
// str连接
revel.TemplateFuncs["urlConcat"] = func(url string, v ...interface{}) string {
revel.TemplateFuncs["urlConcat"] = func(url string, v... interface{}) string {
html := ""
for i := 0; i < len(v); i = i + 2 {
item := v[i]
if i+1 == len(v) {
break
break;
}
value := v[i+1]
if item != nil && value != nil {
@@ -327,23 +269,23 @@ func init() {
if sorterI != nil {
sorter, _ = sorterI.(string)
}
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\""
html += " class=\"th-sortable "
if sorter == sorterField+"-up" {
html += "th-sort-up\""
} else if sorter == sorterField+"-down" {
html += "th-sort-down"
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"";
html += " class=\"th-sortable ";
if sorter == sorterField + "-up" {
html += "th-sort-up\"";
} else if(sorter == sorterField + "-down") {
html += "th-sort-down";
}
html += "\""
html += "\"";
return template.HTMLAttr(html)
}
// pagination
revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML {
if count == 0 {
return ""
return "";
}
totalPage := int(math.Ceil(float64(count) / float64(pageSize)))
totalPage := int(math.Ceil(float64(count)/float64(pageSize)))
preClass := ""
prePage := page - 1
@@ -424,13 +366,12 @@ func init() {
// email配置
InitEmail()
InitVd()
// memcache.InitMemcache() // session服务
memcache.InitMemcache() // session服务
// 其它service
service.InitService()
controllers.InitService()
admin.InitService()
member.InitService()
service.ConfigS.InitGlobalConfigs()
api.InitService()
})
});
}
+3 -11
View File
@@ -2,20 +2,12 @@ package lea
import (
"encoding/json"
"fmt"
"github.com/revel/revel"
"fmt"
)
func Log(i ...interface{}) {
revel.INFO.Println(i...)
}
func LogW(i ...interface{}) {
revel.WARN.Println(i...)
}
func Log1(key, i interface{}) {
revel.INFO.Println(key, i)
func Log(i interface{}) {
revel.INFO.Println(i)
}
func LogJ(i interface{}) {
+6 -8
View File
@@ -1,11 +1,10 @@
package lea
import (
"github.com/revel/revel"
"net/smtp"
"strings"
"github.com/revel/revel"
)
// 发送邮件
var host = "smtp.ym.163.com"
var port = "25"
@@ -13,7 +12,7 @@ var username = "noreply@leanote.com"
var password = "---"
func InitEmail() {
config := revel.Config
config := revel.Config;
host, _ = config.String("email.host")
port, _ = config.String("email.port")
username, _ = config.String("email.username")
@@ -57,7 +56,6 @@ var bodyTpl = `
</body>
</html>
`
func SendEmailOld(to, subject, body string) bool {
hp := strings.Split(host, ":")
auth := smtp.PlainAuth("", username, password, hp[0])
@@ -66,15 +64,15 @@ func SendEmailOld(to, subject, body string) bool {
mailtype := "html"
if mailtype == "html" {
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
} else {
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
} else{
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
}
//body = strings.Replace(bodyTpl, "$body", body, 1)
//body = strings.Replace(body, "$title", title, 1)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
send_to := strings.Split(to, ";")
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
@@ -87,5 +85,5 @@ func SendEmailOld(to, subject, body string) bool {
func SendToLeanoteOld(subject, title, body string) {
to := "leanote@leanote.com"
SendEmailOld(to, subject, body)
SendEmailOld(to, subject, body);
}
+2 -10
View File
@@ -56,14 +56,6 @@ func ClearDir(dir string) bool {
return true
}
func MkdirAll(dir string) bool {
err := os.MkdirAll(dir, 0777)
if err != nil {
return false
}
return true
}
// list dir's all file, return filenames
func ListDir(dir string) []string {
f, err := os.Open(dir)
@@ -116,13 +108,13 @@ func CopyDir(source string, dest string) (err error) {
// create sub-directories - recursively
err = CopyDir(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
// fmt.Println(err)
}
} else {
// perform copy
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
if err != nil {
// fmt.Println(err)
// fmt.Println(err)
}
}
}
-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)
}
+28 -180
View File
@@ -1,19 +1,16 @@
package lea
import (
"bytes"
"fmt"
"regexp"
"crypto/md5"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/PuerkitoBio/goquery"
"gopkg.in/mgo.v2/bson"
"io"
math_rand "math/rand"
"regexp"
"strings"
"gopkg.in/mgo.v2/bson"
"time"
math_rand "math/rand"
)
// 字符串
@@ -25,22 +22,6 @@ func Md5(s string) string {
return hex.EncodeToString(h.Sum(nil))
}
// 3位数的转换, 为了用bson.id -> 3位数
func Digest3(str string) string {
var b rune = 0
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b%1000)
}
func Digest2(str string) string {
var b rune = 0
for _, k := range str {
b += k
}
return fmt.Sprintf("%d", b%100)
}
// Guid
func NewGuid() string {
b := make([]byte, 48)
@@ -141,49 +122,39 @@ func ReplaceAll(oldStr, pattern, newStr string) string {
return string(s)
}
// 获取纯文本
func SubStringHTMLToRaw(param string, length int) string {
if param == "" {
return param
}
func SubStringHTML(param string, length int, end string) string {
// 先取出<pre></pre>占位..
result := ""
// 1
n := 0
var temp rune // 中文问题, 用rune来解决
isCode := false //是不是HTML代码
isHTML := false //是不是HTML特殊字符,如&nbsp;
rStr := []rune(param)
lenStr := len(rStr)
isCode := false
resultRune := make([]rune, length)
// s := ""
for i := 0; i < lenStr; i++ {
for i := 0; i < len(rStr); i++ {
temp = rStr[i]
if temp == '<' {
isCode = true
continue
} else if temp == '>' {
} else if temp == '&' {
isHTML = true
} else if temp == '>' && isCode {
n = n - 1
isCode = false
resultRune[n] = ' '
n++
if n >= length {
break
} else if temp == ';' && isHTML {
isHTML = false
}
continue
if !isCode && !isHTML {
n = n + 1
}
if !isCode {
resultRune[n] = temp
// s += string(temp)
n++
result += string(temp)
if n >= length {
break
}
}
}
result := string(resultRune[0:n])
return strings.Trim(result, " ")
}
result += end
// 自带方法补全html
func fixHtml(result string) string {
// 取出所有标签
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
@@ -198,7 +169,7 @@ func fixHtml(result string) string {
p, _ := regexp.Compile("<(/?[a-zA-Z]+)[^<>]*>") // 得到所有的<div>, </div>...
strs := p.FindAllString(tempResult, -1)
// fmt.Println(strs)
// fmt.Println(strs)
stack := make([]string, len(strs))
stackP := -1
for _, each := range strs {
@@ -225,72 +196,6 @@ func fixHtml(result string) string {
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) {
if pwd == "" {
@@ -305,16 +210,16 @@ func IsGoodPwd(pwd string) (bool, string) {
// 是否是email
func IsEmail(email string) bool {
if email == "" {
return false
return false;
}
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.|\-]?)*[_a-z\-A-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-zA-Z0-9\-]+\.[0-9a-zA-Z]{2,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
}
// 是否只包含数字, 字母 -, _
func IsUsername(username string) bool {
if username == "" {
return false
return false;
}
ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username)
return !ok
@@ -351,7 +256,7 @@ func RandomPwd(num int) string {
chars[j] = byte(i)
j++
}
j--
j--;
str := ""
math_rand.Seed(time.Now().UnixNano())
@@ -374,60 +279,3 @@ func InArray(arr []string, str string) bool {
}
return false
}
// 将名称的特殊字符去掉
func FixFilename(filename string) string {
if filename != "" {
// 把特殊字段给替换掉
// str := `life "%&()+,/:;<>=?@\|`
// . == \\.
// $ === \\$
reg, _ := regexp.Compile("\\.|/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
filename = reg.ReplaceAllString(filename, "-")
filename = strings.Trim(filename, "-") // 左右单独的-去掉
// 把空格替换成-
// filename = strings.Replace(filename, " ", "-", -1)
for strings.Index(filename, "--") >= 0 { // 防止出现连续的--
filename = strings.Replace(filename, "--", "-", -1)
}
return filename
}
return filename
}
// 是否是合法的时间
// 不是, 0001-01-01T00:00:00Z, 且比今天小
func IsValidTime(t time.Time) bool {
if t.Year() > 20 {
now := time.Now()
Log("------")
Log(t)
Log(now)
if t.Before(now) {
return true
}
}
return false
}
// url传过来的时间没有时区信息, 转到本地时间
func ToLocalTime(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, time.Local)
}
// 修复传过来的时间, 如果比今天大, 则设为现在
func FixUrlTime(t time.Time) time.Time {
localTime := ToLocalTime(t)
if IsValidTime(localTime) {
return localTime
}
return time.Now()
}
// 得到用户的随机文件路径 3位/userId/2位
func GetRandomFilePath(userId, uuid string) string {
if uuid == "" {
uuid = NewGuid()
}
return Digest3(userId) + "/" + userId + "/" + Digest2(uuid)
}
+11 -11
View File
@@ -2,8 +2,8 @@ package lea
import (
"encoding/json"
"regexp"
"strconv"
"regexp"
)
// 验证
@@ -38,15 +38,15 @@ var rulesStr = `{
`
var rulesMap map[string][]map[string]string
var rules = map[string]func(string, map[string]string) (bool, string){
"required": func(value string, rule map[string]string) (ok bool, msg string) {
var rules = map[string]func(string, map[string]string)(bool, string) {
"required": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
ok = true
return
},
"minLength": func(value string, rule map[string]string) (ok bool, msg string) {
"minLength": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
@@ -55,7 +55,7 @@ var rules = map[string]func(string, map[string]string) (bool, string){
ok = len(value) >= dataI
return
},
"min": func(value string, rule map[string]string) (ok bool, msg string) {
"min": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
@@ -66,7 +66,7 @@ var rules = map[string]func(string, map[string]string) (bool, string){
return
},
"sortField": func(value string, rule map[string]string) (ok bool, msg string) {
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
@@ -75,21 +75,21 @@ var rules = map[string]func(string, map[string]string) (bool, string){
return
},
"password": func(value string, rule map[string]string) (ok bool, msg string) {
"password": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
ok = len(value) >= 6
return
},
"email": func(value string, rule map[string]string) (ok bool, msg string) {
"email": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
ok = IsEmail(value)
return
},
"noSpecialChars": func(value string, rule map[string]string) (ok bool, msg string) {
"noSpecialChars": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
return
}
@@ -98,7 +98,7 @@ var rules = map[string]func(string, map[string]string) (bool, string){
},
// www.baidu.com
//
"domain": func(value string, rule map[string]string) (ok bool, msg string) {
"domain": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
ok = true
return // 可为空
@@ -112,7 +112,7 @@ var rules = map[string]func(string, map[string]string) (bool, string){
return
},
// abcd
"subDomain": func(value string, rule map[string]string) (ok bool, msg string) {
"subDomain": func(value string, rule map[string]string)(ok bool, msg string) {
if value == "" {
ok = true
return // 可为空
+14 -14
View File
@@ -28,7 +28,7 @@ func main() {
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
os.RemoveAll("/home/ty4z2008/tar")
*/
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
fmt.Println("ok")
}
@@ -67,11 +67,11 @@ func TarGz(srcDirPath string, destFilePath string) (ok bool) {
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from 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() + "...")
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
tarGzFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
@@ -102,11 +102,11 @@ func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
// fmt.Printf("Adding path...%s\n", curPath)
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
// fmt.Printf("Adding file...%s\n", curPath)
}
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
@@ -116,18 +116,18 @@ func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
// Deal with files
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
if fi.IsDir() {
// fmt.Println("??")
// 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)
// fmt.Println(hdr.Name)
hdr.Typeflag = tar.TypeDir
// hdr.Size = 0
// hdr.Size = 0
//hdr.Mode = 0755 | c_ISDIR
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
// Write hander
err := tw.WriteHeader(hdr)
@@ -145,7 +145,7 @@ func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
// Create tar header
hdr := new(tar.Header)
hdr.Name = recPath
// fmt.Println(hdr.Name)
// fmt.Println(hdr.Name)
hdr.Size = fi.Size()
hdr.Mode = int64(fi.Mode())
hdr.ModTime = fi.ModTime()
@@ -167,7 +167,7 @@ func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
// 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 + "...")
// fmt.Println("UnTarGzing " + srcFilePath + "...")
// Create destination directory
os.Mkdir(destDirPath, os.ModePerm)
@@ -194,7 +194,7 @@ func UnTarGz(srcFilePath string, destDirPath string) {
break
}
//handleError(err)
// fmt.Println("UnTarGzing file..." + hdr.Name)
// fmt.Println("UnTarGzing file..." + hdr.Name)
// Check if it is diretory or file
if hdr.Typeflag != tar.TypeDir {
// Get files from archive
@@ -211,7 +211,7 @@ func UnTarGz(srcFilePath string, destDirPath string) {
}
}
}
// fmt.Println("Well done!")
// fmt.Println("Well done!")
}
// Copyfile
+15 -22
View File
@@ -3,11 +3,10 @@ package archive
import (
"archive/zip"
"fmt"
"strings"
"io"
"os"
"path"
"strings"
"github.com/leanote/leanote/app/lea"
)
// main functions shows how to TarGz a directory/file and
@@ -44,11 +43,11 @@ func Zip(srcDirPath string, destFilePath string) (ok bool) {
}
if fi.IsDir() {
// handle source directory
// fmt.Println("Cerating tar.gz from 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() + "...")
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
zipFile(srcDirPath, fi.Name(), tw, fi)
}
ok = true
@@ -79,11 +78,11 @@ func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
if fi.IsDir() {
// Directory
// (Directory won't add unitl all subfiles are added)
// fmt.Printf("Adding path...%s\n", curPath)
// fmt.Printf("Adding path...%s\n", curPath)
zipDir(curPath, recPath+"/"+fi.Name(), tw)
} else {
// File
// fmt.Printf("Adding file...%s\n", curPath)
// fmt.Printf("Adding file...%s\n", curPath)
}
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
@@ -93,7 +92,7 @@ func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
// Deal with files
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
if fi.IsDir() {
// fmt.Println("??")
// fmt.Println("??")
// Create tar header
/*
fh, err := zip.FileInfoHeader(fi)
@@ -139,30 +138,24 @@ func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
}()
os.Mkdir(destDirPath, os.ModePerm)
r, err := zip.OpenReader(srcFilePath)
r, err := zip.OpenReader(srcFilePath);
if err != nil {
panic(err)
}
defer r.Close()
defer r.Close();
for _, f := range r.File {
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
rc, err := f.Open()
if err != nil {
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
rc, err := f.Open();
if err!=nil {
panic(err)
}
// 包含恶意目录
if strings.Contains(f.Name, "../") {
lea.LogW("恶意文件", f.Name);
continue
}
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
paths := strings.Split(f.Name, "/")
prePath := ""
filename := ""
l := len(paths)
// fmt.Println(l)
// fmt.Println(l)
if l > 1 {
// 去掉第1个文件夹
if l == 2 {
@@ -174,16 +167,16 @@ func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
} else {
filename = f.Name
}
// fmt.Println(prePath)
// fmt.Println(prePath)
// 相对于目标文件件下的路径
destPath := destDirPath + "/" + filename
if prePath != "" {
os.MkdirAll(destDirPath+"/"+prePath, os.ModePerm)
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
destPath = destDirPath + "/" + prePath + "/" + filename
}
// Write data to file
// fmt.Println(destPath)
// fmt.Println(destPath)
fw, _ := os.Create(destPath)
if err != nil {
panic(err)
+7 -43
View File
@@ -1,9 +1,9 @@
package binder
import (
"github.com/leanote/leanote/app/info"
"github.com/revel/revel"
// "github.com/leanote/leanote/app/controllers/api"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/controllers"
"fmt"
"reflect"
"strings"
@@ -53,36 +53,16 @@ func nextKey(key string) string {
}
return key[:fieldLen]
}
var leanoteStructBinder = revel.Binder{
// name == "noteOrContent"
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取
result := reflect.New(typ).Elem()
fieldValues := make(map[string]reflect.Value)
// fmt.Println(name)
// 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
for key, _ := range params.Values {
// 这里, 如果没有点, 默认就是a.
// life
// fmt.Println("key:" + key); // files[0][LocalFileId]
// fmt.Println("name:" + name); // files[0][LocalFileId]
var suffix string
var noPrefix = false
if nameIsSlice && strings.HasPrefix(key, name) {
suffix = key[len(name)+1 : len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
} else if !strings.HasPrefix(key, name+".") {
if !strings.HasPrefix(key, name + ".") {
noPrefix = true
suffix = key
// continue
@@ -91,18 +71,13 @@ var leanoteStructBinder = revel.Binder{
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
suffix = key[len(name)+1:]
}
// fmt.Println(suffix);
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
// fmt.Println(fieldName);
fieldLen := len(fieldName)
if _, ok := fieldValues[fieldName]; !ok {
// Time to bind this field. Get it and make sure we can set it.
fieldName = strings.Title(fieldName) // 传过来title, 但struct是Title
// fmt.Println("xx: " + fieldName)
fieldValue := result.FieldByName(fieldName)
// fmt.Println(fieldValue)
if !fieldValue.IsValid() {
continue
}
@@ -111,17 +86,9 @@ var leanoteStructBinder = revel.Binder{
}
var boundVal reflect.Value
// 没有name前缀
if noPrefix {
// life
// fmt.Println("<<")
// fmt.Println(strings.Title(key[:fieldLen]));
if(noPrefix) {
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
} 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())
}
fieldValue.Set(boundVal)
@@ -149,8 +116,5 @@ func init() {
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.UserAccount{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteOrContent{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
}
+12 -8
View File
@@ -6,8 +6,8 @@ import (
"html/template"
"io/ioutil"
// "os"
"bytes"
"fmt"
"bytes"
"io"
"net/http"
"regexp"
@@ -139,7 +139,7 @@ func Init() {
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
fileStr := string(fileBytes)
path := "blog/" + path
// path := path
// path := path
BlogTplObject.PathContent[path] = fileStr
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
}
@@ -157,7 +157,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
// 都不会为空的
if basePath == "" {
path := "blog/" + name
// path := name
// path := name
t := BlogTplObject.Template.Lookup(path)
r = &RenderTemplateResult{
Template: t,
@@ -179,9 +179,11 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
// 将该basePath下的所有文件提出
files := ListDir(basePath)
Log(basePath)
LogJ(files);
for _, t := range files {
if !strings.Contains(t, ".html") {
continue
continue;
}
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
if err != nil {
@@ -211,8 +213,9 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
return r
}
////////////////////
//
// 错误显示
type ErrorResult struct {
RenderArgs map[string]interface{}
@@ -238,7 +241,7 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
var err error
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
err = nil
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
// This func shows a plaintext error message, in case the template rendering
// doesn't work.
@@ -287,12 +290,13 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
r.RenderArgs["Router"] = revel.MainRouter
// 不是preview就不要显示错误了
if r.IsPreview {
LogJ(revelError)
// 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)
}
// }
}
+3 -5
View File
@@ -1,16 +1,15 @@
package captcha
import (
crand "crypto/rand"
"image"
"image/color"
"image/png"
"io"
"math/rand"
"strconv"
crand "crypto/rand"
"time"
"strconv"
)
const (
stdWidth = 100
stdHeight = 40
@@ -133,8 +132,7 @@ type Image struct {
height int //a digit height
dotsize int
}
func init() {
func init(){
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 {
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)
}
+17 -18
View File
@@ -1,13 +1,12 @@
package netutil
import (
"os"
"strings"
// "path/filepath"
. "github.com/leanote/leanote/app/lea"
"io/ioutil"
"os"
// "path/filepath"
"net"
"net/http"
"io/ioutil"
. "github.com/leanote/leanote/app/lea"
)
// net的util
@@ -17,11 +16,11 @@ import (
// 返回文件的完整目录
func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) {
if url == "" {
return
return;
}
content, err := GetContent(url)
if err != nil {
return
return;
}
length = int64(len(content))
@@ -32,7 +31,7 @@ func WriteUrl(url string, toPath string) (length int64, newFilename, path string
if toPath == "" {
toPath = "/tmp"
}
// dir := filepath.Dir(toPath)
// dir := filepath.Dir(toPath)
newFilename = NewGuid() + ext
fullPath := toPath + "/" + newFilename
@@ -54,7 +53,7 @@ func GetContent(url string) (content []byte, err error) {
var resp *http.Response
resp, err = http.Get(url)
Log(err)
if resp != nil && resp.Body != nil {
if(resp != nil && resp.Body != nil) {
defer resp.Body.Close()
} else {
}
@@ -64,33 +63,33 @@ func GetContent(url string) (content []byte, err error) {
var buf []byte
buf, err = ioutil.ReadAll(resp.Body)
if err != nil {
if(err != nil) {
Log(err)
return
}
content = buf
content = buf;
err = nil
return
}
// 将url ?, #后面的字符串去掉
func trimQueryParams(url string) string {
pos := strings.Index(url, "?")
pos := strings.Index(url, "?");
if pos != -1 {
url = Substr(url, 0, pos)
url = Substr(url, 0, pos);
}
pos = strings.Index(url, "#")
pos = strings.Index(url, "#");
if pos != -1 {
url = Substr(url, 0, pos)
url = Substr(url, 0, pos);
}
pos = strings.Index(url, "!")
pos = strings.Index(url, "!");
if pos != -1 {
url = Substr(url, 0, pos)
url = Substr(url, 0, pos);
}
return url
return url;
}
// 通过domain得到ip
+4 -8
View File
@@ -1,9 +1,9 @@
package route
import (
"github.com/leanote/leanote/app/db"
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
// "github.com/leanote/leanote/app/service"
// . "github.com/leanote/leanote/app/lea"
"net/url"
"strings"
)
@@ -11,7 +11,6 @@ import (
// overwite revel RouterFilter
// /api/user/Info => ApiUser.Info()
var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"}
func RouterFilter(c *revel.Controller, fc []revel.Filter) {
// 补全controller部分
path := c.Request.Request.URL.Path
@@ -43,14 +42,10 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
}
*/
if route.ControllerName != "Static" {
// 检查mongodb 是否lost
db.CheckMongoSessionLost()
// api设置
// leanote.com/api/user/get => ApiUser::Get
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api") {
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
route.ControllerName = "Api" + route.ControllerName
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
// member设置
@@ -85,3 +80,4 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
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}
}
+210
View File
@@ -0,0 +1,210 @@
package session
import (
"github.com/revel/revel"
// . "github.com/leanote/leanote/app/lea"
"crypto/rand"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
// 主要修改revel的cookie, 设置Domain
// 为了使sub domain共享cookie
// cookie.domain = leanote.com
// A signed cookie (and thus limited to 4kb in size).
// Restriction: Keys may not have a colon in them.
type Session map[string]string
const (
SESSION_ID_KEY = "_ID"
TIMESTAMP_KEY = "_TS"
)
// expireAfterDuration is the time to live, in seconds, of a session cookie.
// It may be specified in config as "session.expires". Values greater than 0
// set a persistent cookie with a time to live as specified, and the value 0
// sets a session cookie.
var expireAfterDuration time.Duration
var cookieDomain = "" // life
func init() {
// Set expireAfterDuration, default to 30 days if no value in config
revel.OnAppStart(func() {
var err error
if expiresString, ok := revel.Config.String("session.expires"); !ok {
expireAfterDuration = 30 * 24 * time.Hour
} else if expiresString == "session" {
expireAfterDuration = 0
} else if expireAfterDuration, err = time.ParseDuration(expiresString); err != nil {
panic(fmt.Errorf("session.expires invalid: %s", err))
}
cookieDomain, _ = revel.Config.String("cookie.domain")
})
}
// Id retrieves from the cookie or creates a time-based UUID identifying this
// session.
func (s Session) Id() string {
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
return sessionIdStr
}
buffer := make([]byte, 32)
if _, err := rand.Read(buffer); err != nil {
panic(err)
}
s[SESSION_ID_KEY] = hex.EncodeToString(buffer)
return s[SESSION_ID_KEY]
}
// getExpiration return a time.Time with the session's expiration date.
// If previous session has set to "session", remain it
func (s Session) getExpiration() time.Time {
if expireAfterDuration == 0 || s[TIMESTAMP_KEY] == "session" {
// Expire after closing browser
return time.Time{}
}
return time.Now().Add(expireAfterDuration)
}
// cookie returns an http.Cookie containing the signed session.
func (s Session) cookie() *http.Cookie {
var sessionValue string
ts := s.getExpiration()
s[TIMESTAMP_KEY] = getSessionExpirationCookie(ts)
for key, value := range s {
if strings.ContainsAny(key, ":\x00") {
panic("Session keys may not have colons or null bytes")
}
if strings.Contains(value, "\x00") {
panic("Session values may not have null bytes")
}
sessionValue += "\x00" + key + ":" + value + "\x00"
}
sessionData := url.QueryEscape(sessionValue)
cookie := http.Cookie{
Name: revel.CookiePrefix + "_SESSION",
Value: revel.Sign(sessionData) + "-" + sessionData,
Path: "/",
HttpOnly: revel.CookieHttpOnly,
Secure: revel.CookieSecure,
Expires: ts.UTC(),
}
if cookieDomain != "" {
cookie.Domain = cookieDomain
}
return &cookie
}
// sessionTimeoutExpiredOrMissing returns a boolean of whether the session
// cookie is either not present or present but beyond its time to live; i.e.,
// whether there is not a valid session.
func sessionTimeoutExpiredOrMissing(session Session) bool {
if exp, present := session[TIMESTAMP_KEY]; !present {
return true
} else if exp == "session" {
return false
} else if expInt, _ := strconv.Atoi(exp); int64(expInt) < time.Now().Unix() {
return true
}
return false
}
// getSessionFromCookie returns a Session struct pulled from the signed
// session cookie.
func getSessionFromCookie(cookie *http.Cookie) Session {
session := make(Session)
// Separate the data from the signature.
hyphen := strings.Index(cookie.Value, "-")
if hyphen == -1 || hyphen >= len(cookie.Value)-1 {
return session
}
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
// Verify the signature.
if !revel.Verify(data, sig) {
revel.INFO.Println("Session cookie signature failed")
return session
}
revel.ParseKeyValueCookie(data, func(key, val string) {
session[key] = val
})
if sessionTimeoutExpiredOrMissing(session) {
session = make(Session)
}
return session
}
// SessionFilter is a Revel Filter that retrieves and sets the session cookie.
// Within Revel, it is available as a Session attribute on Controller instances.
// The name of the Session cookie is set as CookiePrefix + "_SESSION".
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
session := restoreSession(c.Request.Request)
// c.Session, 重新生成一个revel.Session给controller!!!
// Log("sessoin--------")
// LogJ(session)
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
c.Session = revelSession
// 生成sessionId
c.Session.Id()
sessionWasEmpty := len(c.Session) == 0
// Make session vars available in templates as {{.session.xyz}}
c.RenderArgs["session"] = c.Session
fc[0](c, fc[1:])
// Store the signed session if it could have changed.
if len(c.Session) > 0 || !sessionWasEmpty {
// 转换成lea.Session
session = Session(c.Session)
c.SetCookie(session.cookie())
}
}
// restoreSession returns either the current session, retrieved from the
// session cookie, or a new session.
func restoreSession(req *http.Request) Session {
cookie, err := req.Cookie(revel.CookiePrefix + "_SESSION")
if err != nil {
return make(Session)
} else {
return getSessionFromCookie(cookie)
}
}
// getSessionExpirationCookie retrieves the cookie's time to live as a
// string of either the number of seconds, for a persistent cookie, or
// "session".
func getSessionExpirationCookie(t time.Time) string {
if t.IsZero() {
return "session"
}
return strconv.FormatInt(t.Unix(), 10)
}
// SetNoExpiration sets session to expire when browser session ends
func (s Session) SetNoExpiration() {
s[TIMESTAMP_KEY] = "session"
}
// SetDefaultExpiration sets session to expire after default duration
func (s Session) SetDefaultExpiration() {
delete(s, TIMESTAMP_KEY)
}
+30 -26
View File
@@ -2,11 +2,10 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"io/ioutil"
"strings"
// "time"
)
/*
@@ -33,7 +32,7 @@ import (
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
var jss = []string{"js/jquery-cookie", "js/bootstrap",
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
"js/object_id"}
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
@@ -54,13 +53,13 @@ func compressJs(filename string) {
to := base + filename + "-min.js"
cmd := exec.Command(cmdPath, source, "-o", to)
_, err := cmd.CombinedOutput()
fmt.Println(source)
fmt.Println(source);
cmdError(err)
}
func combineJs() {
// 生成一个总文件
cmd := exec.Command("rm", base+"js/all.js")
cmd := exec.Command("rm", base + "js/all.js")
_, err := cmd.CombinedOutput()
cmdError(err)
@@ -70,10 +69,10 @@ func combineJs() {
compressJs(js)
// 每个压缩后的文件放入之
cmd2 := exec.Command("/bin/sh", "-c", "cat "+to+" >> "+base+"js/all.js")
cmd2 := exec.Command("/bin/sh", "-c", "cat " + to + " >> " + base + "js/all.js")
_, err := cmd2.CombinedOutput()
cmdError(err)
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> "+base+"js/all.js")
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> " + base + "js/all.js")
_, err = cmd2.CombinedOutput()
cmdError(err)
}
@@ -92,6 +91,7 @@ func dev() {
"notebook.js": "notebook-min.js",
"share.js": "share-min.js",
"tag.js": "tag-min.js",
"main.js": "main-min.js",
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
"editor/editor.js": "editor/editor-min.js",
@@ -107,44 +107,48 @@ func dev() {
for key, value := range m {
content = strings.Replace(content, key, value, -1)
}
// var time = time.Now().Unix() % 1000
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
}
// 压缩js成一块
func tinymce() {
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/bin/sh", "-c", "grunt minify")
cmd.Dir = base + "/tinymce_4.1.9"
fmt.Println("正在build tinymce")
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
// 必须要先删除
cmd2 := exec.Command("/bin/sh", "-c", "rm "+cmd.Dir+"/js/tinymce/tinymce.dev.js")
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
cmd2.CombinedOutput()
cmd2 = exec.Command("/bin/sh", "-c", "rm "+cmd.Dir+"/js/tinymce/tinymce.jquery.dev.js")
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
c, _ := cmd2.CombinedOutput()
fmt.Println(string(c))
c, _ = cmd.CombinedOutput()
fmt.Println(string(c))
}
func main() {
// 压缩tinymce
// tinymce()
tinymce()
dev()
dev();
// 其它零散的需要压缩的js
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
otherJss := []string{"tinymce/tinymce", "js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
"mdeditor/editor/scrollLink",
"mdeditor/editor/editor",
"mdeditor/editor/jquery.waitforimages",
"mdeditor/editor/pagedown/local/Markdown.local.zh",
"mdeditor/editor/pagedown/local/Markdown.local.en",
"mdeditor/editor/pagedown/Markdown.Editor",
"mdeditor/editor/pagedown/Markdown.Sanitizer",
"mdeditor/editor/pagedown/Markdown.Converter",
"mdeditor/editor/Markdown.Extra",
"mdeditor/editor/underscore",
"mdeditor/editor/mathJax",
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
"js/app/editor_drop_paste",
"js/app/attachment_upload",
"js/jquery.ztree.all-3.5",
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
}
+1 -1
View File
@@ -2,7 +2,7 @@ package service
import (
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"time"
+22 -83
View File
@@ -1,46 +1,29 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"time"
"os"
"strings"
"time"
)
type AttachService struct {
}
// add attach
// api调用时, 添加attach之前是没有note的
// fromApi表示是api添加的, updateNote传过来的, 此时不要incNote's usn, 因为updateNote会inc的
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
attach.CreatedTime = time.Now()
ok = db.Insert(db.Attachs, attach)
note := noteService.GetNoteById(attach.NoteId.Hex())
// api调用时, 添加attach之前是没有note的
var userId string
if note.NoteId != "" {
userId = note.UserId.Hex()
} else {
userId = attach.UploadUserId.Hex()
}
if ok {
// 更新笔记的attachs num
this.updateNoteAttachNum(attach.NoteId, 1)
}
if !fromApi {
// 增长note's usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
}
return
}
@@ -63,45 +46,22 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
// list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs
}
// 笔记是否是自己的
note := noteService.GetNoteByIdAndUserId(noteId, userId)
if note.NoteId == "" {
return attachs
}
// TODO 这里, 优化权限控制
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
return attachs
}
// 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 {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
// Delete note to delete attas firstly
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
note := noteService.GetNoteById(noteId)
@@ -119,12 +79,11 @@ func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
}
// delete attach
// 删除附件为什么要incrNoteUsn ? 因为可能没有内容要修改的
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
if attach.AttachId != "" {
if(attach.AttachId != "") {
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
return false, "No Perm"
@@ -135,11 +94,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
attach.Path = strings.TrimLeft(attach.Path, "/")
err := os.Remove(revel.BasePath + "/" + attach.Path)
if err == nil {
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size)
// 修改note Usn
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
return true, "delete file success"
return true, "delete file error"
}
return false, "delete file error"
}
@@ -151,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
// 获取文件路径
// 要判断是否具有权限
// userId是否具有attach的访问权限
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
if attachId == "" {
return
}
@@ -182,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
return
}
//userId为空则是分享笔记的附件
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("attach token is equal!")
return
}
}
}
attach = info.Attach{}
return
}
@@ -203,46 +169,19 @@ func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
newFilename := NewGuid() + ext
dir := "files/" + toUserId + "/attachs"
filePath := dir + "/" + newFilename
err := os.MkdirAll(revel.BasePath+"/"+dir, 0755)
err := os.MkdirAll(revel.BasePath + "/" + dir, 0755)
if err != nil {
return false
}
_, err = CopyFile(revel.BasePath+"/"+attach.Path, revel.BasePath+"/"+filePath)
_, err = CopyFile(revel.BasePath + "/" + attach.Path, revel.BasePath + "/" + filePath)
if err != nil {
return false
}
attach.Name = newFilename
attach.Path = filePath
this.AddAttach(attach, false)
this.AddAttach(attach)
}
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
}
+24 -34
View File
@@ -2,31 +2,26 @@ package service
import (
"gopkg.in/mgo.v2/bson"
// "github.com/leanote/leanote/app/db"
// "github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
// "github.com/revel/revel"
"errors"
"fmt"
. "github.com/leanote/leanote/app/lea"
"strconv"
// "github.com/revel/revel"
"strings"
. "github.com/leanote/leanote/app/lea"
"fmt"
"strconv"
)
// 登录与权限 Login & Register
// 登录与权限
type AuthService struct {
}
// 使用bcrypt认证或者Md5认证
// Use bcrypt (Md5 depreciated)
func (this *AuthService) Login(emailOrUsername, pwd string) (info.User, error) {
// pwd已md5了
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
emailOrUsername = strings.Trim(emailOrUsername, " ")
// 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
// pwd = strings.Trim(pwd, " ")
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
return userInfo
}
// 注册
@@ -45,21 +40,17 @@ func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string)
if userService.IsExistsUser(email) {
return false, "userHasBeenRegistered-" + email
}
passwd := GenPwd(pwd)
if passwd == "" {
return false, "GenerateHash error"
}
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: passwd}
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
if fromUserId != "" && IsObjectId(fromUserId) {
user.FromUserId = bson.ObjectIdHex(fromUserId)
}
LogJ(user)
return this.register(user)
}
func (this *AuthService) register(user info.User) (bool, string) {
if userService.AddUser(user) {
// 添加笔记本, 生活, 学习, 工作
userId := user.UserId.Hex()
notebook := info.Notebook{
Seq: -1,
UserId: user.UserId}
@@ -68,12 +59,14 @@ func (this *AuthService) register(user info.User) (bool, string) {
notebook.Title = title
notebook.NotebookId = objectId
notebook.UserId = user.UserId
notebookService.AddNotebook(notebook)
notebookService.AddNotebook(notebook);
}
email := user.Email
// 添加leanote -> 该用户的共享
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
if registerSharedUserId != "" {
if(registerSharedUserId != "") {
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
@@ -81,23 +74,20 @@ func (this *AuthService) register(user info.User) (bool, string) {
// 添加共享笔记本
for _, notebook := range registerSharedNotebooks {
perm, _ := strconv.Atoi(notebook["perm"])
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId)
shareService.AddShareNotebook(notebook["notebookId"], perm, registerSharedUserId, email);
}
// 添加共享笔记
for _, note := range registerSharedNotes {
perm, _ := strconv.Atoi(note["perm"])
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId)
shareService.AddShareNote(note["noteId"], perm, registerSharedUserId, email);
}
// 复制笔记
for _, noteId := range registerCopyNoteIds {
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex())
// Log(noteId)
// Log("Copy")
// LogJ(note)
noteUpdate := bson.M{"IsBlog": false} // 不要是博客
noteService.UpdateNote(user.UserId.Hex(), note.NoteId.Hex(), noteUpdate, -1)
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
noteUpdate := bson.M{"IsBlog": true}
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
}
}
@@ -105,7 +95,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
// 添加一条userBlog
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
Title: user.Username + " 's Blog",
SubTitle: "Love Leanote!",
SubTitle: "love leanote!",
AboutMe: "Hello, I am (^_^)",
CanComment: true,
})
@@ -123,7 +113,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
username = thirdType + "-" + thirdUsername
i := 1
for {
for ;; {
if !userService.IsExistsUserByUsername(username) {
return
}
+17 -41
View File
@@ -45,9 +45,7 @@ func (this *BlogService) GetBlogByIdAndUrlTitle(userId string, noteIdOrUrlTitle
return this.GetBlog(noteIdOrUrlTitle)
}
note := info.Note{}
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle),
"IsBlog": true,
"IsTrash": false, "IsDeleted": false}, &note)
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle), "IsBlog": true, "IsTrash": false}, &note)
return this.GetBlogItem(note)
}
@@ -58,7 +56,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
}
func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
if note.NoteId == "" || !note.IsBlog {
return info.BlogItem{}
return
}
// 内容
@@ -71,14 +69,9 @@ func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
}
// 得到用户共享的notebooks
// 3/19 博客不是deleted
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
notebooks := []info.Notebook{}
orQ := []bson.M{
bson.M{"IsDeleted": false},
bson.M{"IsDeleted": bson.M{"$exists": false}},
}
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "$or": orQ}, &notebooks)
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}, &notebooks)
return notebooks
}
@@ -133,8 +126,7 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
func (this *BlogService) GetBlogTags(userId string) []info.TagCount {
// 得到所有博客
tagCounts := []info.TagCount{}
// tag不能为空
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "Tag": bson.M{"$ne": ""}}
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}
db.TagCounts.Find(query).Sort("-Count").All(&tagCounts)
return tagCounts
}
@@ -145,7 +137,7 @@ func (this *BlogService) ReCountBlogTags(userId string) bool {
// 得到所有博客
notes := []info.Note{}
userIdO := bson.ObjectIdHex(userId)
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsDeleted": false, "IsBlog": true}
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true}
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, &notes)
db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true})
@@ -187,7 +179,7 @@ Posts: []
*/
func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) []info.Archive {
// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true);
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false, "IsDeleted": false}
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false}
if notebookId != "" {
q["NotebookId"] = bson.ObjectIdHex(notebookId)
}
@@ -295,7 +287,6 @@ func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumb
// 不是trash的
query := bson.M{"UserId": bson.ObjectIdHex(userId),
"IsTrash": false,
"IsDeleted": false,
"IsBlog": true,
"Tags": bson.M{"$all": tags}}
@@ -397,12 +388,10 @@ func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bo
sortFieldR2 = sorterField
}
// 1
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
note := info.Note{}
query := bson.M{"UserId": userIdO,
"IsTrash": false,
"IsDeleted": false,
"IsBlog": true,
"_id": bson.M{"$ne": bson.ObjectIdHex(noteId)},
sorterField: sortFieldT1,
@@ -436,7 +425,7 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
// 不是trash的
query := bson.M{"IsTrash": false, "IsDeleted": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
if tag != "" {
query["Tags"] = bson.M{"$in": []string{tag}}
}
@@ -502,9 +491,6 @@ func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRec
content = noteContent.Abstract
}
*/
if len(note.Tags) == 1 && note.Tags[0] == "" {
note.Tags = nil
}
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
}
pageInfo = info.NewPage(page, pageSize, count, nil)
@@ -518,7 +504,7 @@ func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
// Logo路径问题, 有些有http: 有些没有
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
userBlog.Logo = "/" + userBlog.Logo
userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo
}
if userBlog.SortField == "" {
@@ -673,18 +659,19 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
noteIdO := bson.ObjectIdHex(noteId)
userIdO := bson.ObjectIdHex(userId)
var n int
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
n = 1
// 添加之
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
isLike = true
} else {
// 已点过, 那么删除之
n = -1
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
isLike = false
}
count := db.Count(db.BlogLikes, bson.M{"NoteId": noteIdO})
ok = db.UpdateByQI(db.Notes, bson.M{"_id": noteIdO}, bson.M{"LikeNum": count})
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
return
}
@@ -918,7 +905,7 @@ func (this *BlogService) UpateCateUrlTitle(userId string, cateId, urlTitle strin
"UrlTitle": "",
})
*/
url = GetUrTitle(userId, urlTitle, "notebook", cateId)
url = GetUrTitle(userId, urlTitle, "notebook")
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{
"UrlTitle": url,
})
@@ -934,7 +921,7 @@ func (this *BlogService) UpateBlogUrlTitle(userId string, noteId, urlTitle strin
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
"UrlTitle": "",
})
url = GetUrTitle(userId, urlTitle, "note", noteId)
url = GetUrTitle(userId, urlTitle, "note")
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
"UrlTitle": url,
})
@@ -1035,7 +1022,7 @@ func (this *BlogService) UpdateSingleUrlTitle(userId, singleId, urlTitle string)
"UrlTitle": "",
})
*/
url = GetUrTitle(userId, urlTitle, "single", singleId)
url = GetUrTitle(userId, urlTitle, "single")
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
"UrlTitle": url,
})
@@ -1069,7 +1056,7 @@ func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content stri
UserId: bson.ObjectIdHex(userId),
Title: title,
Content: content,
UrlTitle: GetUrTitle(userId, title, "single", singleId),
UrlTitle: GetUrTitle(userId, title, "single"),
CreatedTime: time.Now(),
}
page.UpdatedTime = page.CreatedTime
@@ -1107,8 +1094,6 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool
// 得到用户的博客url
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
/*
if userBlog != nil {
if userBlog.Domain != "" && configService.AllowCustomDomain() {
return configService.GetUserUrl(userBlog.Domain)
} else if userBlog.SubDomain != "" {
@@ -1117,16 +1102,12 @@ func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string
if username == "" {
username = userBlog.UserId.Hex()
}
}
*/
return configService.GetBlogUrl() + "/" + username
}
// 得到所有url
func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.User) info.BlogUrls {
var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl string
/*
if userBlog.Domain != "" && configService.AllowCustomDomain() { // http://demo.com
// ok
indexUrl = configService.GetUserUrl(userBlog.Domain)
@@ -1147,7 +1128,6 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
tagsUrl = indexUrl + "/tags"
tagPostsUrl = indexUrl + "/tag"
} else {
*/
// ok
blogUrl := configService.GetBlogUrl() // blog.leanote.com
userIdOrEmail := ""
@@ -1166,7 +1146,7 @@ func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.Use
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/username
tagsUrl = blogUrl + "/tags/" + userIdOrEmail
tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/username
// }
}
return info.BlogUrls{
IndexUrl: indexUrl,
@@ -1210,10 +1190,6 @@ func (this *BlogService) FixBlog(blog info.BlogItem) info.Post {
LikeNum: blog.LikeNum,
IsMarkdown: blog.IsMarkdown,
}
if blog2.Tags != nil && len(blog2.Tags) > 0 && blog2.Tags[0] != "" {
} else {
blog2.Tags = nil
}
return blog2
}
+56 -82
View File
@@ -1,17 +1,17 @@
package service
import (
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"github.com/revel/revel"
"time"
"os"
"os/exec"
"strconv"
"fmt"
"strings"
"time"
"strconv"
)
// 配置服务
@@ -27,7 +27,6 @@ type ConfigService struct {
GlobalMapConfigs map[string]map[string]string
GlobalArrMapConfigs map[string][]map[string]string
}
// appStart时 将全局的配置从数据库中得到作为全局
func (this *ConfigService) InitGlobalConfigs() bool {
this.GlobalAllConfigs = map[string]interface{}{}
@@ -49,8 +48,7 @@ func (this *ConfigService) InitGlobalConfigs() bool {
this.adminUserId = userInfo.UserId.Hex()
configs := []info.Config{}
// db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
db.ListByQ(db.Configs, bson.M{}, &configs)
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
for _, config := range configs {
if config.IsArr {
@@ -68,21 +66,11 @@ func (this *ConfigService) InitGlobalConfigs() bool {
}
}
// site URL
if s, ok := this.GlobalStringConfigs["siteUrl"]; !ok || s != "" {
this.GlobalStringConfigs["siteUrl"] = this.siteUrl
}
return true
}
func (this *ConfigService) GetSiteUrl() string {
s := this.GetGlobalStringConfig("siteUrl")
if s != "" {
return s
}
return this.siteUrl
return this.siteUrl;
}
func (this *ConfigService) GetAdminUsername() string {
return this.adminUsername
@@ -97,14 +85,14 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
if _, ok := this.GlobalAllConfigs[key]; !ok {
// 需要添加
config := info.Config{ConfigId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId), // 没用
UserId: bson.ObjectIdHex(userId),
Key: key,
IsArr: isArr,
IsMap: isMap,
IsArrMap: isArrMap,
UpdatedTime: time.Now(),
}
if isArr {
if(isArr) {
v, _ := value.([]string)
config.ValueArr = v
this.GlobalArrayConfigs[key] = v
@@ -125,7 +113,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
} else {
i := bson.M{"UpdatedTime": time.Now()}
this.GlobalAllConfigs[key] = value
if isArr {
if(isArr) {
v, _ := value.([]string)
i["ValueArr"] = v
this.GlobalArrayConfigs[key] = v
@@ -142,8 +130,7 @@ func (this *ConfigService) updateGlobalConfig(userId, key string, value interfac
i["ValueStr"] = v
this.GlobalStringConfigs[key] = v
}
// return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
return db.UpdateByQMap(db.Configs, bson.M{"Key": key}, i)
return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
}
}
@@ -190,7 +177,6 @@ func (this *ConfigService) GetGlobalArrMapConfig(key string) []map[string]string
func (this *ConfigService) IsOpenRegister() bool {
return this.GetGlobalStringConfig("openRegister") != ""
}
//-------
// 修改共享笔记的配置
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
@@ -202,7 +188,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
ok = false
msg = fmt.Sprint(err)
}
}()
}();
// 用户是否存在?
if registerSharedUserId == "" {
@@ -236,7 +222,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such notebook: " + notebookId
return
} else {
perm := "0"
perm := "0";
if registerSharedNotebookPerms[i] == 1 {
perm = "1"
}
@@ -261,7 +247,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
msg = "The user has no such note: " + noteId
return
} else {
perm := "0"
perm := "0";
if registerSharedNotePerms[i] == 1 {
perm = "1"
}
@@ -312,14 +298,14 @@ func (this *ConfigService) getBackupDirname() string {
}
func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
binPath := configService.GetGlobalStringConfig("mongodumpPath")
config := revel.Config
config := revel.Config;
dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
username, _ := revel.Config.String("db.username")
password, _ := revel.Config.String("db.password")
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
binPath = binPath + " -h " + host + " -d " + dbname + " --port " + port
binPath = binPath + " -h " + host + " -d " + dbname + " -port " + port
if username != "" {
binPath += " -u " + username + " -p " + password
}
@@ -334,7 +320,7 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
}
cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath)
Log(binPath);
b, err := cmd.Output()
if err != nil {
msg = fmt.Sprintf("%v", err)
@@ -346,7 +332,6 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
ok = configService.AddBackup(dir, remark)
return ok, msg
}
// 还原
func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
@@ -354,7 +339,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break
break;
}
}
if i == len(backups) {
@@ -362,21 +347,21 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
}
// 先备份当前
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"])
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"] )
if !ok {
return
}
// mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/
binPath := configService.GetGlobalStringConfig("mongorestorePath")
config := revel.Config
config := revel.Config;
dbname, _ := config.String("db.dbname")
host, _ := revel.Config.String("db.host")
port, _ := revel.Config.String("db.port")
username, _ := revel.Config.String("db.username")
password, _ := revel.Config.String("db.password")
// 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 != "" {
binPath += " -u " + username + " -p " + password
}
@@ -387,10 +372,10 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
return false, path + " Is Not Exists"
}
binPath += " " + path
binPath += " --directoryperdb " + path
cmd := exec.Command("/bin/sh", "-c", binPath)
Log(binPath)
Log(binPath);
b, err := cmd.Output()
if err != nil {
msg = fmt.Sprintf("%v", err)
@@ -408,7 +393,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break
break;
}
}
if i == len(backups) {
@@ -434,13 +419,13 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break
break;
}
}
if i == len(backups) {
return false, "Backup Not Found"
}
backup["remark"] = remark
backup["remark"] = remark;
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
return ok, ""
@@ -453,7 +438,7 @@ func (this *ConfigService) GetBackup(createdTime string) (map[string]string, boo
var backup map[string]string
for i, backup = range backups {
if backup["createdTime"] == createdTime {
break
break;
}
}
if i == len(backups) {
@@ -470,15 +455,12 @@ var port string
func init() {
revel.OnAppStart(func() {
/*
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
port = strconv.Itoa(revel.HttpPort)
if port != "80" {
port = ":" + port
} else {
port = "";
}
*/
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
if strings.HasPrefix(siteUrl, "http://") {
@@ -487,51 +469,53 @@ func init() {
defaultDomain = siteUrl[len("https://"):]
schema = "https://"
}
// port localhost:9000
ports := strings.Split(defaultDomain, ":")
if len(ports) == 2 {
port = ports[1]
}
if port == "80" {
port = ""
} else {
port = ":" + port
}
})
}
func (this *ConfigService) GetSchema() string {
return schema
return schema;
}
// 默认
func (this *ConfigService) GetDefaultDomain() string {
return defaultDomain
}
// 包含http://
func (this *ConfigService) GetDefaultUrl() string {
return schema + defaultDomain
}
// note
func (this *ConfigService) GetNoteDomain() string {
return "/note"
subDomain := this.GetGlobalStringConfig("noteSubDomain");
if subDomain != "" {
return subDomain + port
}
return this.GetDefaultDomain() + "/note"
}
func (this *ConfigService) GetNoteUrl() string {
return this.GetNoteDomain()
return schema + this.GetNoteDomain();
}
// blog
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 {
return this.GetBlogDomain()
return schema + this.GetBlogDomain();
}
// lea
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 {
return schema + this.GetLeaDomain()
return schema + this.GetLeaDomain();
}
func (this *ConfigService) GetUserUrl(domain string) string {
@@ -545,7 +529,6 @@ func (this *ConfigService) GetUserSubUrl(subDomain string) string {
func (this *ConfigService) AllowCustomDomain() bool {
return configService.GetGlobalStringConfig("allowCustomDomain") != ""
}
// 是否是好的自定义域名
func (this *ConfigService) IsGoodCustomDomain(domain string) bool {
blacks := this.GetGlobalArrayConfig("blackCustomDomains")
@@ -570,29 +553,20 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
// 上传大小
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)
return 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"),
"uploadBlogLogoSize":this.GetUploadSize("uploadBlogLogoSize"),
"uploadAttachSize":this.GetUploadSize("uploadAttachSize"),
"uploadAvatarSize":this.GetUploadSize("uploadAvatarSize"),
}
}
// 为用户得到全局的配置
// NoteController调用
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
uploadSizeConfigs := this.GetUploadSizeLimit()
uploadSizeConfigs := this.GetUploadSizeLimit();
config := map[string]interface{}{}
for k, v := range uploadSizeConfigs {
config[k] = v
@@ -606,5 +580,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
}
func (this *ConfigService) GetVersion() string {
return "2.3"
return "1.0-beta2"
}
+47 -118
View File
@@ -1,19 +1,17 @@
package service
import (
"crypto/tls"
"net"
"bytes"
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"html/template"
"time"
"strings"
"net/smtp"
"strconv"
"strings"
"time"
"fmt"
"html/template"
"bytes"
)
// 发送邮件
@@ -22,7 +20,7 @@ type EmailService struct {
tpls map[string]*template.Template
}
func NewEmailService() *EmailService {
func NewEmailService() (*EmailService) {
return &EmailService{tpls: map[string]*template.Template{}}
}
@@ -31,74 +29,12 @@ var host = ""
var emailPort = ""
var username = ""
var password = ""
var ssl = false
func InitEmailFromDb() {
host = configService.GetGlobalStringConfig("emailHost")
emailPort = configService.GetGlobalStringConfig("emailPort")
username = configService.GetGlobalStringConfig("emailUsername")
password = configService.GetGlobalStringConfig("emailPassword")
if configService.GetGlobalStringConfig("emailSSL") == "1" {
ssl = true
}
}
//return a smtp client
func dial(addr string) (*smtp.Client, error) {
conn, err := tls.Dial("tcp", addr, nil)
if err != nil {
LogW("Dialing Error:", err)
return nil, err
}
//分解主机端口字符串
host, _, _ := net.SplitHostPort(addr)
return smtp.NewClient(conn, host)
}
func SendEmailWithSSL (auth smtp.Auth, to []string, msg []byte) (err error) {
//create smtp client
c, err := dial(host + ":" + emailPort)
if err != nil {
LogW("Create smpt client error:", err)
return err
}
defer c.Close()
if auth != nil {
if ok, _ := c.Extension("AUTH"); ok {
if err = c.Auth(auth); err != nil {
LogW("Error during AUTH", err)
return err
}
}
}
if err = c.Mail(username); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}
func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string) {
@@ -114,21 +50,14 @@ func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string
mailtype := "html"
if mailtype == "html" {
content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
} else {
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
} else{
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
}
msg := []byte("To: " + to + "\r\nFrom: " + username + "<" + username + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
send_to := strings.Split(to, ";")
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)
}
err := smtp.SendMail(host+":"+emailPort, auth, username, send_to, msg)
if err != nil {
e = fmt.Sprint(err)
@@ -146,10 +75,10 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
return false
}
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateRegister")
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateRegister");
if tpl == "" {
if(tpl == "") {
return false
}
@@ -189,8 +118,8 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
return
}
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail")
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
// 发送邮件
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
@@ -215,8 +144,8 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
}
func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) {
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword")
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
// 发送邮件
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
@@ -235,8 +164,8 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st
// 发送邀请链接
func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool {
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateInvite")
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
@@ -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 {
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject")
tpl := configService.GetGlobalStringConfig("emailTemplateComment")
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject");
tpl := configService.GetGlobalStringConfig("emailTemplateComment");
// title := "评论提醒"
@@ -328,16 +257,17 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
return ok
}
// 验证模板是否正确
func (this *EmailService) ValidTpl(str string) (ok bool, msg string) {
func (this *EmailService) ValidTpl(str string) (ok bool, msg string){
defer func() {
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err)
}
}()
header := configService.GetGlobalStringConfig("emailTemplateHeader")
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
}();
header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
str = strings.Replace(str, "{{header}}", header, -1)
str = strings.Replace(str, "{{footer}}", footer, -1)
_, err := template.New("tpl name").Parse(str)
@@ -350,13 +280,13 @@ func (this *EmailService) ValidTpl(str string) (ok bool, msg string) {
}
// ok, msg, subject, tpl
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template) {
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template){
defer func() {
if err := recover(); err != nil {
ok = false
msg = fmt.Sprint(err)
}
}()
}();
var err error
var has bool
@@ -382,16 +312,16 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
ok = false
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容,
}
}()
}();
var tpl *template.Template
values["siteUrl"] = configService.GetSiteUrl()
values["siteUrl"] = configService.GetSiteUrl();
// subject
if subject != "" {
ok, msg, tpl = this.getTpl(subject)
if !ok {
if(!ok) {
return
}
var buffer bytes.Buffer
@@ -406,13 +336,13 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
}
// content
header := configService.GetGlobalStringConfig("emailTemplateHeader")
footer := configService.GetGlobalStringConfig("emailTemplateFooter")
header := configService.GetGlobalStringConfig("emailTemplateHeader");
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
body = strings.Replace(body, "{{header}}", header, -1)
body = strings.Replace(body, "{{footer}}", footer, -1)
values["subject"] = o
ok, msg, tpl = this.getTpl(body)
if !ok {
if(!ok) {
return
}
var buffer2 bytes.Buffer
@@ -429,14 +359,14 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
// 发送email给用户
// 需要记录
func (this *EmailService) SendEmailToUsers(users []info.User, subject, body string) (ok bool, msg string) {
if users == nil || len(users) == 0 {
if(users == nil || len(users) == 0) {
msg = "no users"
return
}
// 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if !ok {
if(!ok) {
Log(msg)
return
}
@@ -451,8 +381,8 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m)
ok = ok2
msg = msg2
if ok2 {
sendOk, msg := this.SendEmail(user.Email, subject2, body2)
if(ok2) {
sendOk, msg := this.SendEmail(user.Email, subject2, body2);
this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下
// 记录到Email Log
if sendOk {
@@ -470,19 +400,19 @@ func (this *EmailService) SendEmailToUsers(users []info.User, subject, body stri
}
func (this *EmailService) SendEmailToEmails(emails []string, subject, body string) (ok bool, msg string) {
if emails == nil || len(emails) == 0 {
if(emails == nil || len(emails) == 0) {
msg = "no emails"
return
}
// 尝试renderHtml
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
if !ok {
if(!ok) {
Log(msg)
return
}
// go func() {
// go func() {
for _, email := range emails {
if email == "" {
continue
@@ -490,8 +420,8 @@ func (this *EmailService) SendEmailToEmails(emails []string, subject, body strin
m := map[string]interface{}{}
m["email"] = email
ok, msg, subject, body = this.renderEmail(subject, body, m)
if ok {
sendOk, msg := this.SendEmail(email, subject, body)
if(ok) {
sendOk, msg := this.SendEmail(email, subject, body);
this.AddEmailLog(email, subject, body, sendOk, msg)
// 记录到Email Log
if sendOk {
@@ -500,10 +430,10 @@ func (this *EmailService) SendEmailToEmails(emails []string, subject, body strin
Log("no " + email)
}
} else {
Log(msg)
Log(msg);
}
}
// }()
// }()
return
}
@@ -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()}
db.Insert(db.EmailLogs, log)
}
// 展示邮件日志
func (this *EmailService) DeleteEmails(ids []string) bool {
@@ -532,7 +461,7 @@ func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField stri
if email != "" {
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
}
q := db.EmailLogs.Find(query)
q := db.EmailLogs.Find(query);
// 总记录数
count, _ := q.Count()
// 列表
+41 -76
View File
@@ -1,18 +1,15 @@
package service
import (
"encoding/base64"
"fmt"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
"gopkg.in/mgo.v2/bson"
"io/ioutil"
"net/http"
"time"
"os"
"strings"
"time"
// "fmt"
)
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
@@ -43,7 +40,7 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
if albumId != "" {
q["AlbumId"] = bson.ObjectIdHex(albumId)
q["AlbumId"] = bson.ObjectIdHex(albumId);
} else {
q["IsDefaultAlbum"] = true
}
@@ -51,9 +48,9 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
}
// LogJ(q)
// LogJ(q)
count := db.Count(db.Files, q)
count := db.Count(db.Files, q);
db.Files.
Find(q).
@@ -92,7 +89,7 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
if file.FileId != "" {
if(file.FileId != "") {
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
// delete image
// TODO
@@ -119,57 +116,11 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
func (this *FileService) GetFileBase64(userId, fileId string) (str string, mine string) {
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
if err := recover(); err != nil {
fmt.Println(err) // 这里的err其实就是panic传入的内容,55
}
}()
path := this.GetFile(userId, fileId)
if path == "" {
return "", ""
}
path = revel.BasePath + "/" + strings.TrimLeft(path, "/")
ff, err := ioutil.ReadFile(path)
if err != nil {
return "", ""
}
e64 := base64.StdEncoding
maxEncLen := e64.EncodedLen(len(ff))
encBuf := make([]byte, maxEncLen)
e64.Encode(encBuf, ff)
mime := http.DetectContentType(ff)
str = string(encBuf)
return str, mime
}
// 得到图片base64, 图片要在之前添加data:image/png;base64,
func (this *FileService) GetImageBase64(userId, fileId string) string {
str, mime := this.GetFileBase64(userId, fileId)
if str == "" {
return ""
}
switch mime {
case "image/gif", "image/jpeg", "image/pjpeg", "image/png", "image/tiff":
return fmt.Sprintf("data:%s;base64,%s", mime, str)
default:
}
return "data:image/png;base64," + str
}
// 获取文件路径
// 要判断是否具有权限
// userId是否具有fileId的访问权限
func (this *FileService) GetFile(userId, fileId string) string {
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
if fileId == "" {
return ""
}
@@ -182,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
}
// 1. 判断权限
//未登录用户,判断token
noteIds := noteImageService.GetNoteIds(fileId)
// 是否是我的文件
if userId != "" && file.UserId.Hex() == userId {
return path
@@ -192,20 +144,38 @@ func (this *FileService) GetFile(userId, fileId string) string {
// 这些笔记是否有public的, 若有则ok
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
noteIds := noteImageService.GetNoteIds(fileId)
if noteIds != nil && len(noteIds) > 0 {
// 这些笔记是否有public的
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
return path
}
//分享给未注册用户
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("image token is equal!")
return path
} else {
Log("image token is different!")
return ""
}
} else {
return ""
}
}
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
for _, noteId := range noteIds {
note := noteService.GetNoteById(noteId.Hex())
if shareService.HasReadPerm(note.UserId.Hex(), userId, noteId.Hex()) {
return path
return path;
}
}
/*
// 若有共享给我的笔记?
// 对该笔记可读?
@@ -242,17 +212,18 @@ func (this *FileService) GetFile(userId, fileId string) string {
return ""
}
// 复制共享的笔记时, 复制其中的图片到我本地
// 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了
file2 := info.File{}
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
if file2.FileId != "" {
return true, file2.FileId.Hex()
return true, file2.FileId.Hex();
}
// 复制之
file := info.File{}
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
@@ -261,20 +232,18 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
}
_, ext := SplitFilename(file.Name)
guid := NewGuid()
newFilename := guid + ext
newFilename := NewGuid() + ext
// TODO 统一目录格式
// dir := "files/" + toUserId + "/images"
dir := "files/" + GetRandomFilePath(toUserId, guid) + "/images"
dir := "files/" + toUserId + "/images"
filePath := dir + "/" + newFilename
err := os.MkdirAll(revel.BasePath+dir, 0755)
err := os.MkdirAll(dir, 0755)
if err != nil {
return false, ""
}
_, err = CopyFile(revel.BasePath+"/"+file.Path, revel.BasePath+"/"+filePath)
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
if err != nil {
Log(err)
return false, ""
}
@@ -283,7 +252,7 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
Path: filePath,
Size: file.Size,
FromFileId: file.FileId}
id := bson.NewObjectId()
id := bson.NewObjectId();
fileInfo.FileId = id
fileId = id.Hex()
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
@@ -296,9 +265,5 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
// 是否是我的文件
func (this *FileService) IsMyFile(userId, fileId string) bool {
// 如果有问题会panic
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
return false
}
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
}
+13 -105
View File
@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
// "strings"
// "strings"
)
// 用户组, 用户组用户管理
@@ -16,7 +16,7 @@ type GroupService struct {
// 添加分组
func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
group := info.Group{
group := info.Group {
GroupId: bson.NewObjectId(),
UserId: bson.ObjectIdHex(userId),
Title: title,
@@ -24,7 +24,6 @@ func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
}
return db.Insert(db.Groups, group), group
}
// 删除分组
// 判断是否有好友
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
@@ -33,36 +32,21 @@ func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg stri
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 {
/*
// 得到我的分组
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
// 得到分组s
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())
@@ -70,65 +54,15 @@ func (this *GroupService) GetGroupsAndUsers(userId string) []info.Group {
}
return groups
}
// 仅仅得到所有分组
func (this *GroupService) GetGroups(userId string) []info.Group {
func (this *GroupService) GetGroups(userId string) ([]info.Group) {
// 得到分组s
groups := []info.Group{}
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
return groups
}
// 得到我的和我所属组的ids
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) []bson.ObjectId {
// 所属组
groupIds := this.GetBelongToGroupIds(userId)
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 {
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
// 得到分组s
group := info.Group{}
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
@@ -136,7 +70,7 @@ func (this *GroupService) GetGroup(userId, groupId string) info.Group {
}
// 得到某分组下的用户
func (this *GroupService) GetUsers(groupId string) []info.User {
func (this *GroupService) GetUsers(groupId string) ([]info.User) {
// 得到UserIds
groupUsers := []info.GroupUser{}
db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers)
@@ -152,7 +86,7 @@ func (this *GroupService) GetUsers(groupId string) []info.User {
}
// 得到我所属的所有分组ids
func (this *GroupService) GetBelongToGroupIds(userId string) []bson.ObjectId {
func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
// 得到UserIds
groupUsers := []info.GroupUser{}
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
@@ -169,32 +103,17 @@ func (this *GroupService) GetBelongToGroupIds(userId string) []bson.ObjectId {
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
}
// 判断组中是否包含指定用户
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"
return false, "forbidden"
}
// 是否已存在
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
return false, "userExistsInGroup"
return false, "hasUsers"
}
return db.Insert(db.GroupUsers, info.GroupUser{
@@ -204,22 +123,11 @@ func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, m
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"
return false, "forbidden"
}
// 删除该用户分享到本组的笔记本, 笔记
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId)
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId)
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
}
+3 -3
View File
@@ -1,11 +1,11 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/db"
// . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
// "time"
// "time"
)
// 历史记录
+19 -86
View File
@@ -1,19 +1,19 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"regexp"
// "time"
// "time"
)
type NoteImageService struct {
}
// 通过id, userId得到noteIds
func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId {
func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, &noteImages)
@@ -29,7 +29,6 @@ func (this *NoteImageService) GetNoteIds(imageId string) []bson.ObjectId {
return nil
}
// TODO 这个web可以用, 但api会传来, 不用用了
// 解析内容中的图片, 建立图片与note的关系
// <img src="/file/outputImage?fileId=12323232" />
// 图片必须是我的, 不然不添加
@@ -39,8 +38,7 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
if imgSrc != "" {
content = "<img src=\"" + imgSrc + "\" >" + content
}
// life 添加getImage
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
// 删除旧的
@@ -52,8 +50,8 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
hasAdded := make(map[string]bool)
if find != nil && len(find) > 0 {
for _, each := range find {
if each != nil && len(each) == 3 {
fileId = each[2] // 现在有两个子表达式了
if each != nil && len(each) == 2 {
fileId = each[1]
// 之前没能添加过的
if _, ok := hasAdded[fileId]; !ok {
Log(fileId)
@@ -73,13 +71,17 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
/* 弃用之
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
noteImages := []info.NoteImage{}
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, &noteImages)
if len(noteImages) == 0 {
return content;
}
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
for _, noteImage := range noteImages {
imageId := noteImage.ImageId.Hex()
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
@@ -87,88 +89,19 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
replaceMap[imageId] = newImageId
}
}
*/
// 因为很多图片上传就会删除, 所以直接从内容中查看图片id进行复制
// <img src="/file/outputImage?fileId=12323232" />
// 把fileId=1232替换成新的
replaceMap := map[string]string{}
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
if len(replaceMap) > 0 {
// 替换之
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
content = reg.ReplaceAllStringFunc(content, func(each string) string {
// each = outputImage?fileId=541bd2f599c37b4f3r000003
// each = getImage?fileId=541bd2f599c37b4f3r000003
// each=outputImage?fileId=541bd2f599c37b4f3r000003
fileId := each[len(each)-24:] // 得到后24位, 也即id
if _, ok := replaceMap[fileId]; !ok {
if bson.IsObjectIdHex(fileId) {
ok2, newImageId := fileService.CopyImage(fromUserId, fileId, toUserId)
if ok2 {
replaceMap[fileId] = newImageId
} else {
replaceMap[fileId] = ""
}
} else {
replaceMap[fileId] = ""
}
}
replaceFileId := replaceMap[fileId]
if replaceFileId != "" {
if each[0] == 'o' {
if replaceFileId, ok := replaceMap[fileId]; ok {
return "outputImage?fileId=" + replaceFileId
}
return "getImage?fileId=" + replaceFileId
}
return each
})
});
}
return content
}
//
func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[string][]info.File {
noteNoteImages := []info.NoteImage{}
db.ListByQ(db.NoteImages, bson.M{"NoteId": bson.M{"$in": noteIds}}, &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
return content;
}
+73 -624
View File
@@ -1,12 +1,10 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"regexp"
"strings"
"time"
)
@@ -20,34 +18,29 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
return
}
// fileService调用
// 不能是已经删除了的, life bug, 客户端删除后, 竟然还能在web上打开
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
//通过附件id得到note
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
note = info.Note{}
if noteId == "" {
return
}
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsDeleted": false}, &note)
return
}
func (this *NoteService) GetNoteByIdAndUserId(noteId, userId string) (note info.Note) {
note = info.Note{}
if noteId == "" || userId == "" {
return
}
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "IsDeleted": false}, &note)
noteId := attach.NoteId
db.Get(db.Notes, noteId.Hex(), &note)
return
}
// fileService调用
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
note = info.Note{}
db.Get(db.Notes, noteId, &note)
return
}
// 得到blog, blogService用
// 不要传userId, 因为是公开的
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
note = info.Note{}
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId),
"IsBlog": true, "IsTrash": false, "IsDeleted": false}, &note)
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsBlog": true, "IsTrash": false}, &note)
return
}
// 通过id, userId得到noteContent
func (this *NoteService) GetNoteContent(noteContentId, userId string) (noteContent info.NoteContent) {
noteContent = info.NoteContent{}
@@ -62,114 +55,14 @@ func (this *NoteService) GetNoteAndContent(noteId, userId string) (noteAndConten
return info.NoteAndContent{note, noteContent}
}
// 获取同步的笔记
// > afterUsn的笔记
func (this *NoteService) GetSyncNotes(userId string, afterUsn, maxEntry int) []info.ApiNote {
notes := []info.Note{}
q := db.Notes.Find(bson.M{
"UserId": bson.ObjectIdHex(userId),
"Usn": bson.M{"$gt": afterUsn},
})
q.Sort("Usn").Limit(maxEntry).All(&notes)
return this.ToApiNotes(notes)
}
// note与apiNote的转换
func (this *NoteService) ToApiNotes(notes []info.Note) []info.ApiNote {
// 2, 得到所有图片, 附件信息
// 查images表, attachs表
if len(notes) > 0 {
noteIds := make([]bson.ObjectId, len(notes))
for i, note := range notes {
noteIds[i] = note.NoteId
}
noteFilesMap := this.getFiles(noteIds)
// 生成info.ApiNote
apiNotes := make([]info.ApiNote, len(notes))
for i, note := range notes {
noteId := note.NoteId.Hex()
apiNotes[i] = this.ToApiNote(&note, noteFilesMap[noteId])
}
return apiNotes
}
// 返回空的
return []info.ApiNote{}
}
// note与apiNote的转换
func (this *NoteService) ToApiNote(note *info.Note, files []info.NoteFile) info.ApiNote {
apiNote := info.ApiNote{
NoteId: note.NoteId.Hex(),
NotebookId: note.NotebookId.Hex(),
UserId: note.UserId.Hex(),
Title: note.Title,
Tags: note.Tags,
IsMarkdown: note.IsMarkdown,
IsBlog: note.IsBlog,
IsTrash: note.IsTrash,
IsDeleted: note.IsDeleted,
Usn: note.Usn,
CreatedTime: note.CreatedTime,
UpdatedTime: note.UpdatedTime,
PublicTime: note.PublicTime,
Files: files,
}
return apiNote
}
// getDirtyNotes, 把note的图片, 附件信息都发送给客户端
// 客户端保存到本地, 再获取图片, 附件
// 得到所有图片, 附件信息
// 查images表, attachs表
// [待测]
func (this *NoteService) getFiles(noteIds []bson.ObjectId) map[string][]info.NoteFile {
noteImages := noteImageService.getImagesByNoteIds(noteIds)
noteAttachs := attachService.getAttachsByNoteIds(noteIds)
noteFilesMap := map[string][]info.NoteFile{}
for _, noteId := range noteIds {
noteIdHex := noteId.Hex()
noteFiles := []info.NoteFile{}
// images
if images, ok := noteImages[noteIdHex]; ok {
for _, image := range images {
noteFiles = append(noteFiles, info.NoteFile{
FileId: image.FileId.Hex(),
Type: image.Type,
})
}
}
// attach
if attachs, ok := noteAttachs[noteIdHex]; ok {
for _, attach := range attachs {
noteFiles = append(noteFiles, info.NoteFile{
FileId: attach.AttachId.Hex(),
Type: attach.Type,
Title: attach.Title,
IsAttach: true,
})
}
}
noteFilesMap[noteIdHex] = noteFiles
}
return noteFilesMap
}
// 列出note, 排序规则, 还有分页
// CreatedTime, UpdatedTime, title 来排序
func (this *NoteService) ListNotes(userId, notebookId string,
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
notes = []info.Note{}
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
// 不是trash的
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash, "IsDeleted": false}
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash}
if isBlog {
query["IsBlog"] = true
}
@@ -177,7 +70,7 @@ func (this *NoteService) ListNotes(userId, notebookId string,
query["NotebookId"] = bson.ObjectIdHex(notebookId)
}
q := db.Notes.Find(query)
q := db.Notes.Find(query);
// 总记录数
count, _ = q.Count()
@@ -205,7 +98,6 @@ func (this *NoteService) ListNotesByNoteIdsWithPageSort(noteIds []bson.ObjectId,
All(&notes)
return
}
// shareService调用
func (this *NoteService) ListNotesByNoteIds(noteIds []bson.ObjectId) (notes []info.Note) {
notes = []info.Note{}
@@ -215,7 +107,6 @@ func (this *NoteService) ListNotesByNoteIds(noteIds []bson.ObjectId) (notes []in
All(&notes)
return
}
// blog需要
func (this *NoteService) ListNoteContentsByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
notes = []info.NoteContent{}
@@ -225,7 +116,6 @@ func (this *NoteService) ListNoteContentsByNoteIds(noteIds []bson.ObjectId) (not
All(&notes)
return
}
// 只得到abstract, 不需要content
func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
notes = []info.NoteContent{}
@@ -242,31 +132,24 @@ func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (note
// 首先要判断Notebook是否是Blog, 是的话设为blog
// [ok]
func (this *NoteService) AddNote(note info.Note, fromApi bool) info.Note {
if note.NoteId.Hex() == "" {
noteId := bson.NewObjectId()
note.NoteId = noteId
func (this *NoteService) AddNote(note info.Note) info.Note {
if(note.NoteId.Hex() == "") {
noteId := bson.NewObjectId();
note.NoteId = noteId;
}
// 关于创建时间, 可能是客户端发来, 此时判断时间是否有
note.CreatedTime = FixUrlTime(note.CreatedTime)
note.UpdatedTime = FixUrlTime(note.UpdatedTime)
note.CreatedTime = time.Now()
note.UpdatedTime = note.CreatedTime
note.IsTrash = false
note.UpdatedUserId = note.UserId
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note", note.NoteId.Hex())
note.Usn = userService.IncrUsn(note.UserId.Hex())
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
notebookId := note.NotebookId.Hex()
// api会传IsBlog, web不会传
if !fromApi {
// 设为blog
notebookId := note.NotebookId.Hex()
note.IsBlog = notebookService.IsBlog(notebookId)
}
// if note.IsBlog {
if note.IsBlog {
note.PublicTime = note.UpdatedTime
// }
}
db.Insert(db.Notes, note)
@@ -284,70 +167,26 @@ func (this *NoteService) AddSharedNote(note info.Note, myUserId bson.ObjectId) i
// 判断我是否有权限添加
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
note.CreatedUserId = myUserId // 是我给共享我的人创建的
return this.AddNote(note, false)
return this.AddNote(note)
}
return info.Note{}
}
// 添加笔记本内容
// [ok]
func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteContent {
noteContent.CreatedTime = FixUrlTime(noteContent.CreatedTime)
noteContent.UpdatedTime = FixUrlTime(noteContent.UpdatedTime)
noteContent.CreatedTime = time.Now()
noteContent.UpdatedTime = noteContent.CreatedTime
noteContent.UpdatedUserId = noteContent.UserId
db.Insert(db.NoteContents, noteContent)
// 更新笔记图片
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), "", noteContent.Content)
return noteContent
return noteContent;
}
// API, abstract, desc需要这里获取
// 不需要
/*
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
if(note.NoteId.Hex() == "") {
noteId := bson.NewObjectId();
note.NoteId = noteId;
}
note.CreatedTime = time.Now()
note.UpdatedTime = note.CreatedTime
note.IsTrash = false
note.UpdatedUserId = note.UserId
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
note.Usn = userService.IncrUsn(note.UserId.Hex())
// desc这里获取
desc := SubStringHTMLToRaw(noteContent.Content, 50)
note.Desc = desc;
// 设为blog
notebookId := note.NotebookId.Hex()
note.IsBlog = notebookService.IsBlog(notebookId)
if note.IsBlog {
note.PublicTime = note.UpdatedTime
}
db.Insert(db.Notes, note)
// tag1, 不需要了
// tagService.AddTags(note.UserId.Hex(), note.Tags)
// recount notebooks' notes number
notebookService.ReCountNotebookNumberNotes(notebookId)
// 这里, 添加到内容中
abstract := SubStringHTML(noteContent.Content, 200, "")
noteContent.Abstract = abstract
this.AddNoteContent(noteContent)
return note
}*/
// 添加笔记和内容
// 这里使用 info.NoteAndContent 接收?
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
@@ -359,10 +198,10 @@ func (this *NoteService) AddNoteAndContentForController(note info.Note, noteCont
Log("HAS AUTH -----------")
}
}
return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId))
return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId));
}
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
if note.NoteId.Hex() == "" {
if(note.NoteId.Hex() == "") {
noteId := bson.NewObjectId()
note.NoteId = noteId
}
@@ -370,24 +209,7 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note
if note.UserId != myUserId {
note = this.AddSharedNote(note, myUserId)
} else {
note = this.AddNote(note, false)
}
if note.NoteId != "" {
this.AddNoteContent(noteContent)
}
return note
}
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
if note.NoteId.Hex() == "" {
noteId := bson.NewObjectId()
note.NoteId = noteId
}
noteContent.NoteId = note.NoteId
if note.UserId != myUserId {
note = this.AddSharedNote(note, myUserId)
} else {
note = this.AddNote(note, true)
note = this.AddNote(note)
}
if note.NoteId != "" {
this.AddNoteContent(noteContent)
@@ -396,138 +218,39 @@ func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.N
}
// 修改笔记
// 这里没有判断usn
func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bson.M, usn int) (bool, string, int) {
// 是否存在
note := this.GetNoteById(noteId)
if note.NoteId == "" {
return false, "notExists", 0
}
userId := note.UserId.Hex()
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
if userId != updatedUserId {
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
Log("NO AUTH2")
return false, "noAuth", 0
return false
} else {
Log("HAS AUTH -----------")
}
}
/*
// 这里不再判断, 因为controller已经判断了, 删除附件会新增, 所以不用判断
if usn > 0 && note.Usn != usn {
Log("有冲突!!")
Log(note.Usn)
Log(usn)
return false, "conflict", 0
}
*/
// 是否已自定义
note := this.GetNoteById(noteId)
if note.IsBlog && note.HasSelfDefined {
delete(needUpdate, "ImgSrc")
delete(needUpdate, "Desc")
}
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId)
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
needUpdate["UpdatedTime"] = time.Now();
// 可以将时间传过来
updatedTime, ok := needUpdate["UpdatedTime"].(time.Time)
if ok {
needUpdate["UpdatedTime"] = FixUrlTime(updatedTime)
} else {
needUpdate["UpdatedTime"] = time.Now()
// 添加tag2
if tags, ok := needUpdate["Tags"]; ok {
tagService.AddTagsI(userId, tags)
}
afterUsn := userService.IncrUsn(userId)
needUpdate["Usn"] = afterUsn
needRecountTags := false
// 是否修改了isBlog
// 也要修改noteContents的IsBlog
if isBlog, ok := needUpdate["IsBlog"]; ok {
isBlog2 := isBlog.(bool)
if note.IsBlog != isBlog2 {
this.UpdateNoteContentIsBlog(noteId, userId, isBlog2)
// 重新发布成博客
if !note.IsBlog {
needUpdate["PublicTime"] = needUpdate["UpdatedTime"]
}
needRecountTags = true
}
}
// 添加tag2
// TODO 这个tag去掉, 添加tag另外添加, 不要这个
if tags, ok := needUpdate["Tags"]; ok {
tagService.AddTagsI(userId, tags)
// 如果是博客, 标签改了, 那么重新计算
if note.IsBlog {
needRecountTags = true
}
}
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
if !ok {
return ok, "", 0
}
if needRecountTags {
// 重新计算tags
go (func() {
blogService.ReCountBlogTags(userId)
})()
}
// 重新获取之
note = this.GetNoteById(noteId)
hasRecount := false
// 如果修改了notebookId, 则更新notebookId'count
// 两方的notebook也要修改
notebookIdI := needUpdate["NotebookId"]
if notebookIdI != nil {
notebookId := notebookIdI.(bson.ObjectId)
if notebookId != "" {
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
notebookService.ReCountNotebookNumberNotes(notebookId.Hex())
hasRecount = true
}
}
// 不要多次更新, isTrash = false, = true都要重新统计
if isTrashI, ok := needUpdate["IsTrash"]; ok {
// 如果是垃圾, 则删除之共享
isTrash := isTrashI.(bool)
if isTrash {
shareService.DeleteShareNoteAll(noteId, userId)
}
if !hasRecount {
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
}
}
return true, "", afterUsn
}
// 当设置/取消了笔记为博客
func (this *NoteService) UpdateNoteContentIsBlog(noteId, userId string, isBlog bool) {
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog})
}
}
// 附件修改, 增加noteIncr
func (this *NoteService) IncrNoteUsn(noteId, userId string) int {
afterUsn := userService.IncrUsn(userId)
db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
bson.M{"UpdatedTime": time.Now(), "Usn": afterUsn})
return afterUsn
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
}
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
@@ -542,54 +265,31 @@ func (this *NoteService) UpdateNoteTitle(userId, updatedUserId, noteId, title st
}
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now(), "Usn": userService.IncrUsn(userId)})
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now()})
}
// 修改笔记本内容
// [ok] TODO perm未测
// hasBeforeUpdateNote 之前是否更新过note其它信息, 如果有更新, usn不用更新
// TODO abstract这里生成
func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstract string,
hasBeforeUpdateNote bool,
usn int, updatedTime time.Time) (bool, string, int) {
// 是否已自定义
note := this.GetNoteById(noteId)
if note.NoteId == "" {
return false, "notExists", 0
}
userId := note.UserId.Hex()
func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, content, abstract string) bool {
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
if userId != updatedUserId {
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
Log("NO AUTH")
return false, "noAuth", 0
return false
}
}
updatedTime = FixUrlTime(updatedTime)
// abstract重置
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
"Content": content,
"Abstract": abstract,
"UpdatedTime": updatedTime}
"UpdatedTime": time.Now()}
// 是否已自定义
note := this.GetNoteById(noteId)
if note.IsBlog && note.HasSelfDefined {
delete(data, "Abstract")
}
// usn, 修改笔记不可能单独修改内容
afterUsn := 0
// 如果之前没有修改note其它信息, 那么usn++
if !hasBeforeUpdateNote {
// 需要验证
if usn >= 0 && note.Usn != usn {
return false, "conflict", 0
}
afterUsn = userService.IncrUsn(userId)
db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Usn", usn)
}
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
// 这里, 添加历史记录
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
@@ -600,9 +300,9 @@ func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstr
// 更新笔记图片
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
return true, "", afterUsn
return true
}
return false, "", 0
return false
}
// ?????
@@ -616,7 +316,7 @@ func (this *NoteService) updateNoteImages(noteId string, content string) bool {
// 更新tags
// [ok] [del]
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{"Tags": tags, "Usn": userService.IncrUsn(userId)})
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
}
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
@@ -634,13 +334,9 @@ func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool
} else {
noteUpdate["HasSelfDefined"] = false
}
noteUpdate["Usn"] = userService.IncrUsn(userId)
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
// 重新计算tags
go (func() {
this.UpdateNoteContentIsBlog(noteId, userId, isBlog)
blogService.ReCountBlogTags(userId)
})()
return ok
@@ -657,9 +353,7 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
bson.M{"$set": bson.M{"IsTrash": false,
"NotebookId": bson.ObjectIdHex(notebookId),
"Usn": userService.IncrUsn(userId),
}})
"NotebookId": bson.ObjectIdHex(notebookId)}})
if re {
// 更新blog状态
@@ -673,7 +367,7 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
}
}
return this.GetNote(noteId, userId)
return this.GetNote(noteId, userId);
}
return info.Note{}
}
@@ -681,23 +375,21 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
// 如果自己的blog状态是true, 不用改变,
// 否则, 如果notebookId的blog是true, 则改为true之
// 返回blog状态
// move, copy时用
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
if this.IsBlog(noteId) {
return true
}
if notebookService.IsBlog(notebookId) {
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
bson.M{"$set": bson.M{"IsBlog": true, "PublicTime": time.Now()}}) // life
bson.M{"$set": bson.M{"IsBlog": true}})
return true
}
return false
}
// 判断是否是blog
func (this *NoteService) IsBlog(noteId string) bool {
note := info.Note{}
db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"IsBlog"}, &note)
db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"IsBlog"}, &note);
return note.IsBlog
}
@@ -711,11 +403,11 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
noteContent := this.GetNoteContent(noteId, userId)
// 重新生成noteId
note.NoteId = bson.NewObjectId()
note.NoteId = bson.NewObjectId();
note.NotebookId = bson.ObjectIdHex(notebookId)
noteContent.NoteId = note.NoteId
note = this.AddNoteAndContent(note, noteContent, note.UserId)
this.AddNoteAndContent(note, noteContent, note.UserId);
// 更新blog状态
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
@@ -734,9 +426,10 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
// 复制别人的共享笔记给我
// 将别人可用的图片转为我的图片, 复制图片
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
// Log(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId))
// 判断是否共享了给我
// Log(notebookService.IsMyNotebook(notebookId, myUserId))
if notebookService.IsMyNotebook(notebookId, myUserId) && shareService.HasReadPerm(fromUserId, myUserId, noteId) {
if notebookService.IsMyNotebook(notebookId, myUserId) &&
(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId)) {
note := this.GetNote(noteId, fromUserId)
if note.NoteId == "" {
return info.Note{}
@@ -744,7 +437,7 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
noteContent := this.GetNoteContent(noteId, fromUserId)
// 重新生成noteId
note.NoteId = bson.NewObjectId()
note.NoteId = bson.NewObjectId();
note.NotebookId = bson.ObjectIdHex(notebookId)
note.UserId = bson.ObjectIdHex(myUserId)
note.IsTop = false
@@ -763,7 +456,7 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
attachService.CopyAttachs(noteId, note.NoteId.Hex(), myUserId)
// 添加之
note = this.AddNoteAndContent(note, noteContent, note.UserId)
note = this.AddNoteAndContent(note, noteContent, note.UserId);
// 更新blog状态
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, myUserId)
@@ -803,13 +496,12 @@ func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int
// 不是trash的
query := bson.M{"UserId": bson.ObjectIdHex(userId),
"IsTrash": false,
"IsDeleted": false, // 不能搜索已删除了的
"$or": orQ,
}
if isBlog {
query["IsBlog"] = true
}
q := db.Notes.Find(query)
q := db.Notes.Find(query);
// 总记录数
count, _ = q.Count()
@@ -834,11 +526,7 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
noteIds[i] = note.NoteId
}
noteContents := []info.NoteContent{}
query := bson.M{
"_id": bson.M{"$nin": noteIds},
"UserId": bson.ObjectIdHex(userId),
"Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
}
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
if isBlog {
query["IsBlog"] = true
}
@@ -849,7 +537,7 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
Select(bson.M{"_id": true}).
All(&noteContents)
var lenContent = len(noteContents)
if lenContent == 0 {
if(lenContent == 0) {
return notes
}
@@ -863,13 +551,7 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
notes2 := this.ListNotesByNoteIds(noteIds2)
// 合并之
// 不能是删除的
for _, n := range notes2 {
if !n.IsDeleted && !n.IsTrash {
// notes = append(notes, notes2...)
notes = append(notes, n)
}
}
notes = append(notes, notes2...)
return notes
}
@@ -884,7 +566,7 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
"IsTrash": false,
"Tags": bson.M{"$all": tags}}
q := db.Notes.Find(query)
q := db.Notes.Find(query);
// 总记录数
count, _ = q.Count()
@@ -896,253 +578,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
return
}
//------------
// 统计
func (this *NoteService) CountNote(userId string) int {
q := bson.M{"IsTrash": false, "IsDeleted": false}
q := bson.M{"IsTrash": false}
if userId != "" {
q["UserId"] = bson.ObjectIdHex(userId)
}
return db.Count(db.Notes, q)
}
func (this *NoteService) CountBlog(userId string) int {
q := bson.M{"IsBlog": true, "IsTrash": false, "IsDeleted": false}
q := bson.M{"IsBlog": true, "IsTrash": false}
if userId != "" {
q["UserId"] = bson.ObjectIdHex(userId)
}
return db.Count(db.Notes, q)
}
// 通过标签来查询
func (this *NoteService) CountNoteByTag(userId string, tag string) int {
if tag == "" {
return 0
}
query := bson.M{"UserId": bson.ObjectIdHex(userId),
// "IsTrash": false,
"IsDeleted": false,
"Tags": bson.M{"$in": []string{tag}}}
return db.Count(db.Notes, query)
}
// 删除tag
// 返回所有note的Usn
func (this *NoteService) UpdateNoteToDeleteTag(userId string, targetTag string) map[string]int {
query := bson.M{"UserId": bson.ObjectIdHex(userId),
"Tags": bson.M{"$in": []string{targetTag}}}
notes := []info.Note{}
db.ListByQ(db.Notes, query, &notes)
ret := map[string]int{}
for _, note := range notes {
tags := note.Tags
if tags == nil {
continue
}
for i, tag := range tags {
if tag == targetTag {
tags = tags
tags = append(tags[:i], tags[i+1:]...)
break
}
}
usn := userService.IncrUsn(userId)
db.UpdateByQMap(db.Notes, bson.M{"_id": note.NoteId}, bson.M{"Usn": usn, "Tags": tags})
ret[note.NoteId.Hex()] = usn
}
return ret
}
// api
// 得到笔记的内容, 此时将笔记内的链接转成标准的Leanote Url
// 将笔记的图片, 附件链接转换成 site.url/file/getImage?fileId=xxx, site.url/file/getAttach?fileId=xxxx
func (this *NoteService) FixContentBad(content string, isMarkdown bool) string {
baseUrl := configService.GetSiteUrl()
baseUrlPattern := baseUrl
// 避免https的url
if baseUrl[0:8] == "https://" {
baseUrlPattern = strings.Replace(baseUrl, "https://", "https*://", 1)
} else {
baseUrlPattern = strings.Replace(baseUrl, "http://", "https*://", 1)
}
patterns := []map[string]string{
map[string]string{"src": "src", "middle": "/file/outputImage", "param": "fileId", "to": "getImage?fileId="},
map[string]string{"src": "href", "middle": "/attach/download", "param": "attachId", "to": "getAttach?fileId="},
// 该链接已失效, 不再支持
map[string]string{"src": "href", "middle": "/attach/downloadAll", "param": "noteId", "to": "getAllAttachs?noteId="},
}
for _, eachPattern := range patterns {
if !isMarkdown {
// 富文本处理
// <img src="http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1">
// <a href="http://leanote.com/attach/download?attachId=5504243a38f4111dcb00017d"></a>
var reg *regexp.Regexp
if eachPattern["src"] == "src" {
reg, _ = regexp.Compile("<img(?:[^>]+?)(" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})["']*)[^>]*>`)
} else {
reg, _ = regexp.Compile("<a(?:[^>]+?)(" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})["']*)[^>]*>`)
}
finds := reg.FindAllStringSubmatch(content, -1) // 查找所有的
for _, eachFind := range finds {
if len(eachFind) == 3 {
// 这一行会非常慢!, content是全部的内容, 多次replace导致
content = strings.Replace(content,
eachFind[1],
eachPattern["src"]+"=\""+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+"\"",
1)
}
}
} else {
// markdown处理
// ![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1)
// [selection 2.html](http://leanote.com/attach/download?attachId=5504262638f4111dcb00017f)
// [all.tar.gz](http://leanote.com/attach/downloadAll?noteId=5503b57d59f81b4eb4000000)
pre := "!" // 默认图片
if eachPattern["src"] == "href" { // 是attach
pre = ""
}
regImageMarkdown, _ := regexp.Compile(pre + `\[([^]]*?)\]\(` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})\)`)
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(content, -1) // 查找所有的
// [[![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1] [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1]]
for _, eachFind := range findsImageMarkdown {
// [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 你好啊, 我很好, 为什么? 5503537b38f4111dcb0000d1]
if len(eachFind) == 3 {
content = strings.Replace(content, eachFind[0], pre+"["+eachFind[1]+"]("+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+")", 1)
}
}
}
}
return content
}
// 得到笔记的内容, 此时将笔记内的链接转成标准的Leanote Url
// 将笔记的图片, 附件链接转换成 site.url/file/getImage?fileId=xxx, site.url/file/getAttach?fileId=xxxx
// 性能更好, 5倍的差距
func (this *NoteService) FixContent(content string, isMarkdown bool) string {
baseUrl := configService.GetSiteUrl()
baseUrlPattern := baseUrl
// 避免https的url
if baseUrl[0:8] == "https://" {
baseUrlPattern = strings.Replace(baseUrl, "https://", "https*://", 1)
} else {
baseUrlPattern = strings.Replace(baseUrl, "http://", "https*://", 1)
}
baseUrlPattern = "(?:" + baseUrlPattern + ")*"
Log(baseUrlPattern)
patterns := []map[string]string{
map[string]string{"src": "src", "middle": "/api/file/getImage", "param": "fileId", "to": "getImage?fileId="},
map[string]string{"src": "src", "middle": "/file/outputImage", "param": "fileId", "to": "getImage?fileId="},
map[string]string{"src": "href", "middle": "/attach/download", "param": "attachId", "to": "getAttach?fileId="},
map[string]string{"src": "href", "middle": "/api/file/getAtach", "param": "fileId", "to": "getAttach?fileId="},
// 该链接已失效, 不再支持
// map[string]string{"src": "href", "middle": "/attach/downloadAll", "param": "noteId", "to": "getAllAttachs?noteId="},
}
for _, eachPattern := range patterns {
if !isMarkdown {
// 富文本处理
// <img src="http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1">
// <a href="http://leanote.com/attach/download?attachId=5504243a38f4111dcb00017d"></a>
var reg *regexp.Regexp
var reg2 *regexp.Regexp
if eachPattern["src"] == "src" {
reg, _ = regexp.Compile("<img(?:[^>]+?)(?:" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=(?:[a-z0-9A-Z]{24})["']*)[^>]*>`)
reg2, _ = regexp.Compile("<img(?:[^>]+?)(" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})["']*)[^>]*>`)
} else {
reg, _ = regexp.Compile("<a(?:[^>]+?)(?:" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=(?:[a-z0-9A-Z]{24})["']*)[^>]*>`)
reg2, _ = regexp.Compile("<a(?:[^>]+?)(" + eachPattern["src"] + `=['"]*` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})["']*)[^>]*>`)
}
Log(reg2)
content = reg.ReplaceAllStringFunc(content, func(str string) string {
// str=这样的
// <img src="http://localhost:9000/file/outputImage?fileId=563d706e99c37b48e0000001" alt="" data-mce-src="http://localhost:9000/file/outputImage?fileId=563d706e99c37b48e0000002">
eachFind := reg2.FindStringSubmatch(str)
str = strings.Replace(str,
eachFind[1],
eachPattern["src"]+"=\""+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+"\"",
1)
// fmt.Println(str)
return str
})
/*
finds := reg.FindAllStringSubmatch(content, -1) // 查找所有的
for _, eachFind := range finds {
if len(eachFind) == 3 {
// 这一行会非常慢!, content是全部的内容, 多次replace导致
content = strings.Replace(content,
eachFind[1],
eachPattern["src"]+"=\""+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+"\"",
1)
}
}
*/
} else {
// markdown处理
// ![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1)
// [selection 2.html](http://leanote.com/attach/download?attachId=5504262638f4111dcb00017f)
// [all.tar.gz](http://leanote.com/attach/downloadAll?noteId=5503b57d59f81b4eb4000000)
pre := "!" // 默认图片
if eachPattern["src"] == "href" { // 是attach
pre = ""
}
regImageMarkdown, _ := regexp.Compile(pre + `\[(?:[^]]*?)\]\(` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=(?:[a-z0-9A-Z]{24})\)`)
regImageMarkdown2, _ := regexp.Compile(pre + `\[([^]]*?)\]\(` + baseUrlPattern + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})\)`)
content = regImageMarkdown.ReplaceAllStringFunc(content, func(str string) string {
// str=这样的
// <img src="http://localhost:9000/file/outputImage?fileId=563d706e99c37b48e0000001" alt="" data-mce-src="http://localhost:9000/file/outputImage?fileId=563d706e99c37b48e0000002">
eachFind := regImageMarkdown2.FindStringSubmatch(str)
str = strings.Replace(str, eachFind[0], pre+"["+eachFind[1]+"]("+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+")", 1)
// fmt.Println(str)
return str
})
/*
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(content, -1) // 查找所有的
// [[![](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1] [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 5503537b38f4111dcb0000d1]]
for _, eachFind := range findsImageMarkdown {
// [![你好啊, 我很好, 为什么?](http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1) 你好啊, 我很好, 为什么? 5503537b38f4111dcb0000d1]
if len(eachFind) == 3 {
content = strings.Replace(content, eachFind[0], pre+"["+eachFind[1]+"]("+baseUrl+"/api/file/"+eachPattern["to"]+eachFind[2]+")", 1)
}
}
*/
}
}
return content
}
+25 -101
View File
@@ -1,15 +1,13 @@
package service
import (
// "fmt"
// "fmt"
"gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"sort"
"strings"
"time"
// "html"
)
// 笔记本
@@ -43,8 +41,6 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
newNotebooks.NotebookId = each.NotebookId
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.UserId = each.UserId
newNotebooks.ParentNotebookId = each.ParentNotebookId
@@ -115,24 +111,12 @@ func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOr
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
// 排序好之后返回
// [ok]
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
userNotebooks := []info.Notebook{}
orQ := []bson.M{
bson.M{"IsDeleted": false},
bson.M{"IsDeleted": bson.M{"$exists": false}},
}
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "$or": orQ}).All(&userNotebooks)
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId)}).All(&userNotebooks)
if len(userNotebooks) == 0 {
return nil
@@ -156,58 +140,21 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
}
// 添加
func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Notebook) {
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
// [ok]
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
err := db.Notebooks.Insert(notebook)
if err != nil {
return false, notebook
}
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)
panic(err)
} else {
updates["ParentNotebookId"] = ""
}
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
if ok {
return ok, "", this.GetNotebookById(notebookId)
}
return false, "", notebook
return true
}
// 判断是否是blog
func (this *NotebookService) IsBlog(notebookId string) bool {
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
}
@@ -227,22 +174,19 @@ func (this *NotebookService) UpdateNotebook(notebook info.Notebook) bool {
// 更新笔记本标题
// [ok]
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
usn := userService.IncrUsn(userId)
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Title": title, "Usn": usn})
return db.UpdateByIdAndUserIdField(db.Notebooks, notebookId, userId, "Title", title)
}
// 更新notebook
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
needUpdate["UpdatedTime"] = time.Now()
needUpdate["Usn"] = userService.IncrUsn(userId)
needUpdate["UpdatedTime"] = time.Now();
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
}
// ToBlog or Not
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool {
updates := bson.M{"IsBlog": isBlog, "Usn": userService.IncrUsn(userId)}
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
// 笔记本
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"IsBlog": isBlog})
// 更新笔记
q := bson.M{"UserId": bson.ObjectIdHex(userId),
@@ -253,8 +197,6 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool
} else {
data["HasSelfDefined"] = false
}
// usn
data["Usn"] = userService.IncrUsn(userId)
db.UpdateByQMap(db.Notes, q, data)
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
@@ -280,19 +222,12 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) bool
// 查看是否有子notebook
// 先查看该notebookId下是否有notes, 没有则删除
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
if db.Count(db.Notebooks, bson.M{
"ParentNotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsDeleted": false,
}) == 0 { // 无
if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
"UserId": bson.ObjectIdHex(userId),
"IsTrash": false,
"IsDeleted": false}) == 0 { // 不包含trash
// 不是真删除 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), ""
"IsTrash": false}) == 0 { // 不包含trash
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
}
return false, "笔记本下有笔记"
} else {
@@ -300,18 +235,6 @@ func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, st
}
}
// API调用, 删除笔记本, 不作笔记控制
func (this *NotebookService) DeleteNotebookForce(userId, notebookId string, usn int) (bool, string) {
notebook := this.GetNotebookById(notebookId)
// 不存在
if notebook.NotebookId == "" {
return false, "notExists"
} else if notebook.Usn != usn {
return false, "conflict"
}
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
}
// 排序
// 传入 notebookId => Seq
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
@@ -322,7 +245,7 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
}
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
}
}
@@ -330,14 +253,15 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
return true
}
// 排序和设置父
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
userIdO := bson.ObjectIdHex(userId)
ok := false
// 如果没parentNotebookId, 则parentNotebookId设空
if parentNotebookId == "" {
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)})
if(parentNotebookId == "") {
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", "");
} 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 {
@@ -346,7 +270,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
// 排序
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
}
}
@@ -359,7 +283,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
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(notebookId)
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
+2 -8
View File
@@ -1,10 +1,10 @@
package service
import (
"gopkg.in/mgo.v2/bson"
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
. "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
}
// 重置密码时
// 修改密码
// 先验证
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
}
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
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
+18 -15
View File
@@ -1,12 +1,12 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
// "strings"
// "strings"
)
// Session存储到mongodb中
@@ -18,6 +18,12 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
bson.M{key: value, "UpdatedTime": time.Now()})
}
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
}
// 注销时清空session
func (this *SessionService) Clear(sessionId string) bool {
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
@@ -46,16 +52,14 @@ func (this *SessionService) LoginTimesIsOver(sessionId string) bool {
session := this.Get(sessionId)
return session.LoginTimes > 5
}
// 登录成功后清空错误次数
func (this *SessionService) ClearLoginTimes(sessionId string) bool {
return this.Update(sessionId, "LoginTimes", 0)
}
// 增加错误次数
func (this *SessionService) IncrLoginTimes(sessionId string) bool {
session := this.Get(sessionId)
return this.Update(sessionId, "LoginTimes", session.LoginTimes+1)
return this.Update(sessionId, "LoginTimes", session.LoginTimes + 1)
}
//----------
@@ -73,19 +77,18 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
return ok
}
//-----------
// API
func (this *SessionService) GetUserId(sessionId string) string {
// 附件token
func (this *SessionService) GetToken(sessionId string) string {
session := this.Get(sessionId)
// 更新updateTime, 避免过期
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{"UpdatedTime": time.Now()})
return session.UserId
return session.Token
}
// 登录成功后设置userId
func (this *SessionService) SetUserId(sessionId, userId string) bool {
func (this *SessionService) SetToken(sessionId, token string) bool {
this.Get(sessionId)
ok := this.Update(sessionId, "UserId", userId)
Log(sessionId)
Log(token)
ok := this.UpdateToken(sessionId, "Token", token)
Log(ok)
return ok
}
+111 -103
View File
@@ -1,12 +1,15 @@
package service
import (
"github.com/leanote/leanote/app/db"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
. "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"sort"
"time"
"sort"
"math/rand"
"regexp"
"strings"
)
// 共享Notebook, Note服务
@@ -33,9 +36,8 @@ type ShareService struct {
// 谁共享给了我的Query
func (this *ShareService) getOrQ(userId string) bson.M {
// 得到我和和我参与的组织
groupIds := groupService.GetMineAndBelongToGroupIds(userId)
// 得到我参与的组织
groupIds := groupService.GetBelongToGroupIds(userId)
q := bson.M{}
if len(groupIds) > 0 {
orQ := []bson.M{
@@ -45,15 +47,13 @@ func (this *ShareService) getOrQ(userId string) bson.M {
// 不是trash的
q["$or"] = orQ
} else {
q["ToUserId"] = bson.ObjectIdHex(userId)
q["ToUserId"] = bson.ObjectIdHex(userId);
}
return q
}
// 得到共享给我的笔记本和用户(谁共享给了我)
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
myUserId := userId
// 得到共享给我的用户s信息
// 得到我参与的组织
q := this.getOrQ(userId)
@@ -67,15 +67,7 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
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
@@ -109,22 +101,17 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
subShareNotebooks := this.parseToSubShareNotebooks(&subNotebooks, &shareNotebooksMap)
// 3 按用户进行分组成ShareNotebooksByUser
shareNotebooksByUsersMap := map[bson.ObjectId][]info.ShareNotebooks{}
shareNotebooksByUsersMap := map[bson.ObjectId] []info.ShareNotebooks{}
// 先建立userId => []
for _, eachSub := range subShareNotebooks {
userId := eachSub.Notebook.UserId
// 我自己的, 算了
if userId.Hex() == myUserId {
continue
}
if _, ok := shareNotebooksByUsersMap[userId]; ok {
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
} else {
shareNotebooksByUsersMap[userId] = []info.ShareNotebooks{eachSub}
}
}
shareNotebooksByUser := info.ShareNotebooksByUser{}
shareNotebooksByUser := info.ShareNotebooksByUser{};
for userId, eachShareNotebooks := range shareNotebooksByUsersMap {
// 4, 按用户排序
shareNotebooksByUser[userId.Hex()] = sortSubShareNotebooks(eachShareNotebooks)
@@ -173,11 +160,11 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
// 得到共享笔记本下的notes
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
q := this.getOrQ(myUserId)
q["NotebookId"] = bson.ObjectIdHex(notebookId)
q["UserId"] = bson.ObjectIdHex(sharedUserId)
q["NotebookId"] = bson.ObjectIdHex(notebookId);
q["UserId"] = bson.ObjectIdHex(sharedUserId);
shareNotebook := info.ShareNotebook{}
db.GetByQ(db.ShareNotebooks,
q,
@@ -190,7 +177,7 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
perm := shareNotebook.Perm
// 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.1 如果该notebook自己有其它权限信息, 比如1, 那么覆盖notebook的权限信息
@@ -210,12 +197,12 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
}
}
Log("笔记权限")
LogJ(notePerms)
LogJ(notePerms);
// 3.2 组合
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
for i, each := range notes {
thisPerm := perm
thisPerm := perm;
if selfPerm, ok := notePerms[each.NoteId]; ok {
thisPerm = selfPerm
}
@@ -247,13 +234,13 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
// 可以这样! 到时将零散的共享noteId放在用户基本数据中
// 这里不好排序
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)
shareNotes := []info.ShareNote{}
q := this.getOrQ(myUserId)
q["UserId"] = bson.ObjectIdHex(sharedUserId)
q["UserId"] = bson.ObjectIdHex(sharedUserId);
db.ShareNotes.
Find(q).
@@ -297,7 +284,7 @@ func (this *ShareService) notes2NotesWithPerm(notes []info.Note) {
// [ok]
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()
return db.Insert(db.ShareNotebooks, shareNotebook)
@@ -310,19 +297,15 @@ func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId,
if toUserId == "" {
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),
"UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId),
})
});
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
UserId: bson.ObjectIdHex(userId),
@@ -347,19 +330,16 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
if toUserId == "" {
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),
"UserId": bson.ObjectIdHex(userId),
"ToUserId": bson.ObjectIdHex(toUserId),
})
});
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
UserId: bson.ObjectIdHex(userId),
@@ -367,9 +347,11 @@ func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId,
Perm: perm,
CreatedTime: time.Now(),
}
return db.Insert(db.ShareNotes, shareNote), "", toUserId
}
// updatedUserId是否有查看userId noteId的权限?
// userId是所有者
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
@@ -442,14 +424,13 @@ func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookI
// 共享note, notebook时使用
func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
db.Insert(db.HasShareNotes, info.HasShareNote{UserId: bson.ObjectIdHex(userId), ToUserId: bson.ObjectIdHex(toUserId)})
return true
return true;
}
// userId是否被共享了noteId
func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
}
// noteId的notebook是否共享了给我
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
notebookId := noteService.GetNotebookId(noteId)
@@ -468,12 +449,11 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
noteContent = info.NoteContent{}
// 是否单独共享了该notebook
// 或者, 其notebook共享了我
// Log(this.HasSharedNote(noteId, myUserId))
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
// Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
// Log(this.HasSharedNote(noteId, myUserId))
// 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) {
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
db.Get(db.NoteContents, noteId, &noteContent)
} else {
}
@@ -494,8 +474,8 @@ func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.Sh
"ToGroupId": bson.M{"$exists": false},
}, &shareNotes, 100)
// Log("<<>>>>")
// Log(len(shareNotes))
// Log("<<>>>>")
// Log(len(shareNotes))
if len(shareNotes) == 0 {
return nil
@@ -592,6 +572,7 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
return shareUserInfos
}
//----------------
// 改变note share权限
func (this *ShareService) UpdateShareNotePerm(noteId string, perm int, userId, toUserId string) bool {
@@ -622,7 +603,6 @@ func (this *ShareService) DeleteShareNoteAll(noteId string, userId string) bool
return db.DeleteAll(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)})
}
// 删除share notebook
func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserId string) bool {
return db.DeleteAll(db.ShareNotebooks,
@@ -632,9 +612,9 @@ func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserI
// 删除userId分享给toUserId的所有
func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool {
query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)}
db.DeleteAll(db.ShareNotebooks, query)
db.DeleteAll(db.ShareNotes, query)
db.DeleteAll(db.HasShareNotes, query)
db.DeleteAll(db.ShareNotebooks, query);
db.DeleteAll(db.ShareNotes, query);
db.DeleteAll(db.HasShareNotes, query);
return true
}
@@ -642,10 +622,10 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
// 用户userId是否有修改noteId的权限
func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false
return false;
}
note := noteService.GetNoteById(noteId)
LogJ(note)
LogJ(note);
if note.UserId != "" {
noteUserId := note.UserId.Hex()
if noteUserId != userId {
@@ -653,20 +633,20 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
if this.HasUpdatePerm(noteUserId, userId, noteId) {
return true
} else {
return false
return false;
}
} else {
return true
}
} else {
return false
return false;
}
}
// 用户userId是否有查看noteId的权限
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if noteId == "" || userId == "" {
return false
return false;
}
note := noteService.GetNoteById(noteId)
if note.UserId != "" {
@@ -676,13 +656,13 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
if this.HasReadPerm(noteUserId, userId, noteId) {
return true
} else {
return false
return false;
}
} else {
return true
}
} else {
return false
return false;
}
}
@@ -691,12 +671,13 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
// 得到笔记分享给的groups
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
groups := groupService.GetGroupsContainOf(userId)
// 得到分组s
groups := groupService.GetGroups(userId)
// 得到有分享的分组
shares := []info.ShareNote{}
db.ListByQ(db.ShareNotes,
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
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
@@ -709,7 +690,7 @@ func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.Share
if !ok {
share = info.ShareNote{}
}
share.ToGroup = group
share.ToGroup = group;
shares2[i] = share
}
@@ -717,8 +698,10 @@ func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.Share
}
// 共享笔记给分组
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
// 得到group, 是否是我的group
group := groupService.GetGroup(userId, groupId)
if group.GroupId == "" {
return false
}
@@ -739,19 +722,20 @@ func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) b
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)
// 得到分组s
groups := groupService.GetGroups(userId)
// 得到有分享的分组
shares := []info.ShareNotebook{}
db.ListByQ(db.ShareNotebooks,
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists": true}}, &shares)
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
@@ -765,16 +749,17 @@ func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []in
if !ok {
share = info.ShareNotebook{}
}
share.ToGroup = group
share.ToGroup = group;
shares2[i] = share
}
return shares2
}
// 共享笔记给分组
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) bool {
if !groupService.IsExistsGroupUser(userId, groupId) {
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
// 得到group, 是否是我的group
group := groupService.GetGroup(userId, groupId)
if group.GroupId == "" {
return false
}
@@ -795,38 +780,61 @@ func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId s
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) GenSharePass(noteId string) (int, bool) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
pass := 1000 + r.Intn(9000)
ok := db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$set": bson.M{"SharePass": pass}})
return pass, ok
}
//--------------------
// 删除组内用户时, 删除其分享的
//--------------------
func (this *ShareService) QuerySharePass(noteId string) int {
note := &info.Note{}
db.Get(db.Notes, noteId, note)
func (this *ShareService) DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotebooks, bson.M{
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
return note.SharePass
}
func (this *ShareService) DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId string) bool {
return db.Delete(db.ShareNotes, bson.M{
"UserId": bson.ObjectIdHex(userId),
"ToGroupId": bson.ObjectIdHex(groupId),
})
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
note = info.Note{}
db.Get(db.Notes, noteId, &note)
if note.SharePass == sharePass {
note = noteService.GetNoteById(noteId)
noteContent = noteService.GetNoteContent(noteId, note.UserId.Hex())
flag = true
} else {
note = info.Note{}
noteContent = info.NoteContent{}
flag = false
}
return
}
//把笔记中含有attachID的url后加上token,返回笔记中含有的attachids
func (this *ShareService) AppendToken4URL(token, content string) (c string, attachIds map[string]bool) {
re := regexp.MustCompile(`href=\"(.*?attachId.*?)\".*?data-mce-href=\"(.*?attachId.*?)\"`)
re2 := regexp.MustCompile(`\"(.*?attachId.*?)\"`)
attachIds = map[string]bool{}
s := re.ReplaceAllStringFunc(content, func(m string) string {
idx := strings.Index(m, "attachId=") + len("attachId=")
var ss []byte = []byte(m)
attachId := string(ss[idx: idx + 24])
attachIds[attachId] = true
return re2.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
re3 := regexp.MustCompile(`<img\s+src=\"(.*?fileId.*?)\".*?data-mce-src=\"(.*?fileId.*?)\"`)
re4 := regexp.MustCompile(`\"(.*?fileId.*?)\"`)
c = re3.ReplaceAllStringFunc(s, func(m string) string {
return re4.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
return
}
Loaded 100 of 3232 files, more files were not shown because too many files have changed in this diff. Show more