Compare commits
11
Commits
1.0
..
dev-binnchx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb484b2132 | ||
|
|
4d5a3ffd0f | ||
|
|
f78eb4db49 | ||
|
|
c35aa1eaa4 | ||
|
|
96b094844e | ||
|
|
9af13bcc32 | ||
|
|
29215a1d64 | ||
|
|
d828a10e7b | ||
|
|
a851aaa399 | ||
|
|
a393bb8723 | ||
|
|
599e54de5b |
No files matched your search
+3
-4
@@ -2,9 +2,9 @@
|
|||||||
pkg
|
pkg
|
||||||
bin2
|
bin2
|
||||||
bin/i18n
|
bin/i18n
|
||||||
bin/leanote*
|
bin/leanote-linux
|
||||||
|
bin/leanote-mac
|
||||||
bin/release
|
bin/release
|
||||||
bin/test.sh
|
|
||||||
bin/tmp
|
bin/tmp
|
||||||
bin/test
|
bin/test
|
||||||
bin/src
|
bin/src
|
||||||
@@ -16,5 +16,4 @@ app/tmp/main.go
|
|||||||
.project
|
.project
|
||||||
public/config.codekit
|
public/config.codekit
|
||||||
files
|
files
|
||||||
/gulpfile.js
|
conf/app.conf
|
||||||
/node_modules
|
|
||||||
@@ -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>
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
## 1. Introduction
|
## 1. Introduction
|
||||||
|
|
||||||
Leanote, not just a notepad!
|
Leanote, not just a notebook!
|
||||||

|

|
||||||
|
|
||||||
**Some Features**
|
**Some Features**
|
||||||
@@ -26,40 +26,83 @@ 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 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 develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
||||||
|
|
||||||
|
### 3.1. Download leanote
|
||||||
|
|
||||||
|
Leanote V1.0.2-beta has been released. Binaries:
|
||||||
|
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
Or you can clone [Leanote bin repository](https://github.com/leanote/leanote-bin) (Recommend)
|
||||||
|
|
||||||
|
### 3.2. Install MongoDB
|
||||||
|
|
||||||
|
Leanote is written in go using [revel](https://revel.github.io/) and [MongoDB](https://www.mongodb.org). Thus, you need to first install MongoDB.
|
||||||
|
|
||||||
|
For more tips please have a look at [our wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
|
### 3.3. Import initial MongoDB data
|
||||||
|
|
||||||
|
The mongodb data is in `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
|
The initial database contains two users:
|
||||||
|
|
||||||
|
```
|
||||||
|
user2 username: admin, password: abc123 (administrator)
|
||||||
|
user3 username: demo, password: demo@leanote.com (this user is for demo)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4. Configuration
|
||||||
|
|
||||||
|
Modify `[PATH_TO_LEANOTE]/conf/app.conf`. Available configuration options are:
|
||||||
|
|
||||||
|
``mongodb`` **required**
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
db.host=localhost
|
||||||
|
db.port=27017
|
||||||
|
db.dbname=leanote
|
||||||
|
db.username=
|
||||||
|
db.password=
|
||||||
|
```
|
||||||
|
|
||||||
|
``app.secret`` **required** **important**
|
||||||
|
The secret key used for cryptographic operations (revel.Sign).
|
||||||
|
|
||||||
|
FOR SECURITY, YOU MUST CHANGE IT!!
|
||||||
|
|
||||||
|
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
|
||||||
|
|
||||||
|
### 3.5. Run leanote
|
||||||
|
|
||||||
|
```
|
||||||
|
$> cd PATH_TO_LEANOTE/bin
|
||||||
|
$> sudo sh run.sh
|
||||||
|
```
|
||||||
|
|
||||||
## 4. How to develop leanote
|
## 4. How to develop leanote
|
||||||
|
|
||||||
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
|
|
||||||
## 5. Docs
|
## 5. Contributors
|
||||||
|
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
||||||
|
this project. Your help is much appreciated.
|
||||||
|
|
||||||
|
## 6. Contributing
|
||||||
|
|
||||||
|
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||||
|
|
||||||
|
## Docs
|
||||||
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
* [leanote 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 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)
|
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
|
||||||
|
|
||||||
More docs please see [wiki](https://github.com/leanote/leanote/wiki).
|
## Discussion
|
||||||
|
|
||||||
## 6. Contributors
|
|
||||||
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
|
||||||
this project. Your help is much appreciated.
|
|
||||||
|
|
||||||
## 7.Join us
|
|
||||||
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
|
||||||
|
|
||||||
If you find some problems or has some good ideas, please submit [issues](https://github.com/leanote/leanote/issues).
|
|
||||||
|
|
||||||
You are always welcomed!
|
|
||||||
|
|
||||||
## 8. Donation
|
|
||||||
Support us, [donate us](http://leanote.org/#donate). And thanks [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), development phase
|
|
||||||
* [Leanote Android](https://github.com/Dminter/leanote-android-client), development phase
|
|
||||||
|
|
||||||
And also, you are welcome to join us.
|
|
||||||
|
|
||||||
## 9. Discussion
|
|
||||||
* [leanote bbs](http://bbs.leanote.com)
|
* [leanote bbs](http://bbs.leanote.com)
|
||||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
* QQ Group: 158716820
|
* QQ Group: 158716820
|
||||||
|
|||||||
+87
-44
@@ -1,69 +1,112 @@
|
|||||||
# Leanote产品
|
|
||||||
|
|
||||||
## 1. 介绍
|
# Leanote产品
|
||||||
|
|
||||||
Leanote, 不只是笔记!
|
## 1. 介绍
|
||||||
|
|
||||||
|
Leanote, 不只是笔记!
|
||||||

|

|
||||||
|
|
||||||
**特性**
|
**特性**
|
||||||
|
|
||||||
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||||
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||||
|
|
||||||
## 2. 为什么我们要创建leanote?
|
## 2. 为什么我们要创建leanote?
|
||||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||||
* 还有...
|
* 还有...
|
||||||
|
|
||||||
## 3.安装leanote
|
## 3.安装leanote
|
||||||
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||||
|
|
||||||
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||||
|
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
|
||||||
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
### 3.1. 下载leanote
|
||||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
|
|
||||||
## 4. 如何对leanote进行二次开发
|
Leanote V1.0-beta.2 已发布, 二进制文件(暂时没有windows版的):
|
||||||
|
|
||||||
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
|
||||||
## 5 相关文档
|
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
|
||||||
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
|
||||||
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
|
||||||
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
|
||||||
|
|
||||||
更多文档请查看 [wiki](https://github.com/leanote/leanote/wiki).
|
### 3.2. 安装 MongodbDB
|
||||||
|
|
||||||
## 6. 贡献者
|
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||||
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
|
||||||
|
|
||||||
## 7. 加入我们
|
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
### 3.3. 导入初始数据
|
||||||
|
|
||||||
有任何问题或建议, 欢迎提交[issue](https://github.com/leanote/leanote/issues).
|
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
## 8. 捐赠
|
初始数据包含两个用户:
|
||||||
支持我们, [捐赠Leanote](http://leanote.org/#donate). 感谢[捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
|
|
||||||
|
|
||||||
## 9. 其它相关项目
|
```
|
||||||
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
|
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||||
* [Leanote IOS](https://github.com/leanote/leanote-ios), 开发阶段
|
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||||
* [Leanote Android](https://github.com/Dminter/leanote-android-client), 开发阶段
|
```
|
||||||
|
|
||||||
同样, 欢迎加入我们!
|
### 3.4. 配置
|
||||||
|
|
||||||
## 讨论
|
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||||
* [leanote 社区](http://bbs.leanote.com)
|
|
||||||
* QQ群: 158716820
|
``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)
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
|||||||
id := bson.NewObjectId();
|
id := bson.NewObjectId();
|
||||||
fileInfo.AttachId = id
|
fileInfo.AttachId = id
|
||||||
fileId = id.Hex()
|
fileId = id.Hex()
|
||||||
Ok, resultMsg = attachService.AddAttach(fileInfo, false)
|
Ok, resultMsg = attachService.AddAttach(fileInfo)
|
||||||
if resultMsg != "" {
|
if resultMsg != "" {
|
||||||
resultMsg = c.Message(resultMsg)
|
resultMsg = c.Message(resultMsg)
|
||||||
}
|
}
|
||||||
@@ -129,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
|
|||||||
|
|
||||||
// 下载附件
|
// 下载附件
|
||||||
// 权限判断
|
// 权限判断
|
||||||
func (c Attach) Download(attachId string) revel.Result {
|
func (c Attach) Download(attachId, token string) revel.Result {
|
||||||
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
|
if c.GetUserId() == "" && token == "" {
|
||||||
|
return c.RenderText("你需要从分享页面下载附件!")
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
|
||||||
path := attach.Path
|
path := attach.Path
|
||||||
|
|
||||||
|
if token != "" && attach.Path == "" {
|
||||||
|
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
|
||||||
|
}
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return c.RenderText("")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
// "strconv"
|
// "strconv"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
// 用户登录/注销/找回密码
|
||||||
@@ -40,7 +41,7 @@ func (c Auth) Login(email, from string) revel.Result {
|
|||||||
func (c Auth) doLogin(email, pwd string) revel.Result {
|
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.Id()
|
||||||
var msg = ""
|
var msg = ""
|
||||||
|
fmt.Println(sessionId)
|
||||||
userInfo := authService.Login(email, pwd)
|
userInfo := authService.Login(email, pwd)
|
||||||
if userInfo.Email != "" {
|
if userInfo.Email != "" {
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
@@ -55,8 +56,8 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
|
|||||||
}
|
}
|
||||||
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.Id()
|
||||||
var msg = ""
|
|
||||||
|
|
||||||
|
var msg = ""
|
||||||
// > 5次需要验证码, 直到登录成功
|
// > 5次需要验证码, 直到登录成功
|
||||||
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||||
msg = "captchaError"
|
msg = "captchaError"
|
||||||
@@ -85,15 +86,9 @@ func (c Auth) Logout() revel.Result {
|
|||||||
|
|
||||||
// 体验一下
|
// 体验一下
|
||||||
func (c Auth) Demo() revel.Result {
|
func (c Auth) Demo() revel.Result {
|
||||||
email := configService.GetGlobalStringConfig("demoPassword")
|
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
|
||||||
pwd := configService.GetGlobalStringConfig("demoPassword");
|
|
||||||
userInfo := authService.Login(email, pwd)
|
|
||||||
if userInfo.Email != "" {
|
|
||||||
c.SetSession(userInfo)
|
|
||||||
return c.Redirect("/note")
|
return c.Redirect("/note")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
// 注册
|
// 注册
|
||||||
|
|||||||
@@ -200,77 +200,29 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
cates := make([]*info.Cate, len(notebooks))
|
cates := make([]map[string]string, len(notebooks))
|
||||||
|
|
||||||
// 先要保证已有的是正确的排序
|
// 先要保证已有的是正确的排序
|
||||||
cateIds := userBlog.CateIds
|
cateIds := userBlog.CateIds
|
||||||
has := map[string]bool{} // cateIds中有的
|
has := map[string]bool{} // cateIds中有的
|
||||||
cateMap := map[string]*info.Cate{}
|
|
||||||
if cateIds != nil && len(cateIds) > 0 {
|
if cateIds != nil && len(cateIds) > 0 {
|
||||||
for _, cateId := range cateIds {
|
for _, cateId := range cateIds {
|
||||||
if n, ok := notebooksMap[cateId]; ok {
|
if n, ok := notebooksMap[cateId]; ok {
|
||||||
parentNotebookId := ""
|
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": n.NotebookId.Hex()}
|
||||||
if n.ParentNotebookId != "" {
|
|
||||||
parentNotebookId = n.ParentNotebookId.Hex()
|
|
||||||
}
|
|
||||||
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: n.NotebookId.Hex(), ParentCateId: parentNotebookId}
|
|
||||||
cateMap[cates[i].CateId] = cates[i]
|
|
||||||
i++
|
i++
|
||||||
has[cateId] = true
|
has[cateId] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 之后
|
||||||
// 之后添加没有排序的
|
|
||||||
for _, n := range notebooks {
|
for _, n := range notebooks {
|
||||||
id := n.NotebookId.Hex()
|
id := n.NotebookId.Hex()
|
||||||
if !has[id] {
|
if !has[id] {
|
||||||
parentNotebookId := ""
|
cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": id}
|
||||||
if n.ParentNotebookId != "" {
|
|
||||||
parentNotebookId = n.ParentNotebookId.Hex()
|
|
||||||
}
|
|
||||||
cates[i] = &info.Cate{Title: n.Title, UrlTitle: c.getCateUrlTitle(&n), CateId: id, ParentCateId: parentNotebookId}
|
|
||||||
cateMap[cates[i].CateId] = cates[i]
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogJ(">>")
|
|
||||||
// LogJ(cates)
|
|
||||||
|
|
||||||
// 建立层级
|
|
||||||
hasParent := map[string]bool{} // 有父的cate
|
|
||||||
for _, cate := range cates {
|
|
||||||
parentCateId := cate.ParentCateId
|
|
||||||
if parentCateId != "" {
|
|
||||||
if parentCate, ok := cateMap[parentCateId]; ok {
|
|
||||||
// Log("________")
|
|
||||||
// LogJ(parentCate)
|
|
||||||
// LogJ(cate)
|
|
||||||
if parentCate.Children == nil {
|
|
||||||
parentCate.Children = []*info.Cate{cate}
|
|
||||||
} else {
|
|
||||||
parentCate.Children = append(parentCate.Children, cate)
|
|
||||||
}
|
|
||||||
hasParent[cate.CateId] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到没有父的cate, 作为第一级cate
|
|
||||||
catesTree := []*info.Cate{}
|
|
||||||
for _, cate := range cates {
|
|
||||||
if !hasParent[cate.CateId] {
|
|
||||||
catesTree = append(catesTree, cate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log("cates")
|
|
||||||
LogJ(cates)
|
|
||||||
LogJ(catesTree);
|
|
||||||
|
|
||||||
c.RenderArgs["cates"] = cates
|
c.RenderArgs["cates"] = cates
|
||||||
c.RenderArgs["catesTree"] = catesTree
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单页
|
// 单页
|
||||||
@@ -588,14 +540,19 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
|
|||||||
}
|
}
|
||||||
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
|
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
|
||||||
var ok = false
|
var ok = false
|
||||||
|
fmt.Println("before test...");
|
||||||
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
||||||
|
fmt.Println("404 occur");
|
||||||
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
||||||
}
|
}
|
||||||
|
fmt.Println("after test0...");
|
||||||
// 分页的话, 需要分页信息, totalPage, curPage
|
// 分页的话, 需要分页信息, totalPage, curPage
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
|
|
||||||
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
|
|
||||||
blogs2 := blogService.FixBlogs(blogs)
|
blogs2 := blogService.FixBlogs(blogs)
|
||||||
|
|
||||||
c.RenderArgs["posts"] = blogs2
|
c.RenderArgs["posts"] = blogs2
|
||||||
|
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
@@ -603,6 +560,7 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
|
|||||||
|
|
||||||
c.RenderArgs["curIsIndex"] = true
|
c.RenderArgs["curIsIndex"] = true
|
||||||
|
|
||||||
|
|
||||||
return c.render("index.html", userBlog.ThemePath)
|
return c.render("index.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,7 +782,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
|
|||||||
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJsonP(callback, re)
|
||||||
}
|
}
|
||||||
func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
func (c Blog) GetComments(noteId string) revel.Result {
|
||||||
// 评论
|
// 评论
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
@@ -837,10 +795,6 @@ func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
|||||||
result["commentUserInfo"] = commentUserInfo
|
result["commentUserInfo"] = commentUserInfo
|
||||||
re.Item = result
|
re.Item = result
|
||||||
|
|
||||||
if callback != "" {
|
|
||||||
return c.RenderJsonP(callback, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"fmt"
|
|
||||||
// "strconv"
|
// "strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -208,8 +208,9 @@ func (c File) DeleteImage(fileId string) revel.Result {
|
|||||||
|
|
||||||
// 输出image
|
// 输出image
|
||||||
// 权限判断
|
// 权限判断
|
||||||
func (c File) OutputImage(noteId, fileId string) revel.Result {
|
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
|
||||||
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
|
sessionId := c.Session.Id()
|
||||||
|
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return c.RenderText("")
|
return c.RenderText("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"strings"
|
"os/exec"
|
||||||
// "time"
|
// "time"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
@@ -49,11 +49,10 @@ func (c Note) Index(noteId string) revel.Result {
|
|||||||
hasRightNoteId := false
|
hasRightNoteId := false
|
||||||
if IsObjectId(noteId) {
|
if IsObjectId(noteId) {
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
|
|
||||||
if note.NoteId != "" {
|
|
||||||
var noteOwner = note.UserId.Hex()
|
var noteOwner = note.UserId.Hex()
|
||||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||||
|
|
||||||
|
if note.NoteId != "" {
|
||||||
hasRightNoteId = true
|
hasRightNoteId = true
|
||||||
c.RenderArgs["curNoteId"] = noteId
|
c.RenderArgs["curNoteId"] = noteId
|
||||||
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
||||||
@@ -125,7 +124,9 @@ func (c Note) Index(noteId string) revel.Result {
|
|||||||
|
|
||||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
|
|
||||||
|
|
||||||
// return c.RenderTemplate("note/note.html")
|
// return c.RenderTemplate("note/note.html")
|
||||||
|
|
||||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||||
return c.RenderTemplate("note/note-dev.html")
|
return c.RenderTemplate("note/note-dev.html")
|
||||||
} else {
|
} else {
|
||||||
@@ -168,7 +169,7 @@ type NoteOrContent struct {
|
|||||||
Title string
|
Title string
|
||||||
Desc string
|
Desc string
|
||||||
ImgSrc string
|
ImgSrc string
|
||||||
Tags string
|
Tags []string
|
||||||
Content string
|
Content string
|
||||||
Abstract string
|
Abstract string
|
||||||
IsNew bool
|
IsNew bool
|
||||||
@@ -191,7 +192,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||||
Title: noteOrContent.Title,
|
Title: noteOrContent.Title,
|
||||||
Tags: strings.Split(noteOrContent.Tags, ","),
|
Tags: noteOrContent.Tags,
|
||||||
Desc: noteOrContent.Desc,
|
Desc: noteOrContent.Desc,
|
||||||
ImgSrc: noteOrContent.ImgSrc,
|
ImgSrc: noteOrContent.ImgSrc,
|
||||||
IsBlog: noteOrContent.IsBlog,
|
IsBlog: noteOrContent.IsBlog,
|
||||||
@@ -224,31 +225,22 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
noteUpdate["Title"] = noteOrContent.Title;
|
noteUpdate["Title"] = noteOrContent.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Has("Tags") {
|
if c.Has("Tags[]") {
|
||||||
needUpdateNote = true
|
needUpdateNote = true
|
||||||
noteUpdate["Tags"] = strings.Split(noteOrContent.Tags, ",");
|
noteUpdate["Tags"] = noteOrContent.Tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// web端不控制
|
|
||||||
if needUpdateNote {
|
if needUpdateNote {
|
||||||
noteService.UpdateNote(c.GetUserId(),
|
noteService.UpdateNote(noteOrContent.UserId, c.GetUserId(),
|
||||||
noteOrContent.NoteId, noteUpdate, -1)
|
noteOrContent.NoteId, noteUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------
|
//-------------
|
||||||
afterContentUsn := 0
|
|
||||||
contentOk := false
|
|
||||||
contentMsg := ""
|
|
||||||
if c.Has("Content") {
|
|
||||||
// noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
|
||||||
// noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
|
||||||
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.GetUserId(),
|
|
||||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(afterContentUsn)
|
if c.Has("Content") {
|
||||||
Log(contentOk)
|
noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
||||||
Log(contentMsg)
|
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
||||||
|
}
|
||||||
|
|
||||||
return c.RenderJson(true)
|
return c.RenderJson(true)
|
||||||
}
|
}
|
||||||
@@ -292,6 +284,135 @@ func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
|||||||
return c.RenderJson(blogs)
|
return c.RenderJson(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------
|
||||||
|
// 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("")
|
||||||
|
}
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.NoteId == "" {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
|
c.RenderArgs["blog"] = note
|
||||||
|
c.RenderArgs["content"] = content.Content
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
return c.RenderTemplate("html2Image/index.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
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.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
// 是否有权限
|
||||||
|
if noteUserId != userId {
|
||||||
|
// 是否是有权限协作的
|
||||||
|
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
||||||
|
re.Msg = "No Perm"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// path 判断是否需要重新生成之
|
||||||
|
fileUrlPath := "/upload/" + noteUserId + "/images/weibo"
|
||||||
|
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||||
|
if !ClearDir(dir) {
|
||||||
|
re.Msg = "No Dir"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := note.NoteId.Hex() + ".png";
|
||||||
|
path := dir + "/" + filename
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
// 生成之
|
||||||
|
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 == "" {
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
cc := binPath + " \"" + url + "\" \"" + path + "\" \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
|
Log(cc);
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
re.Ok = true
|
||||||
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
re.Msg = string(b)
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 这里速度慢, 生成不完全(图片和内容都不全)
|
||||||
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
c.RenderArgs["blog"] = note
|
||||||
|
c.RenderArgs["content"] = content.Content
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
html := c.RenderTemplateStr("html2Image/index.html") // Result类型的
|
||||||
|
contentFile := dir + "/html";
|
||||||
|
fout, err := os.Create(contentFile)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
fout.WriteString(html);
|
||||||
|
fout.Close()
|
||||||
|
|
||||||
|
cc := "/Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/c.js \"" + contentFile + "\" \"" + path + "\""
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
re.Ok = true
|
||||||
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 设置/取消Blog; 置顶
|
// 设置/取消Blog; 置顶
|
||||||
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||||
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.
|
|||||||
if(parentNotebookId != "") {
|
if(parentNotebookId != "") {
|
||||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
||||||
}
|
}
|
||||||
|
re := notebookService.AddNotebook(notebook)
|
||||||
re, notebook := notebookService.AddNotebook(notebook)
|
|
||||||
|
|
||||||
if(re) {
|
if(re) {
|
||||||
return c.RenderJson(notebook)
|
return c.RenderJson(notebook)
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.google.com/p/goauth2/oauth"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/lea/netutil"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Oauth struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
var oauthCfg = &oauth.Config{
|
||||||
|
ClientId: "3790fbf1fc14bc6c5d85",
|
||||||
|
ClientSecret: "e9dadfe601c7caa6df9b33db3e7539945c60dfa2",
|
||||||
|
AuthURL: "https://github.com/login/oauth/authorize",
|
||||||
|
TokenURL: "https://github.com/login/oauth/access_token",
|
||||||
|
RedirectURL: "http://leanote.com/oauth/githubCallback",
|
||||||
|
Scope: "user",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户允许后, github返回到leanote
|
||||||
|
// 通过code得到token
|
||||||
|
// https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Foauth2callback&response_type=code&scope=user&state=
|
||||||
|
func (c Oauth) GithubCallback(code string) revel.Result {
|
||||||
|
t := &oauth.Transport{Config: oauthCfg}
|
||||||
|
|
||||||
|
// Exchange the received code for a token
|
||||||
|
tok, err := t.Exchange(code)
|
||||||
|
token := tok.AccessToken
|
||||||
|
if err != nil || token == "" {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户信息
|
||||||
|
profileInfoURL := "https://api.github.com/user"
|
||||||
|
url := fmt.Sprintf("%s?access_token=%s", profileInfoURL, token)
|
||||||
|
content, err2 := netutil.GetContent(url)
|
||||||
|
if err2 != nil {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
// 转成map
|
||||||
|
profileInfo := map[string]interface{}{}
|
||||||
|
Log(string(content))
|
||||||
|
err2 = json.Unmarshal(content, &profileInfo)
|
||||||
|
if err2 != nil {
|
||||||
|
c.RenderArgs["title"] = "error"
|
||||||
|
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameI := profileInfo["login"]
|
||||||
|
|
||||||
|
username, _ := usernameI.(string)
|
||||||
|
userId := username
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
isExists, userInfo := authService.ThirdRegister("github", userId, username)
|
||||||
|
c.RenderArgs["isExists"] = isExists
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
|
// 登录之
|
||||||
|
c.SetSession(userInfo)
|
||||||
|
|
||||||
|
return c.Redirect("/note")
|
||||||
|
}
|
||||||
@@ -9,12 +9,15 @@ import (
|
|||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Share struct {
|
type Share struct {
|
||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AttachToken = 2
|
||||||
|
|
||||||
// 添加共享note
|
// 添加共享note
|
||||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -36,6 +39,8 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
|||||||
return c.RenderJson(status)
|
return c.RenderJson(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 添加共享notebook
|
// 添加共享notebook
|
||||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -186,3 +191,63 @@ func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result
|
|||||||
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||||
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//生成笔记分享密码及更新到db
|
||||||
|
func (c Share) GenShareLinkPass(noteId string) revel.Result {
|
||||||
|
pass, ok := shareService.GenSharePass(noteId)
|
||||||
|
re := info.Re{Ok : true, Item : pass, List: ok}
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Share) QuerySharePass(noteId string) revel.Result {
|
||||||
|
pass := shareService.QuerySharePass(noteId)
|
||||||
|
re := info.Re{Ok : true, Item : pass}
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
//展示分享笔记
|
||||||
|
func (c Share) ShowShareNote(noteId string) revel.Result {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
//
|
||||||
|
c.RenderArgs["noteId"] = noteId
|
||||||
|
username := userService.GetUsernameById(note.UserId)
|
||||||
|
|
||||||
|
c.RenderArgs["userName"] = username
|
||||||
|
c.RenderArgs["isMarkDown"] = note.IsMarkdown
|
||||||
|
// c.RenderArgs["timestamp"] = time.Now().Unix()
|
||||||
|
c.SetLocale()
|
||||||
|
return c.RenderTemplate("share/show_share_note.html")
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证分享密码
|
||||||
|
func (c Share) Verify4ShareNote(noteId string, sharePass int) revel.Result {
|
||||||
|
ok, note, noteContent := shareService.Verify4ShareNote(noteId, sharePass)
|
||||||
|
|
||||||
|
attaches := []info.Attach{}
|
||||||
|
if ok && note.AttachNum > 0 {
|
||||||
|
attaches = attachService.ListAttachs(noteId, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
token := tokenService.NewToken(noteId, noteId, AttachToken)
|
||||||
|
|
||||||
|
//插入笔记作为链接中的附件
|
||||||
|
noteAttachIds := map[string]bool{}
|
||||||
|
noteContent.Content, noteAttachIds = shareService.AppendToken4URL(token, noteContent.Content)
|
||||||
|
//过滤掉插入笔记的附件
|
||||||
|
filteredAttaches := []info.Attach{}
|
||||||
|
if len(noteAttachIds) > 0 && len(attaches) > 0 {
|
||||||
|
for _, attach := range attaches {
|
||||||
|
if !noteAttachIds[attach.AttachId.Hex()] {
|
||||||
|
filteredAttaches = append(filteredAttaches, attach)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filteredAttaches = attaches
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
sessionService.SetToken(sessionId, token)
|
||||||
|
re := info.Re{Ok : ok, Item: note, List: filteredAttaches, Id: token, Msg: noteContent.Content}
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
// "os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Tag struct {
|
|
||||||
BaseController
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新Tag
|
|
||||||
func (c Tag) UpdateTag(tag string) revel.Result {
|
|
||||||
ret := info.NewRe()
|
|
||||||
ret.Ok = true
|
|
||||||
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
func (c Tag) DeleteTag(tag string) revel.Result {
|
|
||||||
ret := info.Re{}
|
|
||||||
ret.Ok = true
|
|
||||||
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
@@ -22,9 +22,3 @@ func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
|||||||
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,465 +0,0 @@
|
|||||||
# API 列表
|
|
||||||
|
|
||||||
## 前言
|
|
||||||
|
|
||||||
### api url
|
|
||||||
|
|
||||||
所有api的url前面带/api/, 如:
|
|
||||||
|
|
||||||
`/api/user/info?userId=xxxx&token=xxxx`
|
|
||||||
|
|
||||||
除了/auth/login, /auth/register外其它的都需要另外带参数token=xxxx
|
|
||||||
|
|
||||||
### 文件目录结构
|
|
||||||
* 所有API的Controller都在app/api文件夹下
|
|
||||||
* 文件命名: Api功能Controller.go, 如ApiUserController.go
|
|
||||||
* 结构体命名为 Api功能, 如ApiUser
|
|
||||||
* API公用Controller: ApiBaseController
|
|
||||||
* init.go 注入service和定义拦截器
|
|
||||||
|
|
||||||
### 流程
|
|
||||||
用户登录后返回一个token, 以后所有的请求都携带该token.
|
|
||||||
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
|
|
||||||
|
|
||||||
## 返回值结构
|
|
||||||
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
|
|
||||||
* 错误信息全部返回 {Ok: false, Msg: "相应的错误信息"}
|
|
||||||
* 正确信息返回分两种:
|
|
||||||
1. 一些操作型的api, 比如updateUsername, updateLogo之类的, 成功后返回 {Ok: true, Msg:""}
|
|
||||||
2. 一些获取型api, 如getNote, 全部返回真实的返回数据, 如返回笔记:
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"NoteId": "54bdc7e305fcd13ea3000000",
|
|
||||||
"NotebookId": "54bdc65599c37b0da9000003",
|
|
||||||
"UserId": "54bdc65599c37b0da9000002",
|
|
||||||
"Title": "笔记标题",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": true,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Usn": 15,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"PublicTime": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
|
|
||||||
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
## Auth 登录与注册
|
|
||||||
|
|
||||||
### /auth/login 登录
|
|
||||||
|
|
||||||
```
|
|
||||||
参数: email, pwd
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {"Ok":false, "Msg":"用户名或密码有误"}
|
|
||||||
正确: 比如:
|
|
||||||
{
|
|
||||||
"Ok":true,
|
|
||||||
"Token":"5500830738f41138e90003232",
|
|
||||||
"UserId":"52d26b4e99c37b609a000001",
|
|
||||||
"Email":"leanote@leanote.com",
|
|
||||||
"Username":"leanote"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
登录成功后将使用token作为之后的请求
|
|
||||||
|
|
||||||
### /auth/logout 注销
|
|
||||||
```
|
|
||||||
参数: token
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /auth/register 注册
|
|
||||||
```
|
|
||||||
参数: email, pwd
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
## User 用户
|
|
||||||
### /user/info 获取用户信息
|
|
||||||
```
|
|
||||||
参数: userId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.User
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updateUsername 修改用户名
|
|
||||||
```
|
|
||||||
参数: username(新用户名)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updatePwd 修改密码
|
|
||||||
```
|
|
||||||
参数: oldPwd(旧密码), pwd(新密码)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/updateLogo 修改头像
|
|
||||||
```
|
|
||||||
参数: file(文件)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {Ok: true, Msg: ""}
|
|
||||||
```
|
|
||||||
|
|
||||||
### /user/getSyncState 获取最新同步状态
|
|
||||||
```
|
|
||||||
参数: 无
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: {LastSyncUsn: 3232, LastSyncTime: "上次同步时间"(暂时无用)}
|
|
||||||
```
|
|
||||||
|
|
||||||
-----
|
|
||||||
|
|
||||||
## Notebook 笔记本
|
|
||||||
|
|
||||||
### /notebook/getSyncNotebooks 得到需要同步的笔记本
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的笔记本是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Notebook] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/getNotebooks 得到所有笔记本
|
|
||||||
```
|
|
||||||
无参数
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Notebook] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/addNotebook 添加笔记本
|
|
||||||
```
|
|
||||||
参数: title(string), parentNotebookId(string, 父notebookId, 可空), seq(int) 排列
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg:""}
|
|
||||||
成功: type.Notebook
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/updateNotebook 修改笔记本
|
|
||||||
```
|
|
||||||
参数: notebookId, title, parentNotebookId, seq(int), usn(int)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
|
|
||||||
成功: type.Notebook
|
|
||||||
```
|
|
||||||
|
|
||||||
### /notebook/deleteNotebook 删除笔记本
|
|
||||||
```
|
|
||||||
参数: notebookId, usn(int)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ""} msg == "conflict" 表示冲突
|
|
||||||
成功: {Ok: true}
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Note 笔记
|
|
||||||
|
|
||||||
|
|
||||||
### /note/getSyncNotes 获取需要同步的笔记
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的笔记是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Note] 数组, 笔记不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### /note/getNotes 获得某笔记本下的笔记(无内容)
|
|
||||||
```
|
|
||||||
参数: notebookId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Note] 数组, 笔记不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/getNoteAndContent 获得笔记与内容
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Note
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/getNoteContent 获得笔记内容
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.NoteContent
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/addNote 添加笔记
|
|
||||||
```
|
|
||||||
参数: (注意首字大写)
|
|
||||||
NotebookId string 必传
|
|
||||||
Title string 必传
|
|
||||||
Tags []string 可选
|
|
||||||
Content string 必传
|
|
||||||
Abstract string 可选, 当是markdown笔记时必须传
|
|
||||||
IsMarkdown bool 可选
|
|
||||||
Files []type.NoteFiles 数组 可选
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Note, 不包含Abstract, Content
|
|
||||||
```
|
|
||||||
|
|
||||||
** 关于笔记中的图片/附件**
|
|
||||||
客户端应该添加一个"图片/附件表"来存元数据, 图片应该要缓存到本地, 附件可在需要的时候再调用相应api获取.
|
|
||||||
|
|
||||||
Content中的数据, 图片,附件在Leanote的链接是, 所以, 不管你在本地的笔记中是以什么形式来保存图片,附件的链接的,请addNote和updateNote时务必将链接修改成leanote服务器上的链接.
|
|
||||||
http://leanote.com/api/file/getImage?fileId=xx
|
|
||||||
单个附件:
|
|
||||||
http://leanote.com/api/file/getAttach?fileId=xx
|
|
||||||
所有附件:
|
|
||||||
http://leanote.com/api/file/getAllAttachs?noteId=xxx
|
|
||||||
|
|
||||||
**注意:**
|
|
||||||
addNote时必须要把Files, 和相关的图片/附件一起传到服务器中
|
|
||||||
其中Files(文件的元数据)和其它字段以POST方式传出, 而真正数据则以http的multipart传入, 每个文件的name为"FileDatas[LocalFileId]"
|
|
||||||
|
|
||||||
图片在笔记内的链接必须为: http://leanote.com/api/file/getImage?fileId=LocalFileId或FileId
|
|
||||||
附件如果插入到了笔记内容内, 其链接必须为: http://leanote.com/api/file/getAttach?fileId=LocalFileId或FileId
|
|
||||||
其中, fileId为文件在本地的LocalFileId或服务器上的FileId
|
|
||||||
|
|
||||||
服务器端会生成FileId传给Client. Client在本地必须要建立LocalFileId与FileId的关联.
|
|
||||||
|
|
||||||
如果笔记内容传了, 且笔记内有图片, 则必须要传Files 文件元数据, 因为Server端还要对内容内的图片, 附件链接进行修改, 可能你传过去的是LocalFileId, 服务器端会将LocalFileId替换成FileId存到数据库中.
|
|
||||||
|
|
||||||
同样适用于 updateNote
|
|
||||||
|
|
||||||
http://leanote.com 不绝对, 因为用户可以自建服务, 所以在开发时需要可配置
|
|
||||||
|
|
||||||
### /note/updateNote 更新笔记
|
|
||||||
|
|
||||||
当更新了笔记某个属性时, 只要传某个属性就行, 其它不用传, 比如把笔记拉入了trash, 那么就传IsTrash: true
|
|
||||||
|
|
||||||
```
|
|
||||||
参数: (注意首字大写)
|
|
||||||
NoteId string 必传
|
|
||||||
Usn int 必传
|
|
||||||
NotebookId string 可选
|
|
||||||
Title string 可选
|
|
||||||
Tags []string 可选
|
|
||||||
Content string 可选
|
|
||||||
Abstract string 可选, 当是markdown笔记时必须传
|
|
||||||
IsMarkdown bool 可选
|
|
||||||
IsTrash bool 是否是trash 可选
|
|
||||||
Files []type.NoteFiles 数组 可选
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
|
|
||||||
成功: type.Note, 不包含Abstract和Content
|
|
||||||
```
|
|
||||||
|
|
||||||
### /note/deleteTrash 彻底删除笔记
|
|
||||||
```
|
|
||||||
参数: noteId, usn
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, msg: ''} msg == 'conflict' 表示冲突
|
|
||||||
成功: type.UpdateRet
|
|
||||||
```
|
|
||||||
|
|
||||||
-------
|
|
||||||
|
|
||||||
## Tag 标签
|
|
||||||
|
|
||||||
### /tag/getSyncTags 获取需要同步的标签
|
|
||||||
```
|
|
||||||
参数: afterUsn(int, 在此usn后的标签是需要同步的), maxEntry(int, 最大要同步的量)
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: [type.Tag] 数组
|
|
||||||
```
|
|
||||||
|
|
||||||
### /tag/addTag 添加标签
|
|
||||||
```
|
|
||||||
参数: tag(string)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.Tag
|
|
||||||
```
|
|
||||||
|
|
||||||
### /tag/deleteTag 删除标签
|
|
||||||
```
|
|
||||||
参数: tag(string)
|
|
||||||
Method: POST
|
|
||||||
返回:
|
|
||||||
错误: {Ok: false, Msg: ""}
|
|
||||||
成功: type.UpdateRet
|
|
||||||
```
|
|
||||||
|
|
||||||
### File 文件(获取图片, 附件)
|
|
||||||
|
|
||||||
### /file/getImage 获取图片
|
|
||||||
```
|
|
||||||
参数: fileId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
### /file/getAttach 获取附件
|
|
||||||
```
|
|
||||||
参数: fileId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
### /file/getAllAttachs 获取所有附件
|
|
||||||
```
|
|
||||||
参数: noteId
|
|
||||||
Method: GET
|
|
||||||
返回:
|
|
||||||
错误: 非二进制文件数据
|
|
||||||
成功: 二进制文件
|
|
||||||
```
|
|
||||||
|
|
||||||
--------
|
|
||||||
|
|
||||||
## 数据类型
|
|
||||||
|
|
||||||
### type.User 用户信息
|
|
||||||
|
|
||||||
```
|
|
||||||
User {
|
|
||||||
UserId string
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Verified bool
|
|
||||||
Logo string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Notebook 笔记本
|
|
||||||
|
|
||||||
```
|
|
||||||
Notebook {
|
|
||||||
NotebookId
|
|
||||||
UserId
|
|
||||||
ParentNotebookId // 上级
|
|
||||||
Seq int // 排序
|
|
||||||
Title string
|
|
||||||
IsBlog bool
|
|
||||||
IsDeleted bool
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int // UpdateSequenceNum
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Note 笔记
|
|
||||||
```
|
|
||||||
Note {
|
|
||||||
NoteId string
|
|
||||||
NotebookId string
|
|
||||||
UserId string
|
|
||||||
Title string
|
|
||||||
Tags []string
|
|
||||||
Content string
|
|
||||||
IsMarkdown bool
|
|
||||||
IsBlog bool
|
|
||||||
IsTrash bool
|
|
||||||
Files []NoteFile // 图片, 附件
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
PublicTime time.Time
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.NoteContent 笔记内容
|
|
||||||
```
|
|
||||||
NoteContent {
|
|
||||||
NoteId string
|
|
||||||
UserId string
|
|
||||||
Content string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.NoteFile 笔记文件(图片,附件)
|
|
||||||
```
|
|
||||||
NoteFile {
|
|
||||||
FileId string // 服务器端Id
|
|
||||||
LocalFileId string // 客户端Id
|
|
||||||
Type string // images/png, doc, xls, 根据fileName确定
|
|
||||||
Title string
|
|
||||||
HasBody bool // 传过来的值是否要更新内容, 如果有true, 则必须传文件
|
|
||||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.Tag 标签
|
|
||||||
```
|
|
||||||
Tag {
|
|
||||||
TagId string
|
|
||||||
UserId string
|
|
||||||
Tag string
|
|
||||||
CreatedTime
|
|
||||||
UpdatedTime
|
|
||||||
IsDeleted bool // 删除位
|
|
||||||
// 更新序号
|
|
||||||
Usn
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### type.UpdateRe 更新后返回的值, 包含Usn
|
|
||||||
```
|
|
||||||
ReUpdate {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
|
|
||||||
// 更新序号
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# API设计
|
|
||||||
|
|
||||||
By life (life@leanote.com)
|
|
||||||
|
|
||||||
## api url
|
|
||||||
|
|
||||||
所有api的url前面带/api/, 如:
|
|
||||||
|
|
||||||
`/api/user/info?userId=xxxx&token=xxxx`
|
|
||||||
|
|
||||||
## 文件目录结构
|
|
||||||
* 所有API的Controller都在app/api文件夹下
|
|
||||||
* 文件命名: Api功能Controller.go, 如ApiUserController.go
|
|
||||||
* 结构体命名为 Api功能, 如ApiUser
|
|
||||||
* API公用Controller: ApiBaseController
|
|
||||||
* init.go 注入service和定义拦截器
|
|
||||||
|
|
||||||
## 流程
|
|
||||||
用户登录后返回一个token, 以后所有的请求都携带该token.
|
|
||||||
在init.go中的拦截器会得到token并调用sessionService判断是否登录了
|
|
||||||
|
|
||||||
## 返回值结构
|
|
||||||
* 全部返回JSON, JSON, 除二进制文件(图片, 附件外), 如果返回其它非JSON格式的值, 肯定是出错了
|
|
||||||
* 错误信息全部返回 {Ok: false, Msg: ""}
|
|
||||||
* 正确信息全部返回真实的返回数据, 如返回笔记:
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"NoteId": "54bdc7e305fcd13ea3000000",
|
|
||||||
"NotebookId": "54bdc65599c37b0da9000003",
|
|
||||||
"UserId": "54bdc65599c37b0da9000002",
|
|
||||||
"Title": "asdfads",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": true,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Usn": 15,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"UpdatedTime": "2015-01-20T11:13:41.34+08:00",
|
|
||||||
"PublicTime": "0001-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* 时间类型全是返回如 "2015-01-20T11:13:41.34+08:00" 的格式, (因为golang的time转成Json就是这样, 历史原因)
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
// "strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 用户登录后生成一个token, 将这个token保存到session中
|
|
||||||
// 以后每次的请求必须带这个token, 并从session中获取userId
|
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
|
||||||
|
|
||||||
type ApiAuth struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 登录
|
|
||||||
// [ok]
|
|
||||||
// 成功返回 {Ok: true, Item: token }
|
|
||||||
// 失败返回 {Ok: false, Msg: ""}
|
|
||||||
func (c ApiAuth) Login(email, pwd string) revel.Result {
|
|
||||||
var msg = ""
|
|
||||||
|
|
||||||
userInfo := authService.Login(email, pwd)
|
|
||||||
if userInfo.Email != "" {
|
|
||||||
token := bson.NewObjectId().Hex()
|
|
||||||
sessionService.SetUserId(token, userInfo.UserId.Hex())
|
|
||||||
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
|
|
||||||
} else {
|
|
||||||
// 登录错误, 则错误次数++
|
|
||||||
msg = "wrongUsernameOrPassword"
|
|
||||||
}
|
|
||||||
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注销
|
|
||||||
// [Ok]
|
|
||||||
func (c ApiAuth) Logout() revel.Result {
|
|
||||||
token := c.getToken()
|
|
||||||
sessionService.Clear(token)
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Ok = true
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册
|
|
||||||
// [Ok]
|
|
||||||
// 成功后并不返回用户ID, 需要用户重新登录
|
|
||||||
func (c ApiAuth) Register(email, pwd string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if !configService.IsOpenRegister() {
|
|
||||||
re.Msg = "notOpenRegister" // 未开放注册
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册
|
|
||||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
// "encoding/json"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/leanote/leanote/app/controllers"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"os"
|
|
||||||
// "fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "math"
|
|
||||||
// "strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 公用Controller, 其它Controller继承它
|
|
||||||
type ApiBaseContrller struct {
|
|
||||||
controllers.BaseController // 不能用*BaseController
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到token, 这个token是在AuthInterceptor设到Session中的
|
|
||||||
func (c ApiBaseContrller) getToken() string {
|
|
||||||
return c.Session["_token"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// userId
|
|
||||||
// _userId是在AuthInterceptor设置的
|
|
||||||
func (c ApiBaseContrller) getUserId() string {
|
|
||||||
return c.Session["_userId"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户信息
|
|
||||||
func (c ApiBaseContrller) getUserInfo() info.User {
|
|
||||||
userId := c.Session["_userId"]
|
|
||||||
if userId == "" {
|
|
||||||
return info.User{}
|
|
||||||
}
|
|
||||||
return userService.GetUserInfo(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传附件
|
|
||||||
func (c ApiBaseContrller) uploadAttach(name string, noteId string) (ok bool, msg string, id string) {
|
|
||||||
userId := c.getUserId();
|
|
||||||
|
|
||||||
// 判断是否有权限为笔记添加附件
|
|
||||||
// 如果笔记还没有添加是不是会有问题
|
|
||||||
/*
|
|
||||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
file, handel, err := c.Request.FormFile(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// > 5M?
|
|
||||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
|
||||||
if maxFileSize <= 0 {
|
|
||||||
maxFileSize = 1000
|
|
||||||
}
|
|
||||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成上传路径
|
|
||||||
filePath := "files/" + userId + "/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()
|
|
||||||
// 生成上传路径
|
|
||||||
fileUrlPath := "files/" + c.getUserId() + "/images"
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
err = os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 生成新的文件名
|
|
||||||
filename := handel.Filename
|
|
||||||
_, ext := SplitFilename(filename)
|
|
||||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
|
||||||
msg = "notImage"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = NewGuid() + ext
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
maxFileSize := configService.GetUploadSize("uploadImageSize");
|
|
||||||
if maxFileSize <= 0 {
|
|
||||||
maxFileSize = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// > 2M?
|
|
||||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
toPath := dir + "/" + filename;
|
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 改变成gif图片
|
|
||||||
_, toPathGif := TransToGif(toPath, 0, true)
|
|
||||||
filename = GetFilename(toPathGif)
|
|
||||||
filesize := GetFilesize(toPathGif)
|
|
||||||
fileUrlPath += "/" + filename
|
|
||||||
|
|
||||||
// File
|
|
||||||
fileInfo := info.File{FileId: bson.NewObjectId(),
|
|
||||||
Name: filename,
|
|
||||||
Title: handel.Filename,
|
|
||||||
Path: fileUrlPath,
|
|
||||||
Size: filesize}
|
|
||||||
ok, msg = fileService.AddImage(fileInfo, "", c.getUserId(), true)
|
|
||||||
if ok {
|
|
||||||
id = fileInfo.FileId.Hex()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// "github.com/leanote/leanote/app/lea/netutil"
|
|
||||||
// "github.com/leanote/leanote/app/info"
|
|
||||||
// "io/ioutil"
|
|
||||||
"os"
|
|
||||||
// "strconv"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
"strings"
|
|
||||||
"archive/tar"
|
|
||||||
"compress/gzip"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 文件操作, 图片, 头像上传, 输出
|
|
||||||
|
|
||||||
type ApiFile struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// 协作时复制图片到owner
|
|
||||||
func (c ApiFile) CopyImage(userId, fileId, toUserId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
|
|
||||||
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
|
||||||
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all images by userId with page
|
|
||||||
func (c ApiFile) GetImages(albumId, key string, page int) revel.Result {
|
|
||||||
imagesPage := fileService.ListImagesWithPage(c.getUserId(), albumId, key, page, 12)
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = imagesPage
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ApiFile) DeleteImage(fileId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
// 输出image
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetImage(fileId string) revel.Result {
|
|
||||||
path := fileService.GetFile(c.getUserId(), fileId) // 得到路径
|
|
||||||
if path == "" {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
|
||||||
file, _ := os.Open(fn)
|
|
||||||
return c.RenderFile(file, revel.Inline) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载附件
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetAttach(fileId string) revel.Result {
|
|
||||||
attach := attachService.GetAttach(fileId, c.getUserId()); // 得到路径
|
|
||||||
path := attach.Path
|
|
||||||
if path == "" {
|
|
||||||
return c.RenderText("No Such File")
|
|
||||||
}
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
|
||||||
file, _ := os.Open(fn)
|
|
||||||
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
// 下载所有附件
|
|
||||||
// [OK]
|
|
||||||
func (c ApiFile) GetAllAttachs(noteId string) revel.Result {
|
|
||||||
note := noteService.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
// 得到文件列表
|
|
||||||
attachs := attachService.ListAttachs(noteId, c.getUserId())
|
|
||||||
if attachs == nil || len(attachs) == 0 {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
dir := revel.BasePath + "/files/tmp"
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
filename := note.Title + ".tar.gz"
|
|
||||||
if note.Title == "" {
|
|
||||||
filename = "all.tar.gz"
|
|
||||||
}
|
|
||||||
|
|
||||||
// file write
|
|
||||||
fw, err := os.Create(revel.BasePath + "/files/" + filename)
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
|
|
||||||
|
|
||||||
// gzip write
|
|
||||||
gw := gzip.NewWriter(fw)
|
|
||||||
defer gw.Close()
|
|
||||||
|
|
||||||
// tar write
|
|
||||||
tw := tar.NewWriter(gw)
|
|
||||||
defer tw.Close()
|
|
||||||
|
|
||||||
// 遍历文件列表
|
|
||||||
for _, attach := range attachs {
|
|
||||||
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
|
|
||||||
fr, err := os.Open(fn)
|
|
||||||
fileInfo, _ := fr.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return c.RenderText("")
|
|
||||||
}
|
|
||||||
defer fr.Close()
|
|
||||||
|
|
||||||
// 信息头
|
|
||||||
h := new(tar.Header)
|
|
||||||
h.Name = attach.Title
|
|
||||||
h.Size = fileInfo.Size()
|
|
||||||
h.Mode = int64(fileInfo.Mode())
|
|
||||||
h.ModTime = fileInfo.ModTime()
|
|
||||||
|
|
||||||
// 写信息头
|
|
||||||
err = tw.WriteHeader(h)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写文件
|
|
||||||
_, err = io.Copy(tw, fr)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
} // for
|
|
||||||
|
|
||||||
// tw.Close()
|
|
||||||
// gw.Close()
|
|
||||||
// fw.Close()
|
|
||||||
// file, _ := os.Open(dir + "/" + filename)
|
|
||||||
// fw.Seek(0, 0)
|
|
||||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,581 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
// "github.com/leanote/leanote/app/types"
|
|
||||||
// "io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "bytes"
|
|
||||||
// "os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 笔记API
|
|
||||||
|
|
||||||
type ApiNote struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的笔记
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 无Desc, Abstract, 有Files
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"NoteId": "55195fa199c37b79be000005",
|
|
||||||
"NotebookId": "55195fa199c37b79be000002",
|
|
||||||
"UserId": "55195fa199c37b79be000001",
|
|
||||||
"Title": "Leanote语法Leanote语法Leanote语法Leanote语法Leanote语法",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": null,
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": true,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": false,
|
|
||||||
"Usn": 5,
|
|
||||||
"Files": [],
|
|
||||||
"CreatedTime": "2015-03-30T22:37:21.695+08:00",
|
|
||||||
"UpdatedTime": "2015-03-30T22:37:21.724+08:00",
|
|
||||||
"PublicTime": "2015-03-30T22:37:21.695+08:00"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(notes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到笔记本下的笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNotes(notebookId string) revel.Result {
|
|
||||||
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "notebookIdInvalid"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到trash
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetTrashNotes() revel.Result {
|
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// get Note
|
|
||||||
// [OK]
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"NoteId": "550c0bee2ec82a2eb5000000",
|
|
||||||
"NotebookId": "54a1676399c37b1c77000004",
|
|
||||||
"UserId": "54a1676399c37b1c77000002",
|
|
||||||
"Title": "asdfadsf--=",
|
|
||||||
"Desc": "",
|
|
||||||
"Tags": [
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"Abstract": "",
|
|
||||||
"Content": "",
|
|
||||||
"IsMarkdown": false,
|
|
||||||
"IsBlog": false,
|
|
||||||
"IsTrash": false,
|
|
||||||
"Usn": 8,
|
|
||||||
"Files": [
|
|
||||||
{
|
|
||||||
"FileId": "551975d599c37b970f000002",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "",
|
|
||||||
"Title": "",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FileId": "551975de99c37b970f000003",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "doc",
|
|
||||||
"Title": "李铁-简历-ali-print-en.doc",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FileId": "551975de99c37b970f000004",
|
|
||||||
"LocalFileId": "",
|
|
||||||
"Type": "doc",
|
|
||||||
"Title": "李铁-简历-ali-print.doc",
|
|
||||||
"HasBody": false,
|
|
||||||
"IsAttach": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"CreatedTime": "2015-03-20T20:00:52.463+08:00",
|
|
||||||
"UpdatedTime": "2015-03-31T00:12:44.967+08:00",
|
|
||||||
"PublicTime": "2015-03-20T20:00:52.463+08:00"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiNote) GetNote(noteId string) revel.Result {
|
|
||||||
if !bson.IsObjectIdHex(noteId) {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "noteIdInvalid"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
note := noteService.GetNote(noteId, c.getUserId())
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "notExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
apiNotes := noteService.ToApiNotes([]info.Note{note})
|
|
||||||
return c.RenderJson(apiNotes[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到note和内容
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNoteAndContent(noteId string) revel.Result {
|
|
||||||
noteAndContent := noteService.GetNoteAndContent(noteId, c.getUserId())
|
|
||||||
|
|
||||||
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
|
|
||||||
apiNote := apiNotes[0]
|
|
||||||
apiNote.Content = noteAndContent.Content
|
|
||||||
return c.RenderJson(apiNote)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理笔记内容数据 http://leanote.com/file/outputImage -> https://leanote.com/api/file/getImage
|
|
||||||
// 图片, 附件都替换
|
|
||||||
func (c ApiNote) fixContent(content string) string {
|
|
||||||
// TODO, 这个url需要从config中取
|
|
||||||
// baseUrl := "http://leanote.com"
|
|
||||||
baseUrl := configService.GetSiteUrl()
|
|
||||||
// baseUrl := "http://localhost:9000"
|
|
||||||
|
|
||||||
patterns := []map[string]string{
|
|
||||||
map[string]string{"src": "src", "middle": "/file/outputImage", "param": "fileId", "to": "getImage?fileId="},
|
|
||||||
map[string]string{"src": "href", "middle": "/attach/download", "param": "attachId", "to": "getAttach?fileId="},
|
|
||||||
map[string]string{"src": "href", "middle": "/attach/downloadAll", "param": "noteId", "to": "getAllAttachs?noteId="},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, eachPattern := range patterns {
|
|
||||||
|
|
||||||
// src="http://leanote.com/file/outputImage?fileId=5503537b38f4111dcb0000d1"
|
|
||||||
// href="http://leanote.com/attach/download?attachId=5504243a38f4111dcb00017d"
|
|
||||||
// href="http://leanote.com/attach/downloadAll?noteId=55041b6a38f4111dcb000159"
|
|
||||||
|
|
||||||
regImage, _ := regexp.Compile(eachPattern["src"] + `=('|")`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})("|')`)
|
|
||||||
findsImage := regImage.FindAllStringSubmatch(content, -1) // 查找所有的
|
|
||||||
|
|
||||||
// [[src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "] [src="http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" " 54672e8d38f411286b000069 "]]
|
|
||||||
for _, eachFind := range findsImage {
|
|
||||||
// [src='http://leanote.com/file/outputImage?fileId=54672e8d38f411286b000069" ' 54672e8d38f411286b000069 "]
|
|
||||||
if len(eachFind) == 4 {
|
|
||||||
content = strings.Replace(content,
|
|
||||||
eachFind[0],
|
|
||||||
eachPattern["src"] + "=\"" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + "\"",
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// markdown处理
|
|
||||||
// 
|
|
||||||
// [selection 2.html](http://leanote.com/attach/download?attachId=5504262638f4111dcb00017f)
|
|
||||||
// [all.tar.gz](http://leanote.com/attach/downloadAll?noteId=5503b57d59f81b4eb4000000)
|
|
||||||
|
|
||||||
pre := "!" // 默认图片
|
|
||||||
if eachPattern["src"] == "href" { // 是attach
|
|
||||||
pre = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
regImageMarkdown, _ := regexp.Compile(pre + `\[(.*?)\]\(`+ baseUrl + eachPattern["middle"] + `\?` + eachPattern["param"] + `=([a-z0-9A-Z]{24})\)`)
|
|
||||||
findsImageMarkdown := regImageMarkdown.FindAllStringSubmatch(content, -1) // 查找所有的
|
|
||||||
// [[ 5503537b38f4111dcb0000d1] [ 5503537b38f4111dcb0000d1]]
|
|
||||||
for _, eachFind := range findsImageMarkdown {
|
|
||||||
// [ 你好啊, 我很好, 为什么? 5503537b38f4111dcb0000d1]
|
|
||||||
if len(eachFind) == 3 {
|
|
||||||
content = strings.Replace(content, eachFind[0], pre + "[" + eachFind[1] + "](" + baseUrl + "/api/file/" + eachPattern["to"] + eachFind[2] + ")", 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|
||||||
// content里的image, attach链接是
|
|
||||||
// https://leanote.com/api/file/getImage?fileId=xx
|
|
||||||
// https://leanote.com/api/file/getAttach?fileId=xx
|
|
||||||
// 将fileId=映射成ServerFileId, 这里的fileId可能是本地的FileId
|
|
||||||
func (c ApiNote) fixPostNotecontent(noteOrContent *info.ApiNote) {
|
|
||||||
if noteOrContent.Content == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
files := noteOrContent.Files
|
|
||||||
if files != nil && len(files) > 0 {
|
|
||||||
for _, file := range files {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
noteOrContent.Content = strings.Replace(noteOrContent.Content, "fileId=" + file.LocalFileId, "fileId=" + file.FileId, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到内容
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) GetNoteContent(noteId string) revel.Result {
|
|
||||||
// re := info.NewRe()
|
|
||||||
noteContent := noteService.GetNoteContent(noteId, c.getUserId())
|
|
||||||
if noteContent.Content != "" {
|
|
||||||
noteContent.Content = c.fixContent(noteContent.Content)
|
|
||||||
}
|
|
||||||
|
|
||||||
apiNoteContent := info.ApiNoteContent{
|
|
||||||
NoteId: noteContent.NoteId,
|
|
||||||
UserId: noteContent.UserId,
|
|
||||||
Content: noteContent.Content,
|
|
||||||
}
|
|
||||||
|
|
||||||
// re.Item = noteContent
|
|
||||||
return c.RenderJson(apiNoteContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|
||||||
userId := bson.ObjectIdHex(c.getUserId())
|
|
||||||
re := info.NewRe()
|
|
||||||
myUserId := userId
|
|
||||||
// 为共享新建?
|
|
||||||
/*
|
|
||||||
if noteOrContent.FromUserId != "" {
|
|
||||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Log(noteOrContent.Title)
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
/*
|
|
||||||
LogJ(c.Params)
|
|
||||||
for name, _ := range c.Params.Files {
|
|
||||||
Log(name)
|
|
||||||
file, _, _ := c.Request.FormFile(name)
|
|
||||||
LogJ(file)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// return c.RenderJson(re)
|
|
||||||
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
|
||||||
re.Msg = "notebookIdNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteId := bson.NewObjectId()
|
|
||||||
// TODO 先上传图片/附件, 如果不成功, 则返回false
|
|
||||||
//
|
|
||||||
attachNum := 0
|
|
||||||
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
|
|
||||||
for i, file := range noteOrContent.Files {
|
|
||||||
if file.HasBody {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
// FileDatas[54c7ae27d98d0329dd000000]
|
|
||||||
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId.Hex(), file.IsAttach)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
re.Ok = false
|
|
||||||
if msg != "" {
|
|
||||||
Log(msg)
|
|
||||||
Log(file.LocalFileId)
|
|
||||||
re.Msg = "fileUploadError"
|
|
||||||
}
|
|
||||||
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
|
|
||||||
if msg != "notImage" {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 建立映射
|
|
||||||
file.FileId = fileId
|
|
||||||
noteOrContent.Files[i] = file
|
|
||||||
|
|
||||||
if file.IsAttach {
|
|
||||||
attachNum++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.fixPostNotecontent(¬eOrContent)
|
|
||||||
|
|
||||||
// Log("Add")
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
|
|
||||||
// return c.RenderJson(re)
|
|
||||||
|
|
||||||
note := info.Note{UserId: userId,
|
|
||||||
NoteId: noteId,
|
|
||||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
|
||||||
Title: noteOrContent.Title,
|
|
||||||
Tags: noteOrContent.Tags,
|
|
||||||
Desc: noteOrContent.Desc,
|
|
||||||
// ImgSrc: noteOrContent.ImgSrc,
|
|
||||||
IsBlog: noteOrContent.IsBlog,
|
|
||||||
IsMarkdown: noteOrContent.IsMarkdown,
|
|
||||||
AttachNum: attachNum,
|
|
||||||
}
|
|
||||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
|
||||||
UserId: userId,
|
|
||||||
IsBlog: note.IsBlog,
|
|
||||||
Content: noteOrContent.Content,
|
|
||||||
Abstract: noteOrContent.Abstract}
|
|
||||||
|
|
||||||
// 通过内容得到Desc, abstract
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
note.Desc = SubStringHTMLToRaw(noteContent.Content, 200)
|
|
||||||
noteContent.Abstract = SubStringHTML(noteContent.Content, 200, "")
|
|
||||||
} else {
|
|
||||||
note.Desc = SubStringHTMLToRaw(noteContent.Abstract, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
note = noteService.AddNoteAndContentApi(note, noteContent, myUserId)
|
|
||||||
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re.Ok = false
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加需要返回的
|
|
||||||
noteOrContent.NoteId = note.NoteId.Hex()
|
|
||||||
noteOrContent.Usn = note.Usn
|
|
||||||
noteOrContent.CreatedTime = note.CreatedTime
|
|
||||||
noteOrContent.UpdatedTime = note.UpdatedTime
|
|
||||||
noteOrContent.UserId = c.getUserId()
|
|
||||||
noteOrContent.IsMarkdown = note.IsMarkdown
|
|
||||||
// 删除一些不要返回的, 删除Desc?
|
|
||||||
noteOrContent.Content = ""
|
|
||||||
noteOrContent.Abstract = ""
|
|
||||||
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
|
|
||||||
return c.RenderJson(noteOrContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
|
|
||||||
noteUpdate := bson.M{}
|
|
||||||
needUpdateNote := false
|
|
||||||
|
|
||||||
noteId := noteOrContent.NoteId
|
|
||||||
|
|
||||||
if noteOrContent.NoteId == "" {
|
|
||||||
re.Msg = "noteIdNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if noteOrContent.Usn <= 0 {
|
|
||||||
re.Msg = "usnNotExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log("_____________")
|
|
||||||
// LogJ(noteOrContent)
|
|
||||||
/*
|
|
||||||
LogJ(c.Params.Files)
|
|
||||||
LogJ(c.Request.Header)
|
|
||||||
LogJ(c.Params.Values)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 先判断USN的问题, 因为很可能添加完附件后, 会有USN冲突, 这时附件就添错了
|
|
||||||
userId := c.getUserId()
|
|
||||||
note := noteService.GetNote(noteId, userId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
re.Msg = "notExists"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if note.Usn != noteOrContent.Usn {
|
|
||||||
re.Msg = "conflict"
|
|
||||||
Log("conflict")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果传了files
|
|
||||||
// TODO 测试
|
|
||||||
/*
|
|
||||||
for key, v := range c.Params.Values {
|
|
||||||
Log(key)
|
|
||||||
Log(v)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Log(c.Has("Files[0]"))
|
|
||||||
if c.Has("Files[0][LocalFileId]") {
|
|
||||||
// LogJ(c.Params.Files)
|
|
||||||
if noteOrContent.Files != nil && len(noteOrContent.Files) > 0 {
|
|
||||||
for i, file := range noteOrContent.Files {
|
|
||||||
if file.HasBody {
|
|
||||||
if file.LocalFileId != "" {
|
|
||||||
// FileDatas[54c7ae27d98d0329dd000000]
|
|
||||||
ok, msg, fileId := c.upload("FileDatas["+file.LocalFileId+"]", noteId, file.IsAttach)
|
|
||||||
if !ok {
|
|
||||||
Log("upload file error")
|
|
||||||
re.Ok = false
|
|
||||||
if msg == "" {
|
|
||||||
re.Msg = "fileUploadError"
|
|
||||||
} else {
|
|
||||||
re.Msg = msg
|
|
||||||
}
|
|
||||||
return c.RenderJson(re)
|
|
||||||
} else {
|
|
||||||
// 建立映射
|
|
||||||
file.FileId = fileId
|
|
||||||
noteOrContent.Files[i] = file
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log("after upload")
|
|
||||||
// LogJ(noteOrContent.Files)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移到外面来, 删除最后一个file时也要处理, 不然总删不掉
|
|
||||||
// 附件问题, 根据Files, 有些要删除的, 只留下这些
|
|
||||||
attachService.UpdateOrDeleteAttachApi(noteId, userId, noteOrContent.Files)
|
|
||||||
|
|
||||||
// Desc前台传来
|
|
||||||
if c.Has("Desc") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Desc"] = noteOrContent.Desc
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if c.Has("ImgSrc") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if c.Has("Title") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Title"] = noteOrContent.Title
|
|
||||||
}
|
|
||||||
if c.Has("IsTrash") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["IsTrash"] = noteOrContent.IsTrash
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否是博客
|
|
||||||
if c.Has("IsBlog") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["IsBlog"] = noteOrContent.IsBlog
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Log(c.Has("tags[0]"))
|
|
||||||
Log(c.Has("Tags[]"))
|
|
||||||
for key, v := range c.Params.Values {
|
|
||||||
Log(key)
|
|
||||||
Log(v)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if c.Has("Tags[0]") {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["Tags"] = noteOrContent.Tags
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Has("NotebookId") {
|
|
||||||
if bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
|
||||||
needUpdateNote = true
|
|
||||||
noteUpdate["NotebookId"] = bson.ObjectIdHex(noteOrContent.NotebookId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Has("Content") {
|
|
||||||
// 通过内容得到Desc, 如果有Abstract, 则用Abstract生成Desc
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Content, 200)
|
|
||||||
} else {
|
|
||||||
noteUpdate["Desc"] = SubStringHTMLToRaw(noteOrContent.Abstract, 200)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
afterNoteUsn := 0
|
|
||||||
noteOk := false
|
|
||||||
noteMsg := ""
|
|
||||||
if needUpdateNote {
|
|
||||||
noteOk, noteMsg, afterNoteUsn = noteService.UpdateNote(c.getUserId(), noteOrContent.NoteId, noteUpdate, noteOrContent.Usn)
|
|
||||||
if !noteOk {
|
|
||||||
re.Ok = false
|
|
||||||
re.Msg = noteMsg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------
|
|
||||||
afterContentUsn := 0
|
|
||||||
contentOk := false
|
|
||||||
contentMsg := ""
|
|
||||||
if c.Has("Content") {
|
|
||||||
// 把fileId替换下
|
|
||||||
c.fixPostNotecontent(¬eOrContent)
|
|
||||||
// 如果传了Abstract就用之
|
|
||||||
if noteOrContent.Abstract == "" {
|
|
||||||
noteOrContent.Abstract = SubStringHTML(noteOrContent.Content, 200, "")
|
|
||||||
}
|
|
||||||
// Log("--------> afte fixed")
|
|
||||||
// Log(noteOrContent.Content)
|
|
||||||
contentOk, contentMsg, afterContentUsn = noteService.UpdateNoteContent(c.getUserId(),
|
|
||||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract, needUpdateNote, noteOrContent.Usn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if needUpdateNote {
|
|
||||||
re.Ok = noteOk
|
|
||||||
re.Msg = noteMsg
|
|
||||||
re.Usn = afterNoteUsn
|
|
||||||
} else {
|
|
||||||
re.Ok = contentOk
|
|
||||||
re.Msg = contentMsg
|
|
||||||
re.Usn = afterContentUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
if !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteOrContent.Content = ""
|
|
||||||
noteOrContent.Usn = re.Usn
|
|
||||||
noteOrContent.UpdatedTime = time.Now()
|
|
||||||
|
|
||||||
// Log("after upload")
|
|
||||||
// LogJ(noteOrContent.Files)
|
|
||||||
noteOrContent.UserId = c.getUserId()
|
|
||||||
|
|
||||||
return c.RenderJson(noteOrContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除trash
|
|
||||||
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到历史列表
|
|
||||||
/*
|
|
||||||
func (c ApiNote) GetHistories(noteId string) revel.Result {
|
|
||||||
re := info.NewRe()
|
|
||||||
histories := noteContentHistoryService.ListHistories(noteId, c.getUserId())
|
|
||||||
if len(histories) > 0 {
|
|
||||||
re.Ok = true
|
|
||||||
re.Item = histories
|
|
||||||
}
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
// "io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 笔记本API
|
|
||||||
|
|
||||||
type ApiNotebook struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从Notebook -> ApiNotebook
|
|
||||||
func (c ApiNotebook) fixNotebooks(notebooks []info.Notebook) []info.ApiNotebook {
|
|
||||||
if notebooks == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
apiNotebooks := make([]info.ApiNotebook, len(notebooks))
|
|
||||||
for i, notebook := range notebooks {
|
|
||||||
apiNotebooks[i] = c.fixNotebook(¬ebook)
|
|
||||||
}
|
|
||||||
return apiNotebooks
|
|
||||||
}
|
|
||||||
func (c ApiNotebook) fixNotebook(notebook *info.Notebook) info.ApiNotebook {
|
|
||||||
if notebook == nil {
|
|
||||||
return info.ApiNotebook{}
|
|
||||||
}
|
|
||||||
return info.ApiNotebook{
|
|
||||||
NotebookId : notebook.NotebookId,
|
|
||||||
UserId : notebook.UserId,
|
|
||||||
ParentNotebookId : notebook.ParentNotebookId,
|
|
||||||
Seq : notebook.Seq,
|
|
||||||
Title : notebook.Title,
|
|
||||||
UrlTitle : notebook.UrlTitle,
|
|
||||||
IsBlog : notebook.IsBlog,
|
|
||||||
CreatedTime : notebook.CreatedTime,
|
|
||||||
UpdatedTime : notebook.UpdatedTime,
|
|
||||||
Usn: notebook.Usn,
|
|
||||||
IsDeleted: notebook.IsDeleted,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的笔记本
|
|
||||||
// [OK]
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
|
|
||||||
func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户的所有笔记本
|
|
||||||
// [OK]
|
|
||||||
// info.SubNotebooks
|
|
||||||
func (c ApiNotebook) GetNotebooks() revel.Result {
|
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
|
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加notebook
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.Result {
|
|
||||||
notebook := info.Notebook{NotebookId: bson.NewObjectId(),
|
|
||||||
Title: title,
|
|
||||||
Seq: seq,
|
|
||||||
UserId: bson.ObjectIdHex(c.getUserId())}
|
|
||||||
if parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId) {
|
|
||||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
|
||||||
}
|
|
||||||
re := info.NewRe()
|
|
||||||
re.Ok, notebook = notebookService.AddNotebook(notebook)
|
|
||||||
if !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改笔记
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string, seq, usn int) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
|
|
||||||
ok, msg, notebook := notebookService.UpdateNotebookApi(c.getUserId(), notebookId, title, parentNotebookId, seq, usn)
|
|
||||||
if !ok {
|
|
||||||
re.Ok = false
|
|
||||||
re.Msg = msg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
LogJ(notebook)
|
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除笔记本
|
|
||||||
// [OK]
|
|
||||||
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "gopkg.in/mgo.v2/bson"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
// "io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 标签API
|
|
||||||
|
|
||||||
type ApiTag struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取同步的标签
|
|
||||||
// [OK]
|
|
||||||
// > afterUsn的笔记
|
|
||||||
// 返回 {ChunkHighUsn: 本下最大的usn, 借此可以知道是否还有, Notebooks: []}
|
|
||||||
func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
|
|
||||||
if maxEntry == 0 {
|
|
||||||
maxEntry = 100
|
|
||||||
}
|
|
||||||
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
|
|
||||||
return c.RenderJson(tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加Tag
|
|
||||||
// [OK]
|
|
||||||
// 不会产生冲突, 即使里面有
|
|
||||||
// 返回
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"TagId": "551978dd99c37b9bc5000001",
|
|
||||||
"UserId": "54a1676399c37b1c77000002",
|
|
||||||
"Tag": "32",
|
|
||||||
"Usn": 25,
|
|
||||||
"Count": 1,
|
|
||||||
"CreatedTime": "2015-03-31T00:25:01.149312407+08:00",
|
|
||||||
"UpdatedTime": "2015-03-31T00:25:01.149312407+08:00",
|
|
||||||
"IsDeleted": false
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func (c ApiTag) AddTag(tag string) revel.Result {
|
|
||||||
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
// [OK]
|
|
||||||
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
|
|
||||||
re := info.NewReUpdate()
|
|
||||||
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
// "encoding/json"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
|
||||||
"time"
|
|
||||||
// "github.com/leanote/leanote/app/types"
|
|
||||||
"io/ioutil"
|
|
||||||
// "fmt"
|
|
||||||
// "math"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
// "path"
|
|
||||||
// "strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ApiUser struct {
|
|
||||||
ApiBaseContrller
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) Info() revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
|
|
||||||
userInfo := c.getUserInfo()
|
|
||||||
if userInfo.UserId == "" {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
apiUser := info.ApiUser{
|
|
||||||
UserId: userInfo.UserId.Hex(),
|
|
||||||
Username: userInfo.Username,
|
|
||||||
Email: userInfo.Email,
|
|
||||||
Logo: userInfo.Logo,
|
|
||||||
Verified: userInfo.Verified,
|
|
||||||
}
|
|
||||||
return c.RenderJson(apiUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改用户名
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdateUsername(username string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if c.GetUsername() == "demo" {
|
|
||||||
re.Msg = "cannotUpdateDemo"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改密码
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
if c.GetUsername() == "demo" {
|
|
||||||
re.Msg = "cannotUpdateDemo"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获得同步状态
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) GetSyncState() revel.Result {
|
|
||||||
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
|
|
||||||
return c.RenderJson(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 头像设置
|
|
||||||
// 参数file=文件
|
|
||||||
// 成功返回{Logo: url} 头像新url
|
|
||||||
// [OK]
|
|
||||||
func (c ApiUser) UpdateLogo() revel.Result {
|
|
||||||
ok, msg, url := c.uploadImage()
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
ok = userService.UpdateAvatar(c.getUserId(), url)
|
|
||||||
return c.RenderJson(map[string]string{"Logo": url})
|
|
||||||
} else {
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = msg
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传图片
|
|
||||||
func (c ApiUser) uploadImage() (ok bool, msg, url string) {
|
|
||||||
var fileUrlPath = ""
|
|
||||||
ok = false
|
|
||||||
|
|
||||||
file, handel, err := c.Request.FormFile("file")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
// 生成上传路径
|
|
||||||
fileUrlPath = "public/upload/" + c.getUserId() + "/images/logo"
|
|
||||||
|
|
||||||
dir := revel.BasePath + "/" + fileUrlPath
|
|
||||||
err = os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 生成新的文件名
|
|
||||||
filename := handel.Filename
|
|
||||||
|
|
||||||
var ext string
|
|
||||||
|
|
||||||
_, ext = SplitFilename(filename)
|
|
||||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
|
||||||
msg = "notImage"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = NewGuid() + ext
|
|
||||||
data, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
LogJ(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// > 5M?
|
|
||||||
if len(data) > 5*1024*1024 {
|
|
||||||
msg = "fileIsTooLarge"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
toPath := dir + "/" + filename
|
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
|
||||||
if err != nil {
|
|
||||||
LogJ(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true
|
|
||||||
url = configService.GetSiteUrl() + "/" + fileUrlPath + "/" + filename
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/info"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
// "strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApiUser struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户名, 需要重置session
|
||||||
|
func (c ApiUser) Info() revel.Result {
|
||||||
|
Log("APIUser");
|
||||||
|
return c.RenderTemplate("home/index.html");
|
||||||
|
// return nil;
|
||||||
|
}
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
"github.com/leanote/leanote/app/service"
|
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var userService *service.UserService
|
|
||||||
var noteService *service.NoteService
|
|
||||||
var trashService *service.TrashService
|
|
||||||
var notebookService *service.NotebookService
|
|
||||||
var noteContentHistoryService *service.NoteContentHistoryService
|
|
||||||
var authService *service.AuthService
|
|
||||||
var shareService *service.ShareService
|
|
||||||
var blogService *service.BlogService
|
|
||||||
var tagService *service.TagService
|
|
||||||
var pwdService *service.PwdService
|
|
||||||
var tokenService *service.TokenService
|
|
||||||
var suggestionService *service.SuggestionService
|
|
||||||
var albumService *service.AlbumService
|
|
||||||
var noteImageService *service.NoteImageService
|
|
||||||
var fileService *service.FileService
|
|
||||||
var attachService *service.AttachService
|
|
||||||
var configService *service.ConfigService
|
|
||||||
var emailService *service.EmailService
|
|
||||||
var sessionService *service.SessionService
|
|
||||||
|
|
||||||
var pageSize = 1000
|
|
||||||
var defaultSortField = "UpdatedTime"
|
|
||||||
var leanoteUserId = "admin" // 不能更改
|
|
||||||
|
|
||||||
// 状态
|
|
||||||
const (
|
|
||||||
S_DEFAULT = iota // 0
|
|
||||||
S_NOT_LOGIN // 1
|
|
||||||
S_WRONG_USERNAME_PASSWORD // 2
|
|
||||||
S_WRONG_CAPTCHA // 3
|
|
||||||
S_NEED_CAPTCHA // 4
|
|
||||||
S_NOT_OPEN_REGISTER // 4
|
|
||||||
)
|
|
||||||
|
|
||||||
// 拦截器
|
|
||||||
// 不需要拦截的url
|
|
||||||
var commonUrl = map[string]map[string]bool{"ApiAuth": map[string]bool{"Login": true,
|
|
||||||
"Register": true,
|
|
||||||
},
|
|
||||||
// 文件的操作也不用登录, userId会从session中获取
|
|
||||||
"ApiFile": map[string]bool{"GetImage": true,
|
|
||||||
"GetAttach": true,
|
|
||||||
"GetAllAttachs": true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func needValidate(controller, method string) bool {
|
|
||||||
// 在里面
|
|
||||||
if v, ok := commonUrl[controller]; ok {
|
|
||||||
// 在commonUrl里
|
|
||||||
if _, ok2 := v[method]; ok2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
// controller不在这里的, 肯定要验证
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这里得到token, 若不是login, logout等公用操作, 必须验证是否已登录
|
|
||||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
|
||||||
// 得到token /api/user/info?userId=xxx&token=xxxxx
|
|
||||||
token := c.Params.Values.Get("token")
|
|
||||||
noToken := false
|
|
||||||
if token == "" {
|
|
||||||
// 若无, 则取sessionId
|
|
||||||
token = c.Session.Id()
|
|
||||||
noToken = true
|
|
||||||
}
|
|
||||||
c.Session["_token"] = token
|
|
||||||
|
|
||||||
// 全部变成首字大写
|
|
||||||
var controller = strings.Title(c.Name)
|
|
||||||
var method = strings.Title(c.MethodName)
|
|
||||||
|
|
||||||
// 验证是否已登录
|
|
||||||
// 通过sessionService判断该token下是否有userId, 并返回userId
|
|
||||||
userId := sessionService.GetUserId(token)
|
|
||||||
if noToken && userId == "" {
|
|
||||||
// 从session中获取, api/file/getImage, api/file/getAttach, api/file/getAllAttach
|
|
||||||
// 客户端
|
|
||||||
userId, _ = c.Session["UserId"];
|
|
||||||
}
|
|
||||||
c.Session["_userId"] = userId
|
|
||||||
|
|
||||||
// 是否需要验证?
|
|
||||||
if !needValidate(controller, method) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if userId != "" {
|
|
||||||
return nil // 已登录
|
|
||||||
}
|
|
||||||
|
|
||||||
// 没有登录, 返回错误的信息, 需要登录
|
|
||||||
re := info.NewApiRe()
|
|
||||||
re.Msg = "NOTLOGIN"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// interceptors
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiFile{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNote{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiTag{})
|
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiNotebook{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最外层init.go调用
|
|
||||||
// 获取service, 单例
|
|
||||||
func InitService() {
|
|
||||||
notebookService = service.NotebookS
|
|
||||||
noteService = service.NoteS
|
|
||||||
noteContentHistoryService = service.NoteContentHistoryS
|
|
||||||
trashService = service.TrashS
|
|
||||||
shareService = service.ShareS
|
|
||||||
userService = service.UserS
|
|
||||||
tagService = service.TagS
|
|
||||||
blogService = service.BlogS
|
|
||||||
tokenService = service.TokenS
|
|
||||||
noteImageService = service.NoteImageS
|
|
||||||
fileService = service.FileS
|
|
||||||
albumService = service.AlbumS
|
|
||||||
attachService = service.AttachS
|
|
||||||
pwdService = service.PwdS
|
|
||||||
suggestionService = service.SuggestionS
|
|
||||||
authService = service.AuthS
|
|
||||||
configService = service.ConfigS
|
|
||||||
emailService = service.EmailS
|
|
||||||
sessionService = service.SessionS
|
|
||||||
}
|
|
||||||
@@ -49,6 +49,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
|||||||
"Suggestion": true,
|
"Suggestion": true,
|
||||||
},
|
},
|
||||||
"Note": map[string]bool{"ToImage": true},
|
"Note": map[string]bool{"ToImage": true},
|
||||||
|
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
|
||||||
"Blog": map[string]bool{"Index": true,
|
"Blog": map[string]bool{"Index": true,
|
||||||
"View": true,
|
"View": true,
|
||||||
"AboutMe": true,
|
"AboutMe": true,
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
var ext string
|
var ext string
|
||||||
_, ext = SplitFilename(filename)
|
_, ext = SplitFilename(filename)
|
||||||
if ext != ".zip" {
|
if ext != ".zip" {
|
||||||
re.Msg = "Please upload zip file"
|
re.Msg = "请上传zip文件"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
|
|
||||||
// > 10M?
|
// > 10M?
|
||||||
if len(data) > 10*1024*1024 {
|
if len(data) > 10*1024*1024 {
|
||||||
re.Msg = "File is big than 10M"
|
re.Msg = "文件大于10M"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ var Groups *mgo.Collection
|
|||||||
var GroupUsers *mgo.Collection
|
var GroupUsers *mgo.Collection
|
||||||
|
|
||||||
var Tags *mgo.Collection
|
var Tags *mgo.Collection
|
||||||
var NoteTags *mgo.Collection
|
//var TagNotes *mgo.Collection
|
||||||
var TagCounts *mgo.Collection
|
var TagCounts *mgo.Collection
|
||||||
|
|
||||||
var UserBlogs *mgo.Collection
|
var UserBlogs *mgo.Collection
|
||||||
@@ -116,7 +116,7 @@ func Init(url, dbname string) {
|
|||||||
|
|
||||||
// tag
|
// tag
|
||||||
Tags = Session.DB(dbname).C("tags")
|
Tags = Session.DB(dbname).C("tags")
|
||||||
NoteTags = Session.DB(dbname).C("note_tags")
|
// TagNotes = Session.DB(dbname).C("tag_notes")
|
||||||
TagCounts = Session.DB(dbname).C("tag_count")
|
TagCounts = Session.DB(dbname).C("tag_count")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
|
|||||||
+2
-4
@@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
// convert revel msg to js msg
|
// convert revel msg to js msg
|
||||||
|
|
||||||
var msgBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/messages/"
|
var msgBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/messages/"
|
||||||
var targetBasePath = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/js/i18n/"
|
var targetBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/public/js/i18n/"
|
||||||
func parse(filename string) {
|
func parse(filename string) {
|
||||||
file, err := os.Open(msgBasePath + filename)
|
file, err := os.Open(msgBasePath + filename)
|
||||||
reader := bufio.NewReader(file)
|
reader := bufio.NewReader(file)
|
||||||
@@ -84,8 +84,6 @@ function getMsg(key, data) {
|
|||||||
func main() {
|
func main() {
|
||||||
parse("msg.en")
|
parse("msg.en")
|
||||||
parse("msg.zh")
|
parse("msg.zh")
|
||||||
parse("msg.fr")
|
|
||||||
parse("blog.zh")
|
parse("blog.zh")
|
||||||
parse("blog.en")
|
parse("blog.en")
|
||||||
parse("blog.fr")
|
|
||||||
}
|
}
|
||||||
-119
@@ -1,119 +0,0 @@
|
|||||||
package info
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
//---------
|
|
||||||
// 数据结构
|
|
||||||
//---------
|
|
||||||
type NoteFile struct {
|
|
||||||
FileId string // 服务器端Id
|
|
||||||
LocalFileId string // 客户端Id
|
|
||||||
Type string // images/png, doc, xls, 根据fileName确定
|
|
||||||
Title string
|
|
||||||
HasBody bool // 传过来的值是否要更新内容
|
|
||||||
IsAttach bool // 是否是附件, 不是附件就是图片
|
|
||||||
}
|
|
||||||
type ApiNote struct {
|
|
||||||
NoteId string
|
|
||||||
NotebookId string
|
|
||||||
UserId string
|
|
||||||
Title string
|
|
||||||
Desc string
|
|
||||||
// ImgSrc string
|
|
||||||
Tags []string
|
|
||||||
Abstract string
|
|
||||||
Content string
|
|
||||||
IsMarkdown bool
|
|
||||||
// FromUserId string // 为共享而新建
|
|
||||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
|
||||||
IsTrash bool
|
|
||||||
IsDeleted bool
|
|
||||||
Usn int
|
|
||||||
Files []NoteFile
|
|
||||||
CreatedTime time.Time
|
|
||||||
UpdatedTime time.Time
|
|
||||||
PublicTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 内容
|
|
||||||
type ApiNoteContent struct {
|
|
||||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
|
||||||
|
|
||||||
Content string `Content`
|
|
||||||
|
|
||||||
// CreatedTime time.Time `CreatedTime`
|
|
||||||
// UpdatedTime time.Time `UpdatedTime`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换
|
|
||||||
func NoteToApiNote(note Note, files []NoteFile) ApiNote {
|
|
||||||
apiNote := ApiNote{}
|
|
||||||
return apiNote
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// 用户信息
|
|
||||||
//----------
|
|
||||||
|
|
||||||
type ApiUser struct {
|
|
||||||
UserId string
|
|
||||||
Username string
|
|
||||||
Email string
|
|
||||||
Verified bool
|
|
||||||
Logo string
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// Notebook
|
|
||||||
//----------
|
|
||||||
type ApiNotebook struct {
|
|
||||||
NotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
|
||||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
|
||||||
Seq int `Seq` // 排序
|
|
||||||
Title string `Title` // 标题
|
|
||||||
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
|
||||||
CreatedTime time.Time `CreatedTime,omitempty`
|
|
||||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
IsDeleted bool `IsDeleted`
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------
|
|
||||||
// api 返回
|
|
||||||
//---------
|
|
||||||
|
|
||||||
// 一般返回
|
|
||||||
type ApiRe struct {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewApiRe() ApiRe {
|
|
||||||
return ApiRe{Ok: false}
|
|
||||||
}
|
|
||||||
|
|
||||||
// auth
|
|
||||||
type AuthOk struct {
|
|
||||||
Ok bool
|
|
||||||
Token string
|
|
||||||
UserId bson.ObjectId
|
|
||||||
Email string
|
|
||||||
Username string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 供notebook, note, tag更新的返回数据用
|
|
||||||
type ReUpdate struct {
|
|
||||||
Ok bool
|
|
||||||
Msg string
|
|
||||||
Usn int
|
|
||||||
}
|
|
||||||
func NewReUpdate() ReUpdate {
|
|
||||||
return ReUpdate{Ok: false}
|
|
||||||
}
|
|
||||||
@@ -47,11 +47,3 @@ type Archive struct {
|
|||||||
MonthAchives []ArchiveMonth
|
MonthAchives []ArchiveMonth
|
||||||
Posts []*Post
|
Posts []*Post
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cate struct {
|
|
||||||
CateId string
|
|
||||||
ParentCateId string
|
|
||||||
Title string
|
|
||||||
UrlTitle string
|
|
||||||
Children []*Cate
|
|
||||||
}
|
|
||||||
@@ -41,10 +41,7 @@ type Note struct {
|
|||||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
SharePass int `SharePass` //分享笔记的密码
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
|
|
||||||
IsDeleted bool `IsDeleted` // 删除位
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ type Notebook struct {
|
|||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||||
CreatedTime time.Time `CreatedTime,omitempty`
|
CreatedTime time.Time `CreatedTime,omitempty`
|
||||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
UpdatedTime time.Time `UpdatedTime,omitempty`
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
|
||||||
Usn int `Usn` // UpdateSequenceNum
|
|
||||||
IsDeleted bool `IsDeleted`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 仅仅是为了返回前台
|
// 仅仅是为了返回前台
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ type Session struct {
|
|||||||
|
|
||||||
LoginTimes int `LoginTimes` // 登录错误时间
|
LoginTimes int `LoginTimes` // 登录错误时间
|
||||||
Captcha string `Captcha` // 验证码
|
Captcha string `Captcha` // 验证码
|
||||||
|
Token string `Token` //attach token
|
||||||
UserId string `UserId` // API时有值UserId
|
TokenTime time.Time `TokenTime` //token生成时间
|
||||||
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ package info
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 这里主要是为了统计每个tag的note数目
|
// 这里主要是为了统计每个tag的note数目
|
||||||
@@ -22,18 +21,6 @@ type Tag struct {
|
|||||||
Tags []string `Tags`
|
Tags []string `Tags`
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2 版标签
|
|
||||||
type NoteTag struct {
|
|
||||||
TagId bson.ObjectId `bson:"_id"`
|
|
||||||
UserId bson.ObjectId `UserId` // 谁的
|
|
||||||
Tag string `Tag` // UserId, Tag是唯一索引
|
|
||||||
Usn int `Usn` // Update Sequence Number
|
|
||||||
Count int `Count` // 笔记数
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
|
||||||
IsDeleted bool `IsDeleted` // 删除位
|
|
||||||
}
|
|
||||||
|
|
||||||
type TagCount struct {
|
type TagCount struct {
|
||||||
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
UserId bson.ObjectId `UserId` // 谁的
|
UserId bson.ObjectId `UserId` // 谁的
|
||||||
@@ -41,7 +28,6 @@ type TagCount struct {
|
|||||||
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||||
Count int `Count` // 统计数量
|
Count int `Count` // 统计数量
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
type TagsCounts []TagCount
|
type TagsCounts []TagCount
|
||||||
func (this TagsCounts) Len() int {
|
func (this TagsCounts) Len() int {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type Theme struct {
|
|||||||
Version string `Version`
|
Version string `Version`
|
||||||
Author string `Author`
|
Author string `Author`
|
||||||
AuthorUrl string `AuthorUrl`
|
AuthorUrl string `AuthorUrl`
|
||||||
Path string `Path` // 文件夹路径, public/upload/54d7620d99c37b030600002c/themes/54d867c799c37b533e000001
|
Path string `Path` // 文件夹路径
|
||||||
Info map[string]interface{} `Info` // 所有信息
|
Info map[string]interface{} `Info` // 所有信息
|
||||||
IsActive bool `IsActive` // 是否在用
|
IsActive bool `IsActive` // 是否在用
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ type User struct {
|
|||||||
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
|
||||||
// 2015/1/15, 更新序号
|
|
||||||
Usn int `Usn` // UpdateSequenceNum , 全局的
|
|
||||||
FullSyncBefore time.Time `bson:"FullSyncBefore"` // 需要全量同步的时间, 如果 > 客户端的LastSyncTime, 则需要全量更新
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserAccount struct {
|
type UserAccount struct {
|
||||||
|
|||||||
+9
-50
@@ -6,12 +6,11 @@ import (
|
|||||||
"github.com/leanote/leanote/app/service"
|
"github.com/leanote/leanote/app/service"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
"github.com/leanote/leanote/app/controllers/api"
|
|
||||||
"github.com/leanote/leanote/app/controllers/admin"
|
"github.com/leanote/leanote/app/controllers/admin"
|
||||||
"github.com/leanote/leanote/app/controllers/member"
|
"github.com/leanote/leanote/app/controllers/member"
|
||||||
_ "github.com/leanote/leanote/app/lea/binder"
|
_ "github.com/leanote/leanote/app/lea/binder"
|
||||||
// "github.com/leanote/leanote/app/lea/session"
|
"github.com/leanote/leanote/app/lea/session"
|
||||||
// "github.com/leanote/leanote/app/lea/memcache"
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
"github.com/leanote/leanote/app/lea/route"
|
"github.com/leanote/leanote/app/lea/route"
|
||||||
"reflect"
|
"reflect"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -33,11 +32,11 @@ func init() {
|
|||||||
// AuthFilter, // Invoke the action.
|
// AuthFilter, // Invoke the action.
|
||||||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
||||||
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
||||||
revel.SessionFilter, // Restore and write the session cookie.
|
// revel.SessionFilter, // Restore and write the session cookie.
|
||||||
|
|
||||||
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
|
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
|
||||||
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
||||||
// session.SessionFilter, // leanote session
|
session.SessionFilter, // leanote session
|
||||||
// session.MSessionFilter, // leanote memcache session
|
// session.MSessionFilter, // leanote memcache session
|
||||||
|
|
||||||
revel.FlashFilter, // Restore and write the flash cookie.
|
revel.FlashFilter, // Restore and write the flash cookie.
|
||||||
@@ -51,18 +50,6 @@ func init() {
|
|||||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||||
return template.HTML(str)
|
return template.HTML(str)
|
||||||
}
|
}
|
||||||
revel.TemplateFuncs["trim"] = func(str string) string {
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
|
|
||||||
str = strings.Trim(str, "\n")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
|
|
||||||
// 以下两个空格不一样
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
revel.TemplateFuncs["add"] = func(i int) string {
|
revel.TemplateFuncs["add"] = func(i int) string {
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
return fmt.Sprintf("%v", i)
|
return fmt.Sprintf("%v", i)
|
||||||
@@ -157,33 +144,8 @@ func init() {
|
|||||||
return template.HTML(tagStr)
|
return template.HTML(tagStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
revel.TemplateFuncs["blogTagsForExport"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
|
|
||||||
if tags == nil || len(tags) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
tagStr := ""
|
|
||||||
lenTags := len(tags)
|
|
||||||
|
|
||||||
for i, tag := range tags {
|
|
||||||
str := tag
|
|
||||||
var classes = "label"
|
|
||||||
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
|
|
||||||
classes += " label-" + tag
|
|
||||||
} else {
|
|
||||||
classes += " label-default"
|
|
||||||
}
|
|
||||||
|
|
||||||
classes += " label-post"
|
|
||||||
tagStr += "<span class=\"" + classes + "\" >" + str + "</span>";
|
|
||||||
if i != lenTags - 1 {
|
|
||||||
tagStr += " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return template.HTML(tagStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lea++
|
// lea++
|
||||||
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, typeStr string) template.HTML {
|
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
|
||||||
if tags == nil || len(tags) == 0 {
|
if tags == nil || len(tags) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -192,12 +154,10 @@ func init() {
|
|||||||
lenTags := len(tags)
|
lenTags := len(tags)
|
||||||
|
|
||||||
tagPostUrl := "http://lea.leanote.com/"
|
tagPostUrl := "http://lea.leanote.com/"
|
||||||
if typeStr == "recommend" {
|
if isRecommend {
|
||||||
tagPostUrl += "?tag=";
|
tagPostUrl += "?tag=";
|
||||||
} else if typeStr == "latest" {
|
|
||||||
tagPostUrl += "latest?tag=";
|
|
||||||
} else {
|
} else {
|
||||||
tagPostUrl += "subscription?tag=";
|
tagPostUrl += "latest?tag=";
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tag := range tags {
|
for i, tag := range tags {
|
||||||
@@ -406,13 +366,12 @@ func init() {
|
|||||||
// email配置
|
// email配置
|
||||||
InitEmail()
|
InitEmail()
|
||||||
InitVd()
|
InitVd()
|
||||||
// memcache.InitMemcache() // session服务
|
memcache.InitMemcache() // session服务
|
||||||
// 其它service
|
// 其它service
|
||||||
service.InitService()
|
service.InitService()
|
||||||
controllers.InitService()
|
controllers.InitService()
|
||||||
admin.InitService()
|
admin.InitService()
|
||||||
member.InitService()
|
member.InitService()
|
||||||
service.ConfigS.InitGlobalConfigs()
|
service.ConfigS.InitGlobalConfigs()
|
||||||
api.InitService()
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
@@ -56,14 +56,6 @@ func ClearDir(dir string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func MkdirAll(dir string) bool {
|
|
||||||
err := os.MkdirAll(dir, 0777)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// list dir's all file, return filenames
|
// list dir's all file, return filenames
|
||||||
func ListDir(dir string) []string {
|
func ListDir(dir string) []string {
|
||||||
f, err := os.Open(dir)
|
f, err := os.Open(dir)
|
||||||
|
|||||||
+2
-59
@@ -10,7 +10,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
|
||||||
math_rand "math/rand"
|
math_rand "math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,44 +122,9 @@ func ReplaceAll(oldStr, pattern, newStr string) string {
|
|||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取纯文本
|
|
||||||
func SubStringHTMLToRaw(param string, length int) (result string) {
|
|
||||||
if param == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
result = ""
|
|
||||||
n := 0
|
|
||||||
var temp rune // 中文问题, 用rune来解决
|
|
||||||
rStr := []rune(param)
|
|
||||||
isCode := false
|
|
||||||
for i := 0; i < len(rStr); i++ {
|
|
||||||
temp = rStr[i]
|
|
||||||
if temp == '<' {
|
|
||||||
isCode = true
|
|
||||||
continue
|
|
||||||
} else if temp == '>' {
|
|
||||||
isCode = false
|
|
||||||
result += " "; // 空格
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !isCode {
|
|
||||||
result += string(temp)
|
|
||||||
n++
|
|
||||||
if n >= length {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取摘要, HTML
|
|
||||||
func SubStringHTML(param string, length int, end string) string {
|
func SubStringHTML(param string, length int, end string) string {
|
||||||
if param == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先取出<pre></pre>占位..
|
// 先取出<pre></pre>占位..
|
||||||
|
|
||||||
result := ""
|
result := ""
|
||||||
|
|
||||||
// 1
|
// 1
|
||||||
@@ -232,7 +196,6 @@ func SubStringHTML(param string, length int, end string) string {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否是合格的密码
|
// 是否是合格的密码
|
||||||
func IsGoodPwd(pwd string) (bool, string) {
|
func IsGoodPwd(pwd string) (bool, string) {
|
||||||
if pwd == "" {
|
if pwd == "" {
|
||||||
@@ -249,7 +212,7 @@ func IsEmail(email string) bool {
|
|||||||
if email == "" {
|
if email == "" {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-z\-A-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|\-]?)*[a-zA-Z0-9\-]+\.[0-9a-zA-Z]{2,3}$`, email)
|
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[0-9a-zA-Z]{2,3}$`, email)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,23 +279,3 @@ func InArray(arr []string, str string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将名称的特殊字符去掉
|
|
||||||
func FixFilename(filename string) string {
|
|
||||||
if filename != "" {
|
|
||||||
// 把特殊字段给替换掉
|
|
||||||
// str := `life "%&()+,/:;<>=?@\|`
|
|
||||||
// . == \\.
|
|
||||||
// $ === \\$
|
|
||||||
reg, _ := regexp.Compile("\\.|/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
|
|
||||||
filename = reg.ReplaceAllString(filename, "-")
|
|
||||||
filename = strings.Trim(filename, "-") // 左右单独的-去掉
|
|
||||||
// 把空格替换成-
|
|
||||||
// filename = strings.Replace(filename, " ", "-", -1)
|
|
||||||
for strings.Index(filename, "--") >= 0 { // 防止出现连续的--
|
|
||||||
filename = strings.Replace(filename, "--", "-", -1)
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
// "github.com/leanote/leanote/app/controllers/api"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -55,34 +54,15 @@ func nextKey(key string) string {
|
|||||||
return key[:fieldLen]
|
return key[:fieldLen]
|
||||||
}
|
}
|
||||||
var leanoteStructBinder = revel.Binder{
|
var leanoteStructBinder = revel.Binder{
|
||||||
// name == "noteOrContent"
|
|
||||||
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
||||||
result := reflect.New(typ).Elem() // 创建一个该类型的, 然后其field从所有的param去取
|
result := reflect.New(typ).Elem()
|
||||||
fieldValues := make(map[string]reflect.Value)
|
fieldValues := make(map[string]reflect.Value)
|
||||||
// fmt.Println(name)
|
for key, _ := range params.Values {
|
||||||
// fmt.Println(typ) // api.NoteFiles
|
|
||||||
// name = files[0], files[1], noteContent
|
|
||||||
// fmt.Println(params.Values)
|
|
||||||
/*
|
|
||||||
map[Title:[test1] METHOD:[POST] NotebookId:[54c4f51705fcd14031000002]
|
|
||||||
files[1][FileId]:[]
|
|
||||||
controller:[note]
|
|
||||||
files[1][LocalFileId]:[54c7ae27d98d0329dd000000] files[1][HasBody]:[true] files[0][FileId]:[] files[0][LocalFileId]:[54c7ae855e94ea2dba000000] action:[addNote] Content:[<p>lifedddddd</p><p><img src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" alt="" data-mce-src="app://leanote/data/54bdc65599c37b0da9000002/images/1422368307147_2.png" style="display: block; margin-left: auto; margin-right: auto;"></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae27d98d0329dd000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImg?fileId=54c7ae27d98d0329dd000000"></p><p><br></p><p><img src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" alt="" data-mce-src="http://127.0.0.1:8008/api/file/getImage?fileId=54c7ae855e94ea2dba000000" style="display: block; margin-left: auto; margin-right: auto;"></p><p><br></p><p><br></p>] IsBlog:[false] token:[user1]
|
|
||||||
files[0][HasBody]:[true]]
|
|
||||||
*/
|
|
||||||
nameIsSlice := strings.Contains(name, "[")
|
|
||||||
// fmt.Println(params.Values["files[1]"])
|
|
||||||
// fmt.Println(params.Values["Title"])
|
|
||||||
for key, _ := range params.Values {// Title, Content, Files
|
|
||||||
// 这里, 如果没有点, 默认就是a.
|
// 这里, 如果没有点, 默认就是a.
|
||||||
// life
|
// life
|
||||||
// fmt.Println("key:" + key); // files[0][LocalFileId]
|
|
||||||
// fmt.Println("name:" + name); // files[0][LocalFileId]
|
|
||||||
var suffix string
|
var suffix string
|
||||||
var noPrefix = false
|
var noPrefix = false
|
||||||
if nameIsSlice && strings.HasPrefix(key, name) {
|
if !strings.HasPrefix(key, name + ".") {
|
||||||
suffix = key[len(name)+1:len(key)-1] // files[0][LocalFileId] 去掉 => LocalFileId
|
|
||||||
} else if !strings.HasPrefix(key, name + ".") {
|
|
||||||
noPrefix = true
|
noPrefix = true
|
||||||
suffix = key
|
suffix = key
|
||||||
// continue
|
// continue
|
||||||
@@ -91,18 +71,13 @@ files[0][HasBody]:[true]]
|
|||||||
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
||||||
suffix = key[len(name)+1:]
|
suffix = key[len(name)+1:]
|
||||||
}
|
}
|
||||||
// fmt.Println(suffix);
|
|
||||||
|
|
||||||
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
||||||
// fmt.Println(fieldName);
|
|
||||||
fieldLen := len(fieldName)
|
fieldLen := len(fieldName)
|
||||||
|
|
||||||
if _, ok := fieldValues[fieldName]; !ok {
|
if _, ok := fieldValues[fieldName]; !ok {
|
||||||
// Time to bind this field. Get it and make sure we can set it.
|
// Time to bind this field. Get it and make sure we can set it.
|
||||||
fieldName = strings.Title(fieldName) // 传过来title, 但struct是Title
|
|
||||||
// fmt.Println("xx: " + fieldName)
|
|
||||||
fieldValue := result.FieldByName(fieldName)
|
fieldValue := result.FieldByName(fieldName)
|
||||||
// fmt.Println(fieldValue)
|
|
||||||
if !fieldValue.IsValid() {
|
if !fieldValue.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -112,16 +87,8 @@ files[0][HasBody]:[true]]
|
|||||||
var boundVal reflect.Value
|
var boundVal reflect.Value
|
||||||
// 没有name前缀
|
// 没有name前缀
|
||||||
if(noPrefix) {
|
if(noPrefix) {
|
||||||
// life
|
|
||||||
// fmt.Println("<<")
|
|
||||||
// fmt.Println(strings.Title(key[:fieldLen]));
|
|
||||||
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
||||||
} else {
|
} else {
|
||||||
// fmt.Println("final")
|
|
||||||
// fmt.Println(key[:len(name)+1+fieldLen]) // files[0][HasBody
|
|
||||||
if nameIsSlice {
|
|
||||||
fieldLen += 1
|
|
||||||
}
|
|
||||||
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
|
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
|
||||||
}
|
}
|
||||||
fieldValue.Set(boundVal)
|
fieldValue.Set(boundVal)
|
||||||
@@ -149,8 +116,5 @@ func init() {
|
|||||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.UserAccount{})] = leanoteStructBinder
|
|
||||||
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
|
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
|
||||||
revel.TypeBinders[reflect.TypeOf(info.ApiNote{})] = leanoteStructBinder
|
|
||||||
revel.TypeBinders[reflect.TypeOf(info.NoteFile{})] = leanoteStructBinder
|
|
||||||
}
|
}
|
||||||
@@ -179,6 +179,8 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
|
|
||||||
// 将该basePath下的所有文件提出
|
// 将该basePath下的所有文件提出
|
||||||
files := ListDir(basePath)
|
files := ListDir(basePath)
|
||||||
|
Log(basePath)
|
||||||
|
LogJ(files);
|
||||||
for _, t := range files {
|
for _, t := range files {
|
||||||
if !strings.Contains(t, ".html") {
|
if !strings.Contains(t, ".html") {
|
||||||
continue;
|
continue;
|
||||||
@@ -213,8 +215,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
//
|
// 错误显示
|
||||||
|
|
||||||
|
|
||||||
type ErrorResult struct {
|
type ErrorResult struct {
|
||||||
RenderArgs map[string]interface{}
|
RenderArgs map[string]interface{}
|
||||||
@@ -289,12 +290,13 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
|||||||
r.RenderArgs["Router"] = revel.MainRouter
|
r.RenderArgs["Router"] = revel.MainRouter
|
||||||
|
|
||||||
// 不是preview就不要显示错误了
|
// 不是preview就不要显示错误了
|
||||||
if r.IsPreview {
|
LogJ(revelError)
|
||||||
|
// if r.IsPreview {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
out := io.Writer(resp.Out)
|
out := io.Writer(resp.Out)
|
||||||
// out = ioutil.Discard
|
// out = ioutil.Discard
|
||||||
err = tmpl.Execute(&b, r.RenderArgs)
|
err = tmpl.Execute(&b, r.RenderArgs)
|
||||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
b.WriteTo(out)
|
b.WriteTo(out)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,7 @@ func init() {
|
|||||||
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
||||||
// session.
|
// session.
|
||||||
func (s Session) Id() string {
|
func (s Session) Id() string {
|
||||||
|
|
||||||
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
||||||
return sessionIdStr
|
return sessionIdStr
|
||||||
}
|
}
|
||||||
@@ -157,6 +158,7 @@ func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
|||||||
// c.Session, 重新生成一个revel.Session给controller!!!
|
// c.Session, 重新生成一个revel.Session给controller!!!
|
||||||
// Log("sessoin--------")
|
// Log("sessoin--------")
|
||||||
// LogJ(session)
|
// LogJ(session)
|
||||||
|
|
||||||
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
||||||
c.Session = revelSession
|
c.Session = revelSession
|
||||||
// 生成sessionId
|
// 生成sessionId
|
||||||
|
|||||||
+20
-16
@@ -6,7 +6,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
// "time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -33,7 +32,7 @@ import (
|
|||||||
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
||||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
"js/object_id"}
|
||||||
|
|
||||||
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
||||||
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
||||||
@@ -92,6 +91,7 @@ func dev() {
|
|||||||
"notebook.js": "notebook-min.js",
|
"notebook.js": "notebook-min.js",
|
||||||
"share.js": "share-min.js",
|
"share.js": "share-min.js",
|
||||||
"tag.js": "tag-min.js",
|
"tag.js": "tag-min.js",
|
||||||
|
"main.js": "main-min.js",
|
||||||
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||||
"editor/editor.js": "editor/editor-min.js",
|
"editor/editor.js": "editor/editor-min.js",
|
||||||
@@ -107,13 +107,6 @@ func dev() {
|
|||||||
for key, value := range m {
|
for key, value := range m {
|
||||||
content = strings.Replace(content, key, value, -1)
|
content = strings.Replace(content, key, value, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// var time = time.Now().Unix() % 1000
|
|
||||||
|
|
||||||
// content = strings.Replace(content, "-min.js", fmt.Sprintf("-min.js?r=%d", time), -1)
|
|
||||||
// content = strings.Replace(content, "default{{end}}.css", fmt.Sprintf("default{{end}}.css?r=%d", time), 1)
|
|
||||||
// content = strings.Replace(content, "writting-overwrite.css", fmt.Sprintf("writting-overwrite.css?r=%d", time), 1)
|
|
||||||
|
|
||||||
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
|
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,10 +114,8 @@ func dev() {
|
|||||||
func tinymce() {
|
func tinymce() {
|
||||||
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
|
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
|
||||||
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
||||||
cmd := exec.Command("/bin/sh", "-c", "grunt minify");
|
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
|
||||||
cmd.Dir = base + "/tinymce_4.1.9"
|
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||||
|
|
||||||
fmt.Println("正在build tinymce");
|
|
||||||
|
|
||||||
// 必须要先删除
|
// 必须要先删除
|
||||||
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
|
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
|
||||||
@@ -132,19 +123,32 @@ func tinymce() {
|
|||||||
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
|
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
|
||||||
c, _ := cmd2.CombinedOutput()
|
c, _ := cmd2.CombinedOutput()
|
||||||
fmt.Println(string(c))
|
fmt.Println(string(c))
|
||||||
|
|
||||||
c, _ = cmd.CombinedOutput()
|
c, _ = cmd.CombinedOutput()
|
||||||
fmt.Println(string(c))
|
fmt.Println(string(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 压缩tinymce
|
// 压缩tinymce
|
||||||
// tinymce()
|
tinymce()
|
||||||
|
|
||||||
dev();
|
dev();
|
||||||
|
|
||||||
// 其它零散的需要压缩的js
|
// 其它零散的需要压缩的js
|
||||||
otherJss := []string{"js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
otherJss := []string{"tinymce/tinymce", "js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
||||||
|
"mdeditor/editor/scrollLink",
|
||||||
|
"mdeditor/editor/editor",
|
||||||
|
"mdeditor/editor/jquery.waitforimages",
|
||||||
|
"mdeditor/editor/pagedown/local/Markdown.local.zh",
|
||||||
|
"mdeditor/editor/pagedown/local/Markdown.local.en",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Editor",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Sanitizer",
|
||||||
|
"mdeditor/editor/pagedown/Markdown.Converter",
|
||||||
|
"mdeditor/editor/Markdown.Extra",
|
||||||
|
"mdeditor/editor/underscore",
|
||||||
|
"mdeditor/editor/mathJax",
|
||||||
|
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||||
|
"js/app/editor_drop_paste",
|
||||||
|
"js/app/attachment_upload",
|
||||||
"js/jquery.ztree.all-3.5",
|
"js/jquery.ztree.all-3.5",
|
||||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,29 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/db"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttachService struct {
|
type AttachService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add attach
|
// add attach
|
||||||
// api调用时, 添加attach之前是没有note的
|
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
|
||||||
// fromApi表示是api添加的, updateNote传过来的, 此时不要incNote's usn, 因为updateNote会inc的
|
|
||||||
func (this *AttachService) AddAttach(attach info.Attach, fromApi bool) (ok bool, msg string) {
|
|
||||||
attach.CreatedTime = time.Now()
|
attach.CreatedTime = time.Now()
|
||||||
ok = db.Insert(db.Attachs, attach)
|
ok = db.Insert(db.Attachs, attach)
|
||||||
|
|
||||||
note := noteService.GetNoteById(attach.NoteId.Hex())
|
|
||||||
|
|
||||||
// api调用时, 添加attach之前是没有note的
|
|
||||||
var userId string
|
|
||||||
if note.NoteId != "" {
|
|
||||||
userId = note.UserId.Hex()
|
|
||||||
} else {
|
|
||||||
userId = attach.UploadUserId.Hex()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
// 更新笔记的attachs num
|
// 更新笔记的attachs num
|
||||||
this.updateNoteAttachNum(attach.NoteId, 1)
|
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fromApi {
|
|
||||||
// 增长note's usn
|
|
||||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +46,8 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
|
|||||||
// list attachs
|
// list attachs
|
||||||
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||||
attachs := []info.Attach{}
|
attachs := []info.Attach{}
|
||||||
// 判断是否有权限为笔记添加附件
|
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
||||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||||
return attachs
|
return attachs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,26 +56,12 @@ func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
|||||||
return attachs
|
return attachs
|
||||||
}
|
}
|
||||||
|
|
||||||
// api调用, 通过noteIds得到note's attachs, 通过noteId归类返回
|
|
||||||
func (this *AttachService) getAttachsByNoteIds(noteIds []bson.ObjectId) map[string][]info.Attach {
|
|
||||||
attachs := []info.Attach{}
|
|
||||||
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.M{"$in": noteIds}}, &attachs)
|
|
||||||
noteAttchs := make(map[string][]info.Attach)
|
|
||||||
for _, attach := range attachs {
|
|
||||||
noteId := attach.NoteId.Hex()
|
|
||||||
if itAttachs, ok := noteAttchs[noteId]; ok {
|
|
||||||
noteAttchs[noteId] = append(itAttachs, attach)
|
|
||||||
} else {
|
|
||||||
noteAttchs[noteId] = []info.Attach{attach}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noteAttchs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
||||||
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Delete note to delete attas firstly
|
// Delete note to delete attas firstly
|
||||||
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
@@ -125,11 +94,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
|||||||
attach.Path = strings.TrimLeft(attach.Path, "/")
|
attach.Path = strings.TrimLeft(attach.Path, "/")
|
||||||
err := os.Remove(revel.BasePath + "/" + attach.Path)
|
err := os.Remove(revel.BasePath + "/" + attach.Path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// userService.UpdateAttachSize(note.UserId.Hex(), -attach.Size)
|
return true, "delete file error"
|
||||||
// 修改note Usn
|
|
||||||
noteService.IncrNoteUsn(attach.NoteId.Hex(), userId)
|
|
||||||
|
|
||||||
return true, "delete file success"
|
|
||||||
}
|
}
|
||||||
return false, "delete file error"
|
return false, "delete file error"
|
||||||
}
|
}
|
||||||
@@ -141,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
|||||||
// 获取文件路径
|
// 获取文件路径
|
||||||
// 要判断是否具有权限
|
// 要判断是否具有权限
|
||||||
// userId是否具有attach的访问权限
|
// userId是否具有attach的访问权限
|
||||||
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
|
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
|
||||||
if attachId == "" {
|
if attachId == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -172,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//userId为空则是分享笔记的附件
|
||||||
|
if userId == "" && sessionId != "" {
|
||||||
|
if token != "" {
|
||||||
|
realToken := sessionService.GetToken(sessionId)
|
||||||
|
if token == realToken {
|
||||||
|
Log("attach token is equal!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attach = info.Attach{}
|
attach = info.Attach{}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -204,35 +180,8 @@ func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
|
|||||||
attach.Name = newFilename
|
attach.Name = newFilename
|
||||||
attach.Path = filePath
|
attach.Path = filePath
|
||||||
|
|
||||||
this.AddAttach(attach, false)
|
this.AddAttach(attach)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只留下files的数据, 其它的都删除
|
|
||||||
func (this *AttachService) UpdateOrDeleteAttachApi(noteId, userId string, files []info.NoteFile) bool {
|
|
||||||
// 现在数据库内的
|
|
||||||
attachs := this.ListAttachs(noteId, userId)
|
|
||||||
|
|
||||||
nowAttachs := map[string]bool{}
|
|
||||||
if files != nil {
|
|
||||||
for _, file := range files {
|
|
||||||
if file.IsAttach && file.FileId != "" {
|
|
||||||
nowAttachs[file.FileId] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, attach := range attachs {
|
|
||||||
fileId := attach.AttachId.Hex()
|
|
||||||
if !nowAttachs[fileId] {
|
|
||||||
// 需要删除的
|
|
||||||
// TODO 权限验证去掉
|
|
||||||
this.DeleteAttach(fileId, userId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,6 @@ func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string)
|
|||||||
func (this *AuthService) register(user info.User) (bool, string) {
|
func (this *AuthService) register(user info.User) (bool, string) {
|
||||||
if userService.AddUser(user) {
|
if userService.AddUser(user) {
|
||||||
// 添加笔记本, 生活, 学习, 工作
|
// 添加笔记本, 生活, 学习, 工作
|
||||||
userId := user.UserId.Hex();
|
|
||||||
notebook := info.Notebook{
|
notebook := info.Notebook{
|
||||||
Seq: -1,
|
Seq: -1,
|
||||||
UserId: user.UserId}
|
UserId: user.UserId}
|
||||||
@@ -63,6 +62,8 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
notebookService.AddNotebook(notebook);
|
notebookService.AddNotebook(notebook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
email := user.Email
|
||||||
|
|
||||||
// 添加leanote -> 该用户的共享
|
// 添加leanote -> 该用户的共享
|
||||||
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
||||||
if(registerSharedUserId != "") {
|
if(registerSharedUserId != "") {
|
||||||
@@ -73,23 +74,20 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
// 添加共享笔记本
|
// 添加共享笔记本
|
||||||
for _, notebook := range registerSharedNotebooks {
|
for _, notebook := range registerSharedNotebooks {
|
||||||
perm, _ := strconv.Atoi(notebook["perm"])
|
perm, _ := strconv.Atoi(notebook["perm"])
|
||||||
shareService.AddShareNotebookToUserId(notebook["notebookId"], perm, registerSharedUserId, userId);
|
shareService.AddShareNotebook(notebook["notebookId"], perm, registerSharedUserId, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加共享笔记
|
// 添加共享笔记
|
||||||
for _, note := range registerSharedNotes {
|
for _, note := range registerSharedNotes {
|
||||||
perm, _ := strconv.Atoi(note["perm"])
|
perm, _ := strconv.Atoi(note["perm"])
|
||||||
shareService.AddShareNoteToUserId(note["noteId"], perm, registerSharedUserId, userId);
|
shareService.AddShareNote(note["noteId"], perm, registerSharedUserId, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制笔记
|
// 复制笔记
|
||||||
for _, noteId := range registerCopyNoteIds {
|
for _, noteId := range registerCopyNoteIds {
|
||||||
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
||||||
// Log(noteId)
|
noteUpdate := bson.M{"IsBlog": true}
|
||||||
// Log("Copy")
|
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
||||||
// LogJ(note)
|
|
||||||
noteUpdate := bson.M{"IsBlog": false} // 不要是博客
|
|
||||||
noteService.UpdateNote(user.UserId.Hex(), note.NoteId.Hex(), noteUpdate, -1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +95,7 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
// 添加一条userBlog
|
// 添加一条userBlog
|
||||||
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
||||||
Title: user.Username + " 's Blog",
|
Title: user.Username + " 's Blog",
|
||||||
SubTitle: "Love Leanote!",
|
SubTitle: "love leanote!",
|
||||||
AboutMe: "Hello, I am (^_^)",
|
AboutMe: "Hello, I am (^_^)",
|
||||||
CanComment: true,
|
CanComment: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -69,14 +69,9 @@ func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户共享的notebooks
|
// 得到用户共享的notebooks
|
||||||
// 3/19 博客不是deleted
|
|
||||||
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
||||||
notebooks := []info.Notebook{}
|
notebooks := []info.Notebook{}
|
||||||
orQ := []bson.M{
|
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}, ¬ebooks)
|
||||||
bson.M{"IsDeleted": false},
|
|
||||||
bson.M{"IsDeleted": bson.M{"$exists": false}},
|
|
||||||
}
|
|
||||||
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "$or": orQ}, ¬ebooks)
|
|
||||||
return notebooks
|
return notebooks
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,7 +1094,6 @@ func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool
|
|||||||
|
|
||||||
// 得到用户的博客url
|
// 得到用户的博客url
|
||||||
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
||||||
if userBlog != nil {
|
|
||||||
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||||
return configService.GetUserUrl(userBlog.Domain)
|
return configService.GetUserUrl(userBlog.Domain)
|
||||||
} else if userBlog.SubDomain != "" {
|
} else if userBlog.SubDomain != "" {
|
||||||
@@ -1108,7 +1102,6 @@ func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string
|
|||||||
if username == "" {
|
if username == "" {
|
||||||
username = userBlog.UserId.Hex()
|
username = userBlog.UserId.Hex()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return configService.GetBlogUrl() + "/" + username
|
return configService.GetBlogUrl() + "/" + username
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,10 +1190,6 @@ func (this *BlogService) FixBlog(blog info.BlogItem) info.Post {
|
|||||||
LikeNum: blog.LikeNum,
|
LikeNum: blog.LikeNum,
|
||||||
IsMarkdown: blog.IsMarkdown,
|
IsMarkdown: blog.IsMarkdown,
|
||||||
}
|
}
|
||||||
if blog2.Tags != nil && len(blog2.Tags) > 0 && blog2.Tags[0] != "" {
|
|
||||||
} else {
|
|
||||||
blog2.Tags = nil
|
|
||||||
}
|
|
||||||
return blog2
|
return blog2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
|
|||||||
username, _ := revel.Config.String("db.username")
|
username, _ := revel.Config.String("db.username")
|
||||||
password, _ := revel.Config.String("db.password")
|
password, _ := revel.Config.String("db.password")
|
||||||
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
binPath = binPath + " -h " + host + " -d " + dbname + " --port " + port
|
binPath = binPath + " -h " + host + " -d " + dbname + " -port " + port
|
||||||
if username != "" {
|
if username != "" {
|
||||||
binPath += " -u " + username + " -p " + password
|
binPath += " -u " + username + " -p " + password
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
|||||||
username, _ := revel.Config.String("db.username")
|
username, _ := revel.Config.String("db.username")
|
||||||
password, _ := revel.Config.String("db.password")
|
password, _ := revel.Config.String("db.password")
|
||||||
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
binPath = binPath + " --drop -h " + host + " -d " + dbname + " --port " + port
|
binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
|
||||||
if username != "" {
|
if username != "" {
|
||||||
binPath += " -u " + username + " -p " + password
|
binPath += " -u " + username + " -p " + password
|
||||||
}
|
}
|
||||||
@@ -372,7 +372,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
|||||||
return false, path + " Is Not Exists"
|
return false, path + " Is Not Exists"
|
||||||
}
|
}
|
||||||
|
|
||||||
binPath += " " + path
|
binPath += " --directoryperdb " + path
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", binPath)
|
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||||
Log(binPath);
|
Log(binPath);
|
||||||
@@ -455,15 +455,12 @@ var port string
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
/*
|
|
||||||
不用配置的, 因为最终通过命令可以改, 而且有的使用nginx代理
|
|
||||||
port = strconv.Itoa(revel.HttpPort)
|
port = strconv.Itoa(revel.HttpPort)
|
||||||
if port != "80" {
|
if port != "80" {
|
||||||
port = ":" + port
|
port = ":" + port
|
||||||
} else {
|
} else {
|
||||||
port = "";
|
port = "";
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
||||||
if strings.HasPrefix(siteUrl, "http://") {
|
if strings.HasPrefix(siteUrl, "http://") {
|
||||||
@@ -472,17 +469,6 @@ func init() {
|
|||||||
defaultDomain = siteUrl[len("https://"):]
|
defaultDomain = siteUrl[len("https://"):]
|
||||||
schema = "https://"
|
schema = "https://"
|
||||||
}
|
}
|
||||||
|
|
||||||
// port localhost:9000
|
|
||||||
ports := strings.Split(defaultDomain, ":")
|
|
||||||
if len(ports) == 2 {
|
|
||||||
port = ports[1]
|
|
||||||
}
|
|
||||||
if port == "80" {
|
|
||||||
port = ""
|
|
||||||
} else {
|
|
||||||
port = ":" + port
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,5 +580,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ConfigService) GetVersion() string {
|
func (this *ConfigService) GetVersion() string {
|
||||||
return "1.0-beta.4"
|
return "1.0-beta2"
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
// "fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||||
@@ -118,7 +119,8 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
|||||||
// 获取文件路径
|
// 获取文件路径
|
||||||
// 要判断是否具有权限
|
// 要判断是否具有权限
|
||||||
// userId是否具有fileId的访问权限
|
// userId是否具有fileId的访问权限
|
||||||
func (this *FileService) GetFile(userId, fileId string) string {
|
|
||||||
|
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
|
||||||
if fileId == "" {
|
if fileId == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -131,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. 判断权限
|
// 1. 判断权限
|
||||||
|
//未登录用户,判断token
|
||||||
|
noteIds := noteImageService.GetNoteIds(fileId)
|
||||||
// 是否是我的文件
|
// 是否是我的文件
|
||||||
if userId != "" && file.UserId.Hex() == userId {
|
if userId != "" && file.UserId.Hex() == userId {
|
||||||
return path
|
return path
|
||||||
@@ -141,13 +144,30 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
// 这些笔记是否有public的, 若有则ok
|
// 这些笔记是否有public的, 若有则ok
|
||||||
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||||
|
|
||||||
noteIds := noteImageService.GetNoteIds(fileId)
|
|
||||||
if noteIds != nil && len(noteIds) > 0 {
|
if noteIds != nil && len(noteIds) > 0 {
|
||||||
// 这些笔记是否有public的
|
// 这些笔记是否有public的
|
||||||
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//分享给未注册用户
|
||||||
|
if userId == "" && sessionId != "" {
|
||||||
|
if token != "" {
|
||||||
|
realToken := sessionService.GetToken(sessionId)
|
||||||
|
if token == realToken {
|
||||||
|
Log("image token is equal!")
|
||||||
|
return path
|
||||||
|
} else {
|
||||||
|
Log("image token is different!")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
note := noteService.GetNoteById(noteId.Hex())
|
note := noteService.GetNoteById(noteId.Hex())
|
||||||
@@ -155,6 +175,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// 若有共享给我的笔记?
|
// 若有共享给我的笔记?
|
||||||
// 对该笔记可读?
|
// 对该笔记可读?
|
||||||
@@ -191,6 +212,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 复制图片
|
// 复制图片
|
||||||
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
||||||
// 是否已经复制过了
|
// 是否已经复制过了
|
||||||
@@ -243,9 +265,5 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
|
|||||||
|
|
||||||
// 是否是我的文件
|
// 是否是我的文件
|
||||||
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
||||||
// 如果有问题会panic
|
|
||||||
if !bson.IsObjectIdHex(fileId) || !bson.IsObjectIdHex(userId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
||||||
}
|
}
|
||||||
@@ -32,21 +32,11 @@ func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg stri
|
|||||||
return false, "groupHasUsers"
|
return false, "groupHasUsers"
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if !this.isMyGroup(userId, groupId) {
|
|
||||||
return false, "notMyGroup"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除分组后, 需要删除所有用户分享到该组的笔记本, 笔记
|
|
||||||
|
|
||||||
shareService.DeleteAllShareNotebookGroup(groupId);
|
|
||||||
shareService.DeleteAllShareNoteGroup(groupId);
|
|
||||||
|
|
||||||
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
|
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
|
||||||
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
||||||
|
|
||||||
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改group标题
|
// 修改group标题
|
||||||
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
||||||
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
||||||
@@ -54,14 +44,9 @@ func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bo
|
|||||||
|
|
||||||
// 得到用户的所有分组(包括下的所有用户)
|
// 得到用户的所有分组(包括下的所有用户)
|
||||||
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||||
/*
|
// 得到分组s
|
||||||
// 得到我的分组
|
|
||||||
groups := []info.Group{}
|
groups := []info.Group{}
|
||||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
*/
|
|
||||||
// 我的分组, 及我所属的分组
|
|
||||||
groups := this.GetGroupsContainOf(userId);
|
|
||||||
|
|
||||||
// 得到其下的用户
|
// 得到其下的用户
|
||||||
for i, group := range groups {
|
for i, group := range groups {
|
||||||
group.Users = this.GetUsers(group.GroupId.Hex())
|
group.Users = this.GetUsers(group.GroupId.Hex())
|
||||||
@@ -76,55 +61,6 @@ func (this *GroupService) GetGroups(userId string) ([]info.Group) {
|
|||||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
return groups
|
return groups
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到我的和我所属组的ids
|
|
||||||
func (this *GroupService) GetMineAndBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
|
||||||
// 所属组
|
|
||||||
groupIds := this.GetBelongToGroupIds(userId)
|
|
||||||
|
|
||||||
m := map[bson.ObjectId]bool{}
|
|
||||||
for _, groupId := range groupIds {
|
|
||||||
m[groupId] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 我的组
|
|
||||||
myGroups := this.GetGroups(userId)
|
|
||||||
|
|
||||||
for _, group := range myGroups {
|
|
||||||
if !m[group.GroupId] {
|
|
||||||
groupIds = append(groupIds, group.GroupId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupIds
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取包含此用户的组对象数组
|
|
||||||
// 获取该用户所属组, 和我的组
|
|
||||||
func (this *GroupService) GetGroupsContainOf(userId string) []info.Group {
|
|
||||||
// 我的组
|
|
||||||
myGroups := this.GetGroups(userId)
|
|
||||||
myGroupMap := map[bson.ObjectId]bool{}
|
|
||||||
|
|
||||||
for _, group := range myGroups {
|
|
||||||
myGroupMap[group.GroupId] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所属组
|
|
||||||
groupIds := this.GetBelongToGroupIds(userId)
|
|
||||||
|
|
||||||
groups := []info.Group{}
|
|
||||||
db.ListByQ(db.Groups, bson.M{"_id": bson.M{"$in": groupIds}}, &groups)
|
|
||||||
|
|
||||||
for _, group := range groups {
|
|
||||||
if !myGroupMap[group.GroupId] {
|
|
||||||
myGroups = append(myGroups, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return myGroups
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到分组, shareService用
|
// 得到分组, shareService用
|
||||||
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||||
// 得到分组s
|
// 得到分组s
|
||||||
@@ -167,25 +103,10 @@ func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
|||||||
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
||||||
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断组中是否包含指定用户
|
|
||||||
func (this *GroupService) IsExistsGroupUser(userId, groupId string) (ok bool) {
|
|
||||||
// 如果我拥有这个组, 那也行
|
|
||||||
if this.isMyGroup(userId, groupId) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return db.Has(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId), "GroupId": bson.ObjectIdHex(groupId)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为group添加用户
|
// 为group添加用户
|
||||||
// 用户是否已存在?
|
// 用户是否已存在?
|
||||||
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
// groupId是否是ownUserId的?
|
// groupId是否是ownUserId的?
|
||||||
/*
|
|
||||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
|
||||||
return false, "forbidden"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if !this.isMyGroup(ownUserId, groupId) {
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
return false, "forbidden"
|
return false, "forbidden"
|
||||||
}
|
}
|
||||||
@@ -202,22 +123,11 @@ func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, m
|
|||||||
CreatedTime: time.Now(),
|
CreatedTime: time.Now(),
|
||||||
}), ""
|
}), ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除用户
|
// 删除用户
|
||||||
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
// groupId是否是ownUserId的?
|
// groupId是否是ownUserId的?
|
||||||
/*
|
|
||||||
if !this.IsExistsGroupUser(ownUserId, groupId) {
|
|
||||||
return false, "forbidden"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if !this.isMyGroup(ownUserId, groupId) {
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
return false, "forbidden"
|
return false, "forbidden"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除该用户分享到本组的笔记本, 笔记
|
|
||||||
shareService.DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId);
|
|
||||||
shareService.DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId);
|
|
||||||
|
|
||||||
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,6 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 这个web可以用, 但api会传来, 不用用了
|
|
||||||
// 解析内容中的图片, 建立图片与note的关系
|
// 解析内容中的图片, 建立图片与note的关系
|
||||||
// <img src="/file/outputImage?fileId=12323232" />
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
// 图片必须是我的, 不然不添加
|
// 图片必须是我的, 不然不添加
|
||||||
@@ -39,8 +38,7 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
|||||||
if imgSrc != "" {
|
if imgSrc != "" {
|
||||||
content = "<img src=\"" + imgSrc + "\" >" + content
|
content = "<img src=\"" + imgSrc + "\" >" + content
|
||||||
}
|
}
|
||||||
// life 添加getImage
|
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||||
reg, _ := regexp.Compile("(outputImage|getImage)\\?fileId=([a-z0-9A-Z]{24})")
|
|
||||||
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
||||||
|
|
||||||
// 删除旧的
|
// 删除旧的
|
||||||
@@ -52,8 +50,8 @@ func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content s
|
|||||||
hasAdded := make(map[string]bool)
|
hasAdded := make(map[string]bool)
|
||||||
if find != nil && len(find) > 0 {
|
if find != nil && len(find) > 0 {
|
||||||
for _, each := range find {
|
for _, each := range find {
|
||||||
if each != nil && len(each) == 3 {
|
if each != nil && len(each) == 2 {
|
||||||
fileId = each[2] // 现在有两个子表达式了
|
fileId = each[1]
|
||||||
// 之前没能添加过的
|
// 之前没能添加过的
|
||||||
if _, ok := hasAdded[fileId]; !ok {
|
if _, ok := hasAdded[fileId]; !ok {
|
||||||
Log(fileId)
|
Log(fileId)
|
||||||
@@ -107,48 +105,3 @@ func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId,
|
|||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
func (this *NoteImageService) getImagesByNoteIds(noteIds []bson.ObjectId) map[string][]info.File {
|
|
||||||
noteNoteImages := []info.NoteImage{}
|
|
||||||
db.ListByQ(db.NoteImages, bson.M{"NoteId": bson.M{"$in": noteIds}}, ¬eNoteImages)
|
|
||||||
|
|
||||||
// 得到imageId, 再去files表查所有的Files
|
|
||||||
imageIds := []bson.ObjectId{}
|
|
||||||
|
|
||||||
// 图片1 => N notes
|
|
||||||
imageIdNotes := map[string][]string{} // imageId => [noteId1, noteId2, ...]
|
|
||||||
for _, noteImage := range noteNoteImages {
|
|
||||||
imageId := noteImage.ImageId
|
|
||||||
imageIds = append(imageIds, imageId)
|
|
||||||
|
|
||||||
imageIdHex := imageId.Hex()
|
|
||||||
noteId := noteImage.NoteId.Hex()
|
|
||||||
if notes, ok := imageIdNotes[imageIdHex]; ok {
|
|
||||||
imageIdNotes[imageIdHex] = append(notes, noteId)
|
|
||||||
} else {
|
|
||||||
imageIdNotes[imageIdHex] = []string{noteId}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到所有files
|
|
||||||
files := []info.File{}
|
|
||||||
db.ListByQ(db.Files, bson.M{"_id": bson.M{"$in": imageIds}}, &files)
|
|
||||||
|
|
||||||
// 建立note->file关联
|
|
||||||
noteImages := make(map[string][]info.File)
|
|
||||||
for _, file := range files {
|
|
||||||
fileIdHex := file.FileId.Hex() // == imageId
|
|
||||||
// 这个fileIdHex有哪些notes呢?
|
|
||||||
if notes, ok := imageIdNotes[fileIdHex]; ok {
|
|
||||||
for _, noteId := range notes {
|
|
||||||
if files, ok2 := noteImages[noteId]; ok2 {
|
|
||||||
noteImages[noteId] = append(files, file)
|
|
||||||
} else {
|
|
||||||
noteImages[noteId] = []info.File{file}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noteImages
|
|
||||||
}
|
|
||||||
+36
-312
@@ -17,11 +17,21 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
|||||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//通过附件id得到note
|
||||||
|
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
|
||||||
|
attach := info.Attach{}
|
||||||
|
db.Get(db.Attachs, attachId, &attach)
|
||||||
|
note = info.Note{}
|
||||||
|
noteId := attach.NoteId
|
||||||
|
db.Get(db.Notes, noteId.Hex(), ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// fileService调用
|
// fileService调用
|
||||||
// 不能是已经删除了的, life bug, 客户端删除后, 竟然还能在web上打开
|
|
||||||
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||||
note = info.Note{}
|
note = info.Note{}
|
||||||
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsDeleted": false}, ¬e)
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 得到blog, blogService用
|
// 得到blog, blogService用
|
||||||
@@ -45,115 +55,14 @@ func (this *NoteService) GetNoteAndContent(noteId, userId string) (noteAndConten
|
|||||||
return info.NoteAndContent{note, noteContent}
|
return info.NoteAndContent{note, noteContent}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取同步的笔记
|
|
||||||
// > afterUsn的笔记
|
|
||||||
func (this *NoteService) GetSyncNotes(userId string, afterUsn, maxEntry int) []info.ApiNote {
|
|
||||||
notes := []info.Note{}
|
|
||||||
q := db.Notes.Find(bson.M{
|
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"Usn": bson.M{"$gt": afterUsn},
|
|
||||||
});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬es)
|
|
||||||
|
|
||||||
return this.ToApiNotes(notes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// note与apiNote的转换
|
|
||||||
func (this *NoteService) ToApiNotes(notes []info.Note) []info.ApiNote {
|
|
||||||
// 2, 得到所有图片, 附件信息
|
|
||||||
// 查images表, attachs表
|
|
||||||
if len(notes) > 0 {
|
|
||||||
noteIds := make([]bson.ObjectId, len(notes));
|
|
||||||
for i, note := range notes {
|
|
||||||
noteIds[i] = note.NoteId
|
|
||||||
}
|
|
||||||
noteFilesMap := this.getFiles(noteIds)
|
|
||||||
// 生成info.ApiNote
|
|
||||||
apiNotes := make([]info.ApiNote, len(notes))
|
|
||||||
for i, note := range notes {
|
|
||||||
noteId := note.NoteId.Hex()
|
|
||||||
apiNotes[i] = this.ToApiNote(¬e, noteFilesMap[noteId])
|
|
||||||
}
|
|
||||||
return apiNotes
|
|
||||||
}
|
|
||||||
// 返回空的
|
|
||||||
return []info.ApiNote{}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// note与apiNote的转换
|
|
||||||
func (this *NoteService) ToApiNote(note *info.Note, files []info.NoteFile) info.ApiNote {
|
|
||||||
apiNote := info.ApiNote{
|
|
||||||
NoteId: note.NoteId.Hex(),
|
|
||||||
NotebookId: note.NotebookId.Hex(),
|
|
||||||
UserId : note.UserId.Hex(),
|
|
||||||
Title : note.Title,
|
|
||||||
Tags : note.Tags,
|
|
||||||
IsMarkdown : note.IsMarkdown,
|
|
||||||
IsBlog : note.IsBlog,
|
|
||||||
IsTrash : note.IsTrash,
|
|
||||||
IsDeleted : note.IsDeleted,
|
|
||||||
Usn : note.Usn,
|
|
||||||
CreatedTime : note.CreatedTime,
|
|
||||||
UpdatedTime : note.UpdatedTime,
|
|
||||||
PublicTime : note.PublicTime,
|
|
||||||
Files: files,
|
|
||||||
}
|
|
||||||
return apiNote
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDirtyNotes, 把note的图片, 附件信息都发送给客户端
|
|
||||||
// 客户端保存到本地, 再获取图片, 附件
|
|
||||||
|
|
||||||
// 得到所有图片, 附件信息
|
|
||||||
// 查images表, attachs表
|
|
||||||
// [待测]
|
|
||||||
func (this *NoteService) getFiles(noteIds []bson.ObjectId) map[string][]info.NoteFile {
|
|
||||||
noteImages := noteImageService.getImagesByNoteIds(noteIds);
|
|
||||||
noteAttachs := attachService.getAttachsByNoteIds(noteIds)
|
|
||||||
|
|
||||||
noteFilesMap := map[string][]info.NoteFile{}
|
|
||||||
|
|
||||||
for _, noteId := range noteIds {
|
|
||||||
noteIdHex := noteId.Hex()
|
|
||||||
noteFiles := []info.NoteFile{}
|
|
||||||
// images
|
|
||||||
if images, ok := noteImages[noteIdHex]; ok {
|
|
||||||
for _, image := range images {
|
|
||||||
noteFiles = append(noteFiles, info.NoteFile{
|
|
||||||
FileId: image.FileId.Hex(),
|
|
||||||
Type: image.Type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach
|
|
||||||
if attachs, ok := noteAttachs[noteIdHex]; ok {
|
|
||||||
for _, attach := range attachs {
|
|
||||||
noteFiles = append(noteFiles, info.NoteFile{
|
|
||||||
FileId: attach.AttachId.Hex(),
|
|
||||||
Type: attach.Type,
|
|
||||||
Title: attach.Title,
|
|
||||||
IsAttach: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noteFilesMap[noteIdHex] = noteFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
return noteFilesMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列出note, 排序规则, 还有分页
|
// 列出note, 排序规则, 还有分页
|
||||||
// CreatedTime, UpdatedTime, title 来排序
|
// CreatedTime, UpdatedTime, title 来排序
|
||||||
func (this *NoteService) ListNotes(userId, notebookId string,
|
func (this *NoteService) ListNotes(userId, notebookId string,
|
||||||
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
|
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
|
||||||
notes = []info.Note{}
|
notes = []info.Note{}
|
||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash, "IsDeleted": false}
|
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
query["IsBlog"] = true
|
query["IsBlog"] = true
|
||||||
}
|
}
|
||||||
@@ -223,7 +132,7 @@ func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (note
|
|||||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||||
// [ok]
|
// [ok]
|
||||||
|
|
||||||
func (this *NoteService) AddNote(note info.Note, fromApi bool) info.Note {
|
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId();
|
noteId := bson.NewObjectId();
|
||||||
note.NoteId = noteId;
|
note.NoteId = noteId;
|
||||||
@@ -233,18 +142,14 @@ func (this *NoteService) AddNote(note info.Note, fromApi bool) info.Note {
|
|||||||
note.IsTrash = false
|
note.IsTrash = false
|
||||||
note.UpdatedUserId = note.UserId
|
note.UpdatedUserId = note.UserId
|
||||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||||
note.Usn = userService.IncrUsn(note.UserId.Hex())
|
|
||||||
|
|
||||||
notebookId := note.NotebookId.Hex()
|
|
||||||
|
|
||||||
// api会传IsBlog, web不会传
|
|
||||||
if !fromApi {
|
|
||||||
// 设为blog
|
// 设为blog
|
||||||
|
notebookId := note.NotebookId.Hex()
|
||||||
note.IsBlog = notebookService.IsBlog(notebookId)
|
note.IsBlog = notebookService.IsBlog(notebookId)
|
||||||
}
|
|
||||||
// if note.IsBlog {
|
if note.IsBlog {
|
||||||
note.PublicTime = note.UpdatedTime
|
note.PublicTime = note.UpdatedTime
|
||||||
// }
|
}
|
||||||
|
|
||||||
db.Insert(db.Notes, note)
|
db.Insert(db.Notes, note)
|
||||||
|
|
||||||
@@ -262,7 +167,7 @@ func (this *NoteService) AddSharedNote(note info.Note, myUserId bson.ObjectId) i
|
|||||||
// 判断我是否有权限添加
|
// 判断我是否有权限添加
|
||||||
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
|
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
|
||||||
note.CreatedUserId = myUserId // 是我给共享我的人创建的
|
note.CreatedUserId = myUserId // 是我给共享我的人创建的
|
||||||
return this.AddNote(note, false)
|
return this.AddNote(note)
|
||||||
}
|
}
|
||||||
return info.Note{}
|
return info.Note{}
|
||||||
}
|
}
|
||||||
@@ -282,49 +187,6 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
|||||||
return noteContent;
|
return noteContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// API, abstract, desc需要这里获取
|
|
||||||
// 不需要
|
|
||||||
/*
|
|
||||||
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
|
||||||
if(note.NoteId.Hex() == "") {
|
|
||||||
noteId := bson.NewObjectId();
|
|
||||||
note.NoteId = noteId;
|
|
||||||
}
|
|
||||||
note.CreatedTime = time.Now()
|
|
||||||
note.UpdatedTime = note.CreatedTime
|
|
||||||
note.IsTrash = false
|
|
||||||
note.UpdatedUserId = note.UserId
|
|
||||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
|
||||||
note.Usn = userService.IncrUsn(note.UserId.Hex())
|
|
||||||
|
|
||||||
// desc这里获取
|
|
||||||
desc := SubStringHTMLToRaw(noteContent.Content, 50)
|
|
||||||
note.Desc = desc;
|
|
||||||
|
|
||||||
// 设为blog
|
|
||||||
notebookId := note.NotebookId.Hex()
|
|
||||||
note.IsBlog = notebookService.IsBlog(notebookId)
|
|
||||||
|
|
||||||
if note.IsBlog {
|
|
||||||
note.PublicTime = note.UpdatedTime
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Insert(db.Notes, note)
|
|
||||||
|
|
||||||
// tag1, 不需要了
|
|
||||||
// tagService.AddTags(note.UserId.Hex(), note.Tags)
|
|
||||||
|
|
||||||
// recount notebooks' notes number
|
|
||||||
notebookService.ReCountNotebookNumberNotes(notebookId)
|
|
||||||
|
|
||||||
// 这里, 添加到内容中
|
|
||||||
abstract := SubStringHTML(noteContent.Content, 200, "")
|
|
||||||
noteContent.Abstract = abstract
|
|
||||||
this.AddNoteContent(noteContent)
|
|
||||||
|
|
||||||
return note
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// 添加笔记和内容
|
// 添加笔记和内容
|
||||||
// 这里使用 info.NoteAndContent 接收?
|
// 这里使用 info.NoteAndContent 接收?
|
||||||
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
||||||
@@ -347,24 +209,7 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note
|
|||||||
if note.UserId != myUserId {
|
if note.UserId != myUserId {
|
||||||
note = this.AddSharedNote(note, myUserId)
|
note = this.AddSharedNote(note, myUserId)
|
||||||
} else {
|
} else {
|
||||||
note = this.AddNote(note, false)
|
note = this.AddNote(note)
|
||||||
}
|
|
||||||
if note.NoteId != "" {
|
|
||||||
this.AddNoteContent(noteContent)
|
|
||||||
}
|
|
||||||
return note
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
|
||||||
if(note.NoteId.Hex() == "") {
|
|
||||||
noteId := bson.NewObjectId()
|
|
||||||
note.NoteId = noteId
|
|
||||||
}
|
|
||||||
noteContent.NoteId = note.NoteId
|
|
||||||
if note.UserId != myUserId {
|
|
||||||
note = this.AddSharedNote(note, myUserId)
|
|
||||||
} else {
|
|
||||||
note = this.AddNote(note, true)
|
|
||||||
}
|
}
|
||||||
if note.NoteId != "" {
|
if note.NoteId != "" {
|
||||||
this.AddNoteContent(noteContent)
|
this.AddNoteContent(noteContent)
|
||||||
@@ -373,30 +218,19 @@ func (this *NoteService) AddNoteAndContentApi(note info.Note, noteContent info.N
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记
|
// 修改笔记
|
||||||
// 这里没有判断usn
|
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||||
func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bson.M, usn int) (bool, string, int) {
|
|
||||||
// 是否存在
|
|
||||||
note := this.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
userId := note.UserId.Hex()
|
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH2")
|
Log("NO AUTH2")
|
||||||
return false, "noAuth", 0
|
return false
|
||||||
} else {
|
} else {
|
||||||
Log("HAS AUTH -----------")
|
Log("HAS AUTH -----------")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if usn > 0 && note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否已自定义
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
if note.IsBlog && note.HasSelfDefined {
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
delete(needUpdate, "ImgSrc")
|
delete(needUpdate, "ImgSrc")
|
||||||
delete(needUpdate, "Desc")
|
delete(needUpdate, "Desc")
|
||||||
@@ -404,11 +238,8 @@ func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bso
|
|||||||
|
|
||||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
afterUsn := userService.IncrUsn(userId);
|
|
||||||
needUpdate["Usn"] = afterUsn
|
|
||||||
|
|
||||||
// 添加tag2
|
// 添加tag2
|
||||||
// TODO 这个tag去掉, 添加tag另外添加, 不要这个
|
|
||||||
if tags, ok := needUpdate["Tags"]; ok {
|
if tags, ok := needUpdate["Tags"]; ok {
|
||||||
tagService.AddTagsI(userId, tags)
|
tagService.AddTagsI(userId, tags)
|
||||||
}
|
}
|
||||||
@@ -416,55 +247,10 @@ func (this *NoteService) UpdateNote(updatedUserId, noteId string, needUpdate bso
|
|||||||
// 是否修改了isBlog
|
// 是否修改了isBlog
|
||||||
// 也要修改noteContents的IsBlog
|
// 也要修改noteContents的IsBlog
|
||||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||||
isBlog2 := isBlog.(bool)
|
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog})
|
||||||
if note.IsBlog != isBlog2 {
|
|
||||||
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog2})
|
|
||||||
|
|
||||||
// 重新发布成博客
|
|
||||||
if !note.IsBlog {
|
|
||||||
needUpdate["PublicTime"] = needUpdate["UpdatedTime"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
|
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
|
||||||
if !ok {
|
|
||||||
return ok, "", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新获取之
|
|
||||||
note = this.GetNoteById(noteId)
|
|
||||||
|
|
||||||
hasRecount := false
|
|
||||||
|
|
||||||
// 如果修改了notebookId, 则更新notebookId'count
|
|
||||||
// 两方的notebook也要修改
|
|
||||||
notebookIdI := needUpdate["NotebookId"]
|
|
||||||
if notebookIdI != nil {
|
|
||||||
notebookId := notebookIdI.(bson.ObjectId)
|
|
||||||
if notebookId != "" {
|
|
||||||
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
|
|
||||||
hasRecount = true
|
|
||||||
notebookService.ReCountNotebookNumberNotes(notebookId.Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不要多次更新, isTrash = false, = true都要重新统计
|
|
||||||
if !hasRecount {
|
|
||||||
if _, ok := needUpdate["IsTrash"]; ok {
|
|
||||||
notebookService.ReCountNotebookNumberNotes(note.NotebookId.Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, "", afterUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 附件修改, 增加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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
|
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
|
||||||
@@ -479,50 +265,31 @@ func (this *NoteService) UpdateNoteTitle(userId, updatedUserId, noteId, title st
|
|||||||
}
|
}
|
||||||
|
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
||||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now(), "Usn": userService.IncrUsn(userId)})
|
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记本内容
|
// 修改笔记本内容
|
||||||
// [ok] TODO perm未测
|
// [ok] TODO perm未测
|
||||||
// hasBeforeUpdateNote 之前是否更新过note其它信息, 如果有更新, usn不用更新
|
func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, content, abstract string) bool {
|
||||||
// TODO abstract这里生成
|
|
||||||
func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstract string, hasBeforeUpdateNote bool, usn int) (bool, string, int) {
|
|
||||||
// 是否已自定义
|
|
||||||
note := this.GetNoteById(noteId)
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
userId := note.UserId.Hex()
|
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH")
|
Log("NO AUTH")
|
||||||
return false, "noAuth", 0
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstract重置
|
|
||||||
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||||
"Content": content,
|
"Content": content,
|
||||||
"Abstract": abstract,
|
"Abstract": abstract,
|
||||||
"UpdatedTime": time.Now()}
|
"UpdatedTime": time.Now()}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
if note.IsBlog && note.HasSelfDefined {
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
delete(data, "Abstract")
|
delete(data, "Abstract")
|
||||||
}
|
}
|
||||||
|
|
||||||
// usn, 修改笔记不可能单独修改内容
|
|
||||||
afterUsn := 0
|
|
||||||
// 如果之前没有修改note其它信息, 那么usn++
|
|
||||||
if !hasBeforeUpdateNote {
|
|
||||||
// 需要验证
|
|
||||||
if usn >= 0 && note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
afterUsn = userService.IncrUsn(userId)
|
|
||||||
db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Usn", usn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
||||||
// 这里, 添加历史记录
|
// 这里, 添加历史记录
|
||||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||||
@@ -533,9 +300,9 @@ func (this *NoteService) UpdateNoteContent(updatedUserId, noteId, content, abstr
|
|||||||
// 更新笔记图片
|
// 更新笔记图片
|
||||||
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
||||||
|
|
||||||
return true, "", afterUsn
|
return true
|
||||||
}
|
}
|
||||||
return false, "", 0
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ?????
|
// ?????
|
||||||
@@ -549,7 +316,7 @@ func (this *NoteService) updateNoteImages(noteId string, content string) bool {
|
|||||||
// 更新tags
|
// 更新tags
|
||||||
// [ok] [del]
|
// [ok] [del]
|
||||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{"Tags": tags, "Usn": userService.IncrUsn(userId)})
|
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
||||||
@@ -567,8 +334,6 @@ func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool
|
|||||||
} else {
|
} else {
|
||||||
noteUpdate["HasSelfDefined"] = false
|
noteUpdate["HasSelfDefined"] = false
|
||||||
}
|
}
|
||||||
noteUpdate["Usn"] = userService.IncrUsn(userId)
|
|
||||||
|
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
||||||
// 重新计算tags
|
// 重新计算tags
|
||||||
go (func() {
|
go (func() {
|
||||||
@@ -588,9 +353,7 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
|||||||
|
|
||||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsTrash": false,
|
bson.M{"$set": bson.M{"IsTrash": false,
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId),
|
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||||
"Usn": userService.IncrUsn(userId),
|
|
||||||
}})
|
|
||||||
|
|
||||||
if re {
|
if re {
|
||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
@@ -612,14 +375,13 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
|||||||
// 如果自己的blog状态是true, 不用改变,
|
// 如果自己的blog状态是true, 不用改变,
|
||||||
// 否则, 如果notebookId的blog是true, 则改为true之
|
// 否则, 如果notebookId的blog是true, 则改为true之
|
||||||
// 返回blog状态
|
// 返回blog状态
|
||||||
// move, copy时用
|
|
||||||
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
|
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
|
||||||
if this.IsBlog(noteId) {
|
if this.IsBlog(noteId) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if notebookService.IsBlog(notebookId) {
|
if notebookService.IsBlog(notebookId) {
|
||||||
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsBlog": true, "PublicTime": time.Now()}}) // life
|
bson.M{"$set": bson.M{"IsBlog": true}})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -816,6 +578,7 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
// 统计
|
// 统计
|
||||||
func (this *NoteService) CountNote(userId string) int {
|
func (this *NoteService) CountNote(userId string) int {
|
||||||
@@ -832,42 +595,3 @@ func (this *NoteService) CountBlog(userId string) int {
|
|||||||
}
|
}
|
||||||
return db.Count(db.Notes, q)
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过标签来查询
|
|
||||||
func (this *NoteService) CountNoteByTag(userId string, tag string) int {
|
|
||||||
if tag == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
|
||||||
// "IsTrash": false,
|
|
||||||
"IsDeleted": false,
|
|
||||||
"Tags": bson.M{"$in": []string{tag}}}
|
|
||||||
return db.Count(db.Notes, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除tag
|
|
||||||
// 返回所有note的Usn
|
|
||||||
func (this *NoteService) UpdateNoteToDeleteTag(userId string, targetTag string) map[string]int {
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"Tags": bson.M{"$in": []string{targetTag}}}
|
|
||||||
notes := []info.Note{}
|
|
||||||
db.ListByQ(db.Notes, query, ¬es)
|
|
||||||
ret := map[string]int{}
|
|
||||||
for _, note := range notes {
|
|
||||||
tags := note.Tags
|
|
||||||
if tags == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for i, tag := range tags {
|
|
||||||
if tag == targetTag {
|
|
||||||
tags = tags
|
|
||||||
tags = append(tags[:i], tags[i+1:]...)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
usn := userService.IncrUsn(userId)
|
|
||||||
db.UpdateByQMap(db.Notes, bson.M{"_id": note.NoteId}, bson.M{"Usn": usn, "Tags": tags})
|
|
||||||
ret[note.NoteId.Hex()] = usn
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,6 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
|
||||||
// "html"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 笔记本
|
// 笔记本
|
||||||
@@ -42,9 +40,7 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
|
|||||||
for _, each := range userNotebooks {
|
for _, each := range userNotebooks {
|
||||||
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
|
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
|
||||||
newNotebooks.NotebookId = each.NotebookId
|
newNotebooks.NotebookId = each.NotebookId
|
||||||
newNotebooks.Title = each.Title;
|
newNotebooks.Title = each.Title
|
||||||
// newNotebooks.Title = html.EscapeString(each.Title)
|
|
||||||
newNotebooks.Title = strings.Replace(strings.Replace(each.Title, "<script>", "", -1), "</script", "", -1)
|
|
||||||
newNotebooks.Seq = each.Seq
|
newNotebooks.Seq = each.Seq
|
||||||
newNotebooks.UserId = each.UserId
|
newNotebooks.UserId = each.UserId
|
||||||
newNotebooks.ParentNotebookId = each.ParentNotebookId
|
newNotebooks.ParentNotebookId = each.ParentNotebookId
|
||||||
@@ -115,24 +111,12 @@ func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOr
|
|||||||
return notebook
|
return notebook
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步的方法
|
|
||||||
func (this *NotebookService) GeSyncNotebooks(userId string, afterUsn, maxEntry int) ([]info.Notebook) {
|
|
||||||
notebooks := []info.Notebook{}
|
|
||||||
q := db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬ebooks)
|
|
||||||
return notebooks
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到用户下所有的notebook
|
// 得到用户下所有的notebook
|
||||||
// 排序好之后返回
|
// 排序好之后返回
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
|
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
|
||||||
userNotebooks := []info.Notebook{}
|
userNotebooks := []info.Notebook{}
|
||||||
orQ := []bson.M{
|
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId)}).All(&userNotebooks)
|
||||||
bson.M{"IsDeleted": false},
|
|
||||||
bson.M{"IsDeleted": bson.M{"$exists": false}},
|
|
||||||
}
|
|
||||||
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "$or": orQ}).All(&userNotebooks)
|
|
||||||
|
|
||||||
if len(userNotebooks) == 0 {
|
if len(userNotebooks) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -157,46 +141,14 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
|||||||
|
|
||||||
// 添加
|
// 添加
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) (bool, info.Notebook) {
|
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||||
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||||
notebook.Usn = userService.IncrUsn(notebook.UserId.Hex())
|
|
||||||
now := time.Now()
|
|
||||||
notebook.CreatedTime = now
|
|
||||||
notebook.UpdatedTime = now
|
|
||||||
err := db.Notebooks.Insert(notebook)
|
err := db.Notebooks.Insert(notebook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, notebook
|
panic(err)
|
||||||
}
|
|
||||||
return true, notebook
|
|
||||||
}
|
|
||||||
// 更新笔记, api
|
|
||||||
func (this *NotebookService) UpdateNotebookApi(userId, notebookId, title, parentNotebookId string, seq, usn int) (bool, string, info.Notebook) {
|
|
||||||
if notebookId == "" {
|
|
||||||
return false, "notebookIdNotExists", info.Notebook{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先判断usn是否和数据库的一样, 如果不一样, 则冲突, 不保存
|
|
||||||
notebook := this.GetNotebookById(notebookId)
|
|
||||||
// 不存在
|
|
||||||
if notebook.NotebookId == "" {
|
|
||||||
return false, "notExists", notebook
|
|
||||||
} else if notebook.Usn != usn {
|
|
||||||
return false, "conflict", notebook
|
|
||||||
}
|
|
||||||
notebook.Usn = userService.IncrUsn(userId);
|
|
||||||
notebook.Title = title;
|
|
||||||
|
|
||||||
updates := bson.M{"Title": title, "Usn": notebook.Usn, "Seq": seq, "UpdatedTime": time.Now()};
|
|
||||||
if(parentNotebookId != "" && bson.IsObjectIdHex(parentNotebookId)) {
|
|
||||||
updates["ParentNotebookId"] = bson.ObjectIdHex(parentNotebookId);
|
|
||||||
} else {
|
} else {
|
||||||
updates["ParentNotebookId"] = "";
|
|
||||||
}
|
}
|
||||||
ok := db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates);
|
return true
|
||||||
if ok {
|
|
||||||
return ok, "", this.GetNotebookById(notebookId)
|
|
||||||
}
|
|
||||||
return false, "", notebook
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否是blog
|
// 判断是否是blog
|
||||||
@@ -222,22 +174,19 @@ func (this *NotebookService) UpdateNotebook(notebook info.Notebook) bool {
|
|||||||
// 更新笔记本标题
|
// 更新笔记本标题
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
|
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
|
||||||
usn := userService.IncrUsn(userId)
|
return db.UpdateByIdAndUserIdField(db.Notebooks, notebookId, userId, "Title", title)
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Title": title, "Usn": usn})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新notebook
|
// 更新notebook
|
||||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
needUpdate["Usn"] = userService.IncrUsn(userId)
|
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToBlog or Not
|
// ToBlog or Not
|
||||||
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
||||||
updates := bson.M{"IsBlog": isBlog, "Usn": userService.IncrUsn(userId)}
|
|
||||||
// 笔记本
|
// 笔记本
|
||||||
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, updates)
|
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"IsBlog": isBlog})
|
||||||
|
|
||||||
// 更新笔记
|
// 更新笔记
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
@@ -248,8 +197,6 @@ func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (boo
|
|||||||
} else {
|
} else {
|
||||||
data["HasSelfDefined"] = false
|
data["HasSelfDefined"] = false
|
||||||
}
|
}
|
||||||
// usn
|
|
||||||
data["Usn"] = userService.IncrUsn(userId)
|
|
||||||
db.UpdateByQMap(db.Notes, q, data)
|
db.UpdateByQMap(db.Notes, q, data)
|
||||||
|
|
||||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||||
@@ -280,10 +227,7 @@ func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, st
|
|||||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false}) == 0 { // 不包含trash
|
"IsTrash": false}) == 0 { // 不包含trash
|
||||||
// 不是真删除 1/20, 为了同步笔记本
|
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||||
ok := db.UpdateByQMap(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, bson.M{"IsDeleted": true, "Usn": userService.IncrUsn(userId)})
|
|
||||||
return ok, ""
|
|
||||||
// return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
|
||||||
}
|
}
|
||||||
return false, "笔记本下有笔记"
|
return false, "笔记本下有笔记"
|
||||||
} else {
|
} else {
|
||||||
@@ -291,18 +235,6 @@ func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API调用, 删除笔记本, 不作笔记控制
|
|
||||||
func (this *NotebookService) DeleteNotebookForce(userId, notebookId string, usn int) (bool, string) {
|
|
||||||
notebook := this.GetNotebookById(notebookId)
|
|
||||||
// 不存在
|
|
||||||
if notebook.NotebookId == "" {
|
|
||||||
return false, "notExists"
|
|
||||||
} else if notebook.Usn != usn {
|
|
||||||
return false, "conflict"
|
|
||||||
}
|
|
||||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
// 传入 notebookId => Seq
|
// 传入 notebookId => Seq
|
||||||
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
|
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
|
||||||
@@ -313,7 +245,7 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
|||||||
}
|
}
|
||||||
|
|
||||||
for notebookId, seq := range notebookId2Seqs {
|
for notebookId, seq := range notebookId2Seqs {
|
||||||
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) {
|
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), bson.ObjectIdHex(userId), "Seq", seq) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,14 +253,15 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序和设置父
|
|
||||||
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
ok := false
|
ok := false
|
||||||
// 如果没parentNotebookId, 则parentNotebookId设空
|
// 如果没parentNotebookId, 则parentNotebookId设空
|
||||||
if(parentNotebookId == "") {
|
if(parentNotebookId == "") {
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": "", "Usn": userService.IncrUsn(userId)});
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", "");
|
||||||
} else {
|
} else {
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, curNotebookId, userId, bson.M{"ParentNotebookId": bson.ObjectIdHex(parentNotebookId), "Usn": userService.IncrUsn(userId)});
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", bson.ObjectIdHex(parentNotebookId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -337,7 +270,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
|
|||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
for seq, notebookId := range siblings {
|
for seq, notebookId := range siblings {
|
||||||
if !db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"Seq": seq, "Usn": userService.IncrUsn(userId)}) {
|
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), userIdO, "Seq", seq) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,7 +283,7 @@ func (this *NotebookService) DragNotebooks(userId string, curNotebookId string,
|
|||||||
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
|
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
|
||||||
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
|
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
|
||||||
notebookIdO := bson.ObjectIdHex(notebookId)
|
notebookIdO := bson.ObjectIdHex(notebookId)
|
||||||
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false, "IsDeleted": false})
|
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false})
|
||||||
Log(count)
|
Log(count)
|
||||||
Log(notebookId)
|
Log(notebookId)
|
||||||
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
|
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
|
|||||||
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||||
bson.M{key: value, "UpdatedTime": time.Now()})
|
bson.M{key: value, "UpdatedTime": time.Now()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
|
||||||
|
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||||
|
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 注销时清空session
|
// 注销时清空session
|
||||||
func (this *SessionService) Clear(sessionId string) bool {
|
func (this *SessionService) Clear(sessionId string) bool {
|
||||||
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
|
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
|
||||||
@@ -70,19 +77,18 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------
|
|
||||||
// API
|
// 附件token
|
||||||
func (this *SessionService) GetUserId(sessionId string) string {
|
func (this *SessionService) GetToken(sessionId string) string {
|
||||||
session := this.Get(sessionId)
|
session := this.Get(sessionId)
|
||||||
// 更新updateTime, 避免过期
|
return session.Token
|
||||||
db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
|
||||||
bson.M{"UpdatedTime": time.Now()})
|
|
||||||
return session.UserId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录成功后设置userId
|
func (this *SessionService) SetToken(sessionId, token string) bool {
|
||||||
func (this *SessionService) SetUserId(sessionId, userId string) bool {
|
|
||||||
this.Get(sessionId)
|
this.Get(sessionId)
|
||||||
ok := this.Update(sessionId, "UserId", userId)
|
Log(sessionId)
|
||||||
|
Log(token)
|
||||||
|
ok := this.UpdateToken(sessionId, "Token", token)
|
||||||
|
Log(ok)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
+65
-55
@@ -7,6 +7,9 @@ import (
|
|||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"sort"
|
"sort"
|
||||||
|
"math/rand"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 共享Notebook, Note服务
|
// 共享Notebook, Note服务
|
||||||
@@ -33,9 +36,8 @@ type ShareService struct {
|
|||||||
|
|
||||||
// 谁共享给了我的Query
|
// 谁共享给了我的Query
|
||||||
func (this *ShareService) getOrQ(userId string) bson.M {
|
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||||
// 得到我和和我参与的组织
|
// 得到我参与的组织
|
||||||
groupIds := groupService.GetMineAndBelongToGroupIds(userId)
|
groupIds := groupService.GetBelongToGroupIds(userId)
|
||||||
|
|
||||||
q := bson.M{}
|
q := bson.M{}
|
||||||
if len(groupIds) > 0 {
|
if len(groupIds) > 0 {
|
||||||
orQ := []bson.M{
|
orQ := []bson.M{
|
||||||
@@ -52,8 +54,6 @@ func (this *ShareService) getOrQ(userId string) bson.M {
|
|||||||
|
|
||||||
// 得到共享给我的笔记本和用户(谁共享给了我)
|
// 得到共享给我的笔记本和用户(谁共享给了我)
|
||||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||||
myUserId := userId
|
|
||||||
|
|
||||||
// 得到共享给我的用户s信息
|
// 得到共享给我的用户s信息
|
||||||
// 得到我参与的组织
|
// 得到我参与的组织
|
||||||
q := this.getOrQ(userId)
|
q := this.getOrQ(userId)
|
||||||
@@ -67,15 +67,7 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
|
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
|
||||||
|
|
||||||
userIds := append(userIds1, userIds2...)
|
userIds := append(userIds1, userIds2...)
|
||||||
|
|
||||||
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||||
// 不要我的id
|
|
||||||
for i, userInfo := range userInfos {
|
|
||||||
if userInfo.UserId.Hex() == myUserId {
|
|
||||||
userInfos = append(userInfos[:i], userInfos[i+1:]...)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// 得到他们共享给我的notebooks
|
// 得到他们共享给我的notebooks
|
||||||
@@ -113,11 +105,6 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
// 先建立userId => []
|
// 先建立userId => []
|
||||||
for _, eachSub := range subShareNotebooks {
|
for _, eachSub := range subShareNotebooks {
|
||||||
userId := eachSub.Notebook.UserId
|
userId := eachSub.Notebook.UserId
|
||||||
// 我自己的, 算了
|
|
||||||
if userId.Hex() == myUserId {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := shareNotebooksByUsersMap[userId]; ok {
|
if _, ok := shareNotebooksByUsersMap[userId]; ok {
|
||||||
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
|
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
|
||||||
} else {
|
} else {
|
||||||
@@ -310,11 +297,7 @@ func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId,
|
|||||||
if toUserId == "" {
|
if toUserId == "" {
|
||||||
return false, "无该用户", ""
|
return false, "无该用户", ""
|
||||||
}
|
}
|
||||||
return this.AddShareNotebookToUserId(notebookId, perm, userId, toUserId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 第三方注册时没有email
|
|
||||||
func (this *ShareService) AddShareNotebookToUserId(notebookId string, perm int, userId, toUserId string) (bool, string, string) {
|
|
||||||
// 添加一条记录说明两者存在关系
|
// 添加一条记录说明两者存在关系
|
||||||
this.AddHasShareNote(userId, toUserId);
|
this.AddHasShareNote(userId, toUserId);
|
||||||
|
|
||||||
@@ -347,11 +330,7 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
|||||||
if toUserId == "" {
|
if toUserId == "" {
|
||||||
return false, "无该用户", ""
|
return false, "无该用户", ""
|
||||||
}
|
}
|
||||||
return this.AddShareNoteToUserId(noteId, perm, userId, toUserId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 第三方测试没有userId
|
|
||||||
func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId, toUserId string) (bool, string, string) {
|
|
||||||
// 添加一条记录说明两者存在关系
|
// 添加一条记录说明两者存在关系
|
||||||
this.AddHasShareNote(userId, toUserId);
|
this.AddHasShareNote(userId, toUserId);
|
||||||
|
|
||||||
@@ -361,12 +340,14 @@ func (this *ShareService) AddShareNoteToUserId(noteId string, perm int, userId,
|
|||||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||||
UserId: bson.ObjectIdHex(userId),
|
UserId: bson.ObjectIdHex(userId),
|
||||||
ToUserId: bson.ObjectIdHex(toUserId),
|
ToUserId: bson.ObjectIdHex(toUserId),
|
||||||
Perm: perm,
|
Perm: perm,
|
||||||
CreatedTime: time.Now(),
|
CreatedTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,7 +671,8 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
|||||||
|
|
||||||
// 得到笔记分享给的groups
|
// 得到笔记分享给的groups
|
||||||
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
||||||
groups := groupService.GetGroupsContainOf(userId)
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
// 得到有分享的分组
|
// 得到有分享的分组
|
||||||
shares := []info.ShareNote{}
|
shares := []info.ShareNote{}
|
||||||
@@ -717,7 +699,9 @@ func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.Share
|
|||||||
|
|
||||||
// 共享笔记给分组
|
// 共享笔记给分组
|
||||||
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
||||||
if !groupService.IsExistsGroupUser(userId, groupId) {
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +729,8 @@ func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) b
|
|||||||
|
|
||||||
// 得到笔记本分享给的groups
|
// 得到笔记本分享给的groups
|
||||||
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
||||||
groups := groupService.GetGroupsContainOf(userId)
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
// 得到有分享的分组
|
// 得到有分享的分组
|
||||||
shares := []info.ShareNotebook{}
|
shares := []info.ShareNotebook{}
|
||||||
@@ -772,7 +757,9 @@ func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []in
|
|||||||
}
|
}
|
||||||
// 共享笔记给分组
|
// 共享笔记给分组
|
||||||
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
||||||
if !groupService.IsExistsGroupUser(userId, groupId) {
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,35 +783,58 @@ func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId s
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
|
||||||
// 删除组时, 删除所有的
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
func (this *ShareService) DeleteAllShareNotebookGroup(groupId string) bool {
|
func (this *ShareService) GenSharePass(noteId string) (int, bool) {
|
||||||
return db.Delete(db.ShareNotebooks, bson.M{
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
pass := 1000 + r.Intn(9000)
|
||||||
});
|
|
||||||
}
|
ok := db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$set": bson.M{"SharePass": pass}})
|
||||||
func (this *ShareService) DeleteAllShareNoteGroup(groupId string) bool {
|
return pass, ok
|
||||||
return db.Delete(db.ShareNotes, bson.M{
|
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------
|
func (this *ShareService) QuerySharePass(noteId string) int {
|
||||||
// 删除组内用户时, 删除其分享的
|
note := &info.Note{}
|
||||||
//--------------------
|
db.Get(db.Notes, noteId, note)
|
||||||
|
|
||||||
func (this *ShareService) DeleteShareNotebookGroupWhenDeleteGroupUser(userId, groupId string) bool {
|
return note.SharePass
|
||||||
return db.Delete(db.ShareNotebooks, bson.M{
|
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *ShareService) DeleteShareNoteGroupWhenDeleteGroupUser(userId, groupId string) bool {
|
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
|
||||||
return db.Delete(db.ShareNotes, bson.M{
|
note = info.Note{}
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
if note.SharePass == sharePass {
|
||||||
});
|
note = noteService.GetNoteById(noteId)
|
||||||
|
noteContent = noteService.GetNoteContent(noteId, note.UserId.Hex())
|
||||||
|
flag = true
|
||||||
|
} else {
|
||||||
|
note = info.Note{}
|
||||||
|
noteContent = info.NoteContent{}
|
||||||
|
flag = false
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//把笔记中含有attachID的url后加上token,返回笔记中含有的attachids
|
||||||
|
func (this *ShareService) AppendToken4URL(token, content string) (c string, attachIds map[string]bool) {
|
||||||
|
re := regexp.MustCompile(`href=\"(.*?attachId.*?)\".*?data-mce-href=\"(.*?attachId.*?)\"`)
|
||||||
|
re2 := regexp.MustCompile(`\"(.*?attachId.*?)\"`)
|
||||||
|
|
||||||
|
attachIds = map[string]bool{}
|
||||||
|
s := re.ReplaceAllStringFunc(content, func(m string) string {
|
||||||
|
idx := strings.Index(m, "attachId=") + len("attachId=")
|
||||||
|
var ss []byte = []byte(m)
|
||||||
|
attachId := string(ss[idx: idx + 24])
|
||||||
|
attachIds[attachId] = true
|
||||||
|
return re2.ReplaceAllString(m, `"${1}&token=` + token + `"`)
|
||||||
|
})
|
||||||
|
|
||||||
|
re3 := regexp.MustCompile(`<img\s+src=\"(.*?fileId.*?)\".*?data-mce-src=\"(.*?fileId.*?)\"`)
|
||||||
|
re4 := regexp.MustCompile(`\"(.*?fileId.*?)\"`)
|
||||||
|
|
||||||
|
c = re3.ReplaceAllStringFunc(s, func(m string) string {
|
||||||
|
return re4.ReplaceAllString(m, `"${1}&token=` + token + `"`)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+2
-100
@@ -3,9 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -14,14 +14,12 @@ import (
|
|||||||
type TagService struct {
|
type TagService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (this *TagService) GetTags(userId string) []string {
|
func (this *TagService) GetTags(userId string) []string {
|
||||||
tag := info.Tag{}
|
tag := info.Tag{}
|
||||||
db.Get(db.Tags, userId, &tag)
|
db.Get(db.Tags, userId, &tag)
|
||||||
LogJ(tag)
|
LogJ(tag)
|
||||||
return tag.Tags
|
return tag.Tags
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
|
func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
|
||||||
if ts, ok2 := tags.([]string); ok2 {
|
if ts, ok2 := tags.([]string); ok2 {
|
||||||
@@ -39,99 +37,3 @@ func (this *TagService) AddTags(userId string, tags []string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------
|
|
||||||
// v2
|
|
||||||
// 第二版标签, 单独一张表, 每一个tag一条记录
|
|
||||||
|
|
||||||
// 添加或更新标签, 先查下是否存在, 不存在则添加, 存在则更新
|
|
||||||
// 都要统计下tag的note数
|
|
||||||
// 什么时候调用? 笔记添加Tag, 删除Tag时
|
|
||||||
// 删除note时, 都可以调用
|
|
||||||
// 万能
|
|
||||||
func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
|
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
db.GetByQ(db.NoteTags, bson.M{"UserId": userIdO, "Tag": tag}, ¬eTag)
|
|
||||||
|
|
||||||
// 存在, 则更新之
|
|
||||||
if noteTag.TagId != "" {
|
|
||||||
// 统计note数
|
|
||||||
count := noteService.CountNoteByTag(userId, tag)
|
|
||||||
noteTag.Count = count
|
|
||||||
noteTag.UpdatedTime = time.Now()
|
|
||||||
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
|
|
||||||
db.UpdateByIdAndUserId(db.NoteTags, noteTag.TagId.Hex(), userId, noteTag)
|
|
||||||
return noteTag
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不存在, 则创建之
|
|
||||||
noteTag.TagId = bson.NewObjectId()
|
|
||||||
noteTag.Count = 1
|
|
||||||
noteTag.Tag = tag
|
|
||||||
noteTag.UserId = bson.ObjectIdHex(userId)
|
|
||||||
noteTag.CreatedTime = time.Now()
|
|
||||||
noteTag.UpdatedTime = noteTag.CreatedTime
|
|
||||||
noteTag.Usn = userService.IncrUsn(userId)
|
|
||||||
noteTag.IsDeleted = false
|
|
||||||
db.Insert(db.NoteTags, noteTag)
|
|
||||||
|
|
||||||
return noteTag
|
|
||||||
}
|
|
||||||
|
|
||||||
// 得到标签, 按更新时间来排序
|
|
||||||
func (this *TagService) GetTags(userId string) []info.NoteTag {
|
|
||||||
tags := []info.NoteTag{}
|
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsDeleted": false}
|
|
||||||
q := db.NoteTags.Find(query);
|
|
||||||
sortFieldR := "-UpdatedTime"
|
|
||||||
q.Sort(sortFieldR).All(&tags)
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签
|
|
||||||
// 也删除所有的笔记含该标签的
|
|
||||||
// 返回noteId => usn
|
|
||||||
func (this *TagService) DeleteTag(userId string, tag string) map[string]int {
|
|
||||||
usn := userService.IncrUsn(userId)
|
|
||||||
if db.UpdateByQMap(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, bson.M{"Usn": usn, "IsDeleted": true}) {
|
|
||||||
return noteService.UpdateNoteToDeleteTag(userId, tag);
|
|
||||||
}
|
|
||||||
return map[string]int{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除标签, 供API调用
|
|
||||||
func (this *TagService) DeleteTagApi(userId string, tag string, usn int) (ok bool, msg string, toUsn int) {
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
db.GetByQ(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, ¬eTag)
|
|
||||||
|
|
||||||
if noteTag.TagId == "" {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
if noteTag.Usn > usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
toUsn = userService.IncrUsn(userId)
|
|
||||||
if db.UpdateByQMap(db.NoteTags, bson.M{"UserId": bson.ObjectIdHex(userId), "Tag": tag}, bson.M{"Usn": usn, "IsDeleted": true}) {
|
|
||||||
return true, "", toUsn
|
|
||||||
}
|
|
||||||
return false, "", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新统计标签的count
|
|
||||||
func (this *TagService) reCountTagCount(userId string, tags []string) {
|
|
||||||
if tags == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, tag := range tags {
|
|
||||||
this.AddOrUpdateTag(userId, tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同步用
|
|
||||||
func (this *TagService) GeSyncTags(userId string, afterUsn, maxEntry int) ([]info.NoteTag) {
|
|
||||||
noteTags := []info.NoteTag{}
|
|
||||||
q := db.NoteTags.Find(bson.M{"UserId": bson.ObjectIdHex(userId), "Usn": bson.M{"$gt": afterUsn}});
|
|
||||||
q.Sort("Usn").Limit(maxEntry).All(¬eTags)
|
|
||||||
return noteTags
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,7 @@ func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
|||||||
// 首先删除其共享
|
// 首先删除其共享
|
||||||
if shareService.DeleteShareNoteAll(noteId, userId) {
|
if shareService.DeleteShareNoteAll(noteId, userId) {
|
||||||
// 更新note isTrash = true
|
// 更新note isTrash = true
|
||||||
if db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true, "Usn": userService.IncrUsn(userId)}}) {
|
if db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}}) {
|
||||||
// recount notebooks' notes number
|
// recount notebooks' notes number
|
||||||
notebookIdO := noteService.GetNotebookId(noteId)
|
notebookIdO := noteService.GetNotebookId(noteId)
|
||||||
notebookId := notebookIdO.Hex()
|
notebookId := notebookIdO.Hex()
|
||||||
@@ -44,7 +44,7 @@ func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
|||||||
func (this *TrashService) DeleteSharedNote(noteId, userId, myUserId string) bool {
|
func (this *TrashService) DeleteSharedNote(noteId, userId, myUserId string) bool {
|
||||||
note := noteService.GetNote(noteId, userId)
|
note := noteService.GetNote(noteId, userId)
|
||||||
if shareService.HasUpdatePerm(userId, myUserId, noteId) && note.CreatedUserId.Hex() == myUserId {
|
if shareService.HasUpdatePerm(userId, myUserId, noteId) && note.CreatedUserId.Hex() == myUserId {
|
||||||
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true, "Usn": userService.IncrUsn(userId)}})
|
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}})
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -53,63 +53,23 @@ func (this *TrashService) DeleteSharedNote(noteId, userId, myUserId string) bool
|
|||||||
func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
||||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsTrash": false,
|
bson.M{"$set": bson.M{"IsTrash": false,
|
||||||
"Usn": userService.IncrUsn(userId),
|
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除trash
|
// 删除trash
|
||||||
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
||||||
note := noteService.GetNote(noteId, userId);
|
|
||||||
if note.NoteId == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// delete note's attachs
|
// delete note's attachs
|
||||||
ok := attachService.DeleteAllAttachs(noteId, userId)
|
ok := attachService.DeleteAllAttachs(noteId, userId)
|
||||||
|
|
||||||
// 设置删除位
|
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
|
||||||
bson.M{"IsDeleted": true,
|
|
||||||
"Usn": userService.IncrUsn(userId)})
|
|
||||||
// delete note
|
// delete note
|
||||||
// ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
||||||
|
|
||||||
// delete content
|
// delete content
|
||||||
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
||||||
|
|
||||||
// 重新统计tag's count
|
|
||||||
// TODO 这里会改变tag's Usn
|
|
||||||
tagService.reCountTagCount(userId, note.Tags)
|
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *TrashService) DeleteTrashApi(noteId, userId string, usn int) (bool, string, int) {
|
|
||||||
note := noteService.GetNote(noteId, userId)
|
|
||||||
|
|
||||||
if note.NoteId == "" || note.IsDeleted {
|
|
||||||
return false, "notExists", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if note.Usn != usn {
|
|
||||||
return false, "conflict", 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete note's attachs
|
|
||||||
ok := attachService.DeleteAllAttachs(noteId, userId)
|
|
||||||
|
|
||||||
// 设置删除位
|
|
||||||
afterUsn := userService.IncrUsn(userId)
|
|
||||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
|
||||||
bson.M{"IsDeleted": true,
|
|
||||||
"Usn": afterUsn})
|
|
||||||
|
|
||||||
// delete content
|
|
||||||
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
|
||||||
|
|
||||||
return ok, "", afterUsn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列出note, 排序规则, 还有分页
|
// 列出note, 排序规则, 还有分页
|
||||||
// CreatedTime, UpdatedTime, title 来排序
|
// CreatedTime, UpdatedTime, title 来排序
|
||||||
func (this *TrashService) ListNotes(userId string,
|
func (this *TrashService) ListNotes(userId string,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func (this *UpgradeService) UpgradeBlog() bool {
|
|||||||
*/
|
*/
|
||||||
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
||||||
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
||||||
return false, "Leanote have been upgraded"
|
return false, "已升级"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. aboutMe -> page
|
// 1. aboutMe -> page
|
||||||
@@ -102,81 +102,3 @@ func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg stri
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usn设置
|
|
||||||
// 客户端 api
|
|
||||||
|
|
||||||
func (this *UpgradeService) moveTag() {
|
|
||||||
usnI := 1
|
|
||||||
tags := []info.Tag{}
|
|
||||||
db.ListByQ(db.Tags, bson.M{}, &tags)
|
|
||||||
for _, eachTag := range tags {
|
|
||||||
tagTitles := eachTag.Tags
|
|
||||||
now := time.Now()
|
|
||||||
if tagTitles != nil && len(tagTitles) > 0 {
|
|
||||||
for _, tagTitle := range tagTitles {
|
|
||||||
noteTag := info.NoteTag{}
|
|
||||||
noteTag.TagId = bson.NewObjectId()
|
|
||||||
noteTag.Count = 1
|
|
||||||
noteTag.Tag = tagTitle
|
|
||||||
noteTag.UserId = eachTag.UserId
|
|
||||||
noteTag.CreatedTime = now
|
|
||||||
noteTag.UpdatedTime = now
|
|
||||||
noteTag.Usn = usnI
|
|
||||||
noteTag.IsDeleted = false
|
|
||||||
db.Insert(db.NoteTags, noteTag)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpgradeService) setNotebookUsn() {
|
|
||||||
usnI := 1
|
|
||||||
notebooks := []info.Notebook{}
|
|
||||||
db.ListByQWithFields(db.Notebooks, bson.M{}, []string{"UserId"}, ¬ebooks)
|
|
||||||
|
|
||||||
for _, notebook := range notebooks {
|
|
||||||
db.UpdateByQField(db.Notebooks, bson.M{"_id": notebook.NotebookId}, "Usn", usnI)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UpgradeService) setNoteUsn() {
|
|
||||||
usnI := 1
|
|
||||||
notes := []info.Note{}
|
|
||||||
db.ListByQWithFields(db.Notes, bson.M{}, []string{"UserId"}, ¬es)
|
|
||||||
|
|
||||||
for _, note := range notes {
|
|
||||||
db.UpdateByQField(db.Notes, bson.M{"_id": note.NoteId}, "Usn", usnI)
|
|
||||||
usnI++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 升级为Api, beta.4
|
|
||||||
func (this *UpgradeService) Api(userId string) (ok bool, msg string) {
|
|
||||||
if configService.GetGlobalStringConfig("UpgradeBetaToBeta4") != "" {
|
|
||||||
return false, "Leanote have been upgraded"
|
|
||||||
}
|
|
||||||
|
|
||||||
// user
|
|
||||||
db.UpdateByQField(db.Users, bson.M{}, "Usn", 200000)
|
|
||||||
|
|
||||||
// notebook
|
|
||||||
db.UpdateByQField(db.Notebooks, bson.M{}, "IsDeleted", false)
|
|
||||||
this.setNotebookUsn();
|
|
||||||
|
|
||||||
// note
|
|
||||||
// 1-N
|
|
||||||
db.UpdateByQField(db.Notes, bson.M{}, "IsDeleted", false)
|
|
||||||
this.setNoteUsn();
|
|
||||||
|
|
||||||
// tag
|
|
||||||
// 1-N
|
|
||||||
/// tag, 要重新插入, 将之前的Tag表迁移到NoteTag中
|
|
||||||
this.moveTag();
|
|
||||||
|
|
||||||
configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToBeta4", "1")
|
|
||||||
|
|
||||||
return true, ""
|
|
||||||
}
|
|
||||||
@@ -12,27 +12,6 @@ import (
|
|||||||
type UserService struct {
|
type UserService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自增Usn
|
|
||||||
// 每次notebook,note添加, 修改, 删除, 都要修改
|
|
||||||
func (this *UserService) IncrUsn(userId string) int {
|
|
||||||
user := info.User{}
|
|
||||||
query := bson.M{"_id": bson.ObjectIdHex(userId)}
|
|
||||||
db.GetByQWithFields(db.Users, query, []string{"Usn"}, &user)
|
|
||||||
usn := user.Usn
|
|
||||||
usn += 1
|
|
||||||
Log("inc Usn")
|
|
||||||
db.UpdateByQField(db.Users, query, "Usn", usn)
|
|
||||||
return usn
|
|
||||||
// return db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"ReadNum": 1}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UserService) GetUsn(userId string) int {
|
|
||||||
user := info.User{}
|
|
||||||
query := bson.M{"_id": bson.ObjectIdHex(userId)}
|
|
||||||
db.GetByQWithFields(db.Users, query, []string{"Usn"}, &user)
|
|
||||||
return user.Usn
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加用户
|
// 添加用户
|
||||||
func (this *UserService) AddUser(user info.User) bool {
|
func (this *UserService) AddUser(user info.User) bool {
|
||||||
if user.UserId == "" {
|
if user.UserId == "" {
|
||||||
@@ -69,6 +48,13 @@ func (this *UserService) GetUsername(userId string) string {
|
|||||||
return user.Username
|
return user.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 得到用户名
|
||||||
|
func (this *UserService) GetUsernameById(userId bson.ObjectId) string {
|
||||||
|
user := info.User{}
|
||||||
|
db.GetByQWithFields(db.Users, bson.M{"_id": userId}, []string{"Username"}, &user)
|
||||||
|
return user.Username
|
||||||
|
}
|
||||||
|
|
||||||
// 是否存在该用户 email
|
// 是否存在该用户 email
|
||||||
func (this *UserService) IsExistsUser(email string) bool {
|
func (this *UserService) IsExistsUser(email string) bool {
|
||||||
if this.GetUserId(email) == "" {
|
if this.GetUserId(email) == "" {
|
||||||
@@ -119,8 +105,6 @@ func (this *UserService) GetUserInfo(userId string) info.User {
|
|||||||
func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
||||||
// Logo路径问题, 有些有http: 有些没有
|
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
// 得到用户信息 username
|
// 得到用户信息 username
|
||||||
@@ -128,15 +112,12 @@ func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
|||||||
user := info.User{}
|
user := info.User{}
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
||||||
// Logo路径问题, 有些有http: 有些没有
|
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *UserService) GetUserInfoByThirdUserId(thirdUserId string) info.User {
|
func (this *UserService) GetUserInfoByThirdUserId(thirdUserId string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
db.GetByQ(db.Users, bson.M{"ThirdUserId": thirdUserId}, &user)
|
db.GetByQ(db.Users, bson.M{"ThirdUserId": thirdUserId}, &user)
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.User {
|
func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.User {
|
||||||
@@ -249,7 +230,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
|||||||
} else {
|
} else {
|
||||||
db.GetByQ(db.Users, bson.M{"Username": emailOrUsername, "Pwd": md5Pwd}, &user)
|
db.GetByQ(db.Users, bson.M{"Username": emailOrUsername, "Pwd": md5Pwd}, &user)
|
||||||
}
|
}
|
||||||
this.setUserLogo(&user)
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -229,12 +229,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="/admin/t?t=upgrade/beta2">
|
<a href="/admin/t?t=upgrade/beta2">
|
||||||
<span>
|
<span>
|
||||||
v1.0-beta to v1.0-beta.2
|
v1.0-beta to v1.0-beta2
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a href="/admin/t?t=upgrade/beta3">
|
|
||||||
<span>
|
|
||||||
v1.0-beta.2/3 to v1.0-beta.4
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="hidden-xs">
|
<li class="hidden-xs">
|
||||||
<a href="/blog" class="dk" target="_blank">
|
<a href="/blog/admin" class="dk" target="_blank">
|
||||||
My Blog
|
My Blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{{template "admin/top.html" .}}
|
{{template "admin/top.html" .}}
|
||||||
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta to v1.0-beta.2</h3></div>
|
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta to v1.0-beta2</h3></div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<footer class="panel-footer text-right bg-light lter">
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade to v1.0-beta.2</button>
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade</button>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
@@ -31,7 +31,6 @@ $(function() {
|
|||||||
$("#submit").click(function(e){
|
$("#submit").click(function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var t = this;
|
var t = this;
|
||||||
art.confirm("Are you sure to upgrade to v1.0-beta.2", function() {
|
|
||||||
$(t).button('loading');
|
$(t).button('loading');
|
||||||
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
||||||
$(t).button('reset')
|
$(t).button('reset')
|
||||||
@@ -43,7 +42,6 @@ $("#submit").click(function(e){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{template "admin/end.html" .}}
|
{{template "admin/end.html" .}}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
{{template "admin/top.html" .}}
|
|
||||||
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta.2/3 to v1.0-beta.4</h3></div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<form id="add_user_form">
|
|
||||||
<section class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
Current Version: <span class="label label-success">leanote v{{.version}}</span>
|
|
||||||
<ul>
|
|
||||||
<li>Api support (Enable Leanote Desktop App to connect server))</li>
|
|
||||||
<li>Update tags</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<footer class="panel-footer text-right bg-light lter">
|
|
||||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade to v1.0-beta.4</button>
|
|
||||||
</footer>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{template "admin/footer.html" .}}
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#submit").click(function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var t = this;
|
|
||||||
art.confirm("Are you sure to upgrade to v1.0-beta.4 ? Please don't try to upgrade twice.", function() {
|
|
||||||
$(t).button('loading');
|
|
||||||
ajaxPost("/adminUpgrade/UpgradeBeta3ToBeta4", {}, function(ret){
|
|
||||||
$(t).button('reset')
|
|
||||||
if(!ret.Ok) {
|
|
||||||
art.alert(ret.Msg)
|
|
||||||
} else {
|
|
||||||
art.tips("Success");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{template "admin/end.html" .}}
|
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
<a href="http://weibo.com/leanotecom" target="_blank"><i class="fa fa-weibo"></i></a>
|
<a href="http://weibo.com/leanotecom" target="_blank"><i class="fa fa-weibo"></i></a>
|
||||||
<br />
|
<br />
|
||||||
leanote@leanote.com
|
leanote@leanote.com
|
||||||
<br />
|
<div id="beian">
|
||||||
Copyright © 2014-2015 <a href="http://leanote.com">Leanote</a>
|
<a href="http://www.miibeian.gov.cn" target="_blank">沪ICP备14006011号</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<i class="fa fa-globe fa-3x icon-muted"></i>
|
<i class="fa fa-globe fa-3x icon-muted"></i>
|
||||||
|
|||||||
+19
-24
@@ -5,8 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="keywords" content="leanote,leanote.com">
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
<meta name="description" content="Leanote, {{msg $ "moto"}}">
|
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||||
<meta property="qc:admins" content="2451332115167456375" />
|
|
||||||
<meta name="author" content="leanote">
|
<meta name="author" content="leanote">
|
||||||
<title>{{.title}}</title>
|
<title>{{.title}}</title>
|
||||||
|
|
||||||
@@ -38,33 +37,30 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
<div id="lang">
|
|
||||||
<a data-lang="en-us">English</a>
|
|
||||||
<a data-lang="fr-fr">Français</a>
|
|
||||||
<a data-lang="zh-cn">简体中文</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-left">
|
<ul class="nav navbar-nav navbar-left">
|
||||||
<li><a href="/index#" data-target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||||
<li style="position: relative;">
|
<!--
|
||||||
<a id="" href="http://leanote.com/service" title="" class="">{{msg . "service"}}</a>
|
<li><a href="/index#aboutLeanote" target="#aboutLeanote" class="smooth-scroll">{{msg . "aboutLeanote"}}</a> </li>
|
||||||
|
-->
|
||||||
|
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
||||||
|
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
||||||
|
<li style="position: relative; margin-right: 3px;">
|
||||||
|
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
||||||
<div class="red-circle" style=""></div>
|
<div class="red-circle" style=""></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li style="position: relative; margin-right: 3px;">
|
|
||||||
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
|
||||||
</li>
|
|
||||||
<li><a id="leanoteBlog" href="http://lea.leanote.com" target="_blank" title="lea++, leanote blog platform" class="">lea++</a></li>
|
|
||||||
<li><a id="leanoteApp" href="http://app.leanote.com" target="_blank" title="Leanote App" class="">{{msg . "desktopApp"}}</a></li>
|
|
||||||
<li><a href="http://leanote.org" target="_blank" title="leanote.org" class="">leanote.org</a></li>
|
|
||||||
|
|
||||||
{{if .userInfo.Email}}
|
|
||||||
<li id="loginBtns">
|
<li id="loginBtns">
|
||||||
|
{{if .userInfo.Email}}
|
||||||
{{msg . "hi"}}, {{.userInfo.Username}}
|
{{msg . "hi"}}, {{.userInfo.Username}}
|
||||||
<a href="{{$.noteUrl}}">{{msg . "myNote"}}</a>
|
<a href="{{$.noteUrl}}">{{msg . "myNote"}}</a>
|
||||||
<a href="/logout">{{msg . "logout"}}</a>
|
<a href="/logout">{{msg . "logout"}}</a>
|
||||||
</li>
|
{{else}}
|
||||||
|
<a href="/login">{{msg . "login"}}</a>
|
||||||
|
{{if .openRegister}}
|
||||||
|
<a href="/register" class="btn-register">{{msg . "register"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,11 +90,10 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul id="blogNav" class="pull-right">
|
<ul id="blogNav" class="pull-right">
|
||||||
<li><a href="#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||||
<li><a href="#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
||||||
<li><a href="#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
||||||
<li><a id="leanoteBlog" href="{{.leaUrl}}/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
|
<li><a id="leanoteBlog" href="{{.leaUrl}}/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
|
||||||
|
|
||||||
<li style="position: relative; margin-right: 3px;">
|
<li style="position: relative; margin-right: 3px;">
|
||||||
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
||||||
<div style="position: absolute;
|
<div style="position: absolute;
|
||||||
|
|||||||
@@ -4,22 +4,23 @@
|
|||||||
</style>
|
</style>
|
||||||
<section>
|
<section>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>Leanote, {{msg . "moto"}}</h2>
|
<h2>leanote, {{msg . "moto"}}</h2>
|
||||||
<p>{{msg . "moto3"}}</p>
|
<p>{{msg . "moto3"}}</p>
|
||||||
<p>
|
<p>
|
||||||
Knowledge, Blog, Sharing, Cooperation... all in leanote
|
Knowledge, Blog, Sharing, Cooperation... all in leanote
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/login">{{msg . "login"}}</a>
|
|
||||||
{{if .openRegister}}
|
{{if .openRegister}}
|
||||||
|
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
@@ -65,6 +66,20 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="download">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:300px; margin:auto; padding: 10px;">
|
||||||
|
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||||
|
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<div class="container" id="donate">
|
<div class="container" id="donate">
|
||||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -119,19 +134,6 @@ $(function() {
|
|||||||
var targetOffset = $(t).offset().top - 80;
|
var targetOffset = $(t).offset().top - 80;
|
||||||
$('html,body').animate({scrollTop: targetOffset}, 300);
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setCookie(name, value) {
|
|
||||||
var Days = 10*365;
|
|
||||||
var exp = new Date();
|
|
||||||
exp.setTime(exp.getTime() + Days*24*60*60*1000);
|
|
||||||
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#lang a').click(function() {
|
|
||||||
var lang = $(this).data('lang');
|
|
||||||
setCookie('LEANOTE_LANG', lang);
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</style>
|
</style>
|
||||||
<section>
|
<section>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>Leanote, {{msg . "moto"}}</h2>
|
<h2>leanote, {{msg . "moto"}}</h2>
|
||||||
<p>{{msg . "moto3"}}</p>
|
<p>{{msg . "moto3"}}</p>
|
||||||
<p>{{msg . "moto2"}}</p>
|
<p>{{msg . "moto2"}}</p>
|
||||||
|
|
||||||
@@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/login">{{msg . "login"}}</a>
|
|
||||||
{{if .openRegister}}
|
{{if .openRegister}}
|
||||||
|
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
@@ -64,6 +64,20 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<div class="container" id="download">
|
||||||
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div style="width:300px; margin:auto; padding: 10px;">
|
||||||
|
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||||
|
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<div class="container" id="donate">
|
<div class="container" id="donate">
|
||||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -119,19 +133,6 @@ $(function() {
|
|||||||
var targetOffset = $(t).offset().top - 80;
|
var targetOffset = $(t).offset().top - 80;
|
||||||
$('html,body').animate({scrollTop: targetOffset}, 300);
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setCookie(name, value) {
|
|
||||||
var Days = 10*365;
|
|
||||||
var exp = new Date();
|
|
||||||
exp.setTime(exp.getTime() + Days*24*60*60*1000);
|
|
||||||
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#lang a').click(function() {
|
|
||||||
var lang = $(this).data('lang');
|
|
||||||
setCookie('LEANOTE_LANG', lang);
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<a href="/index">{{msg . "home"}}</a>
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="/index">leanote</a> © 2014-2015
|
<a href="/index">leanote</a> © 2014
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
|
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||||
|
<meta name="author" content="leanote">
|
||||||
|
|
||||||
|
<title>{{.title}}</title>
|
||||||
|
<link href="{{.siteUrl}}/css/bootstrap.css" rel="stylesheet">
|
||||||
|
<link id="styleLink" href="{{.siteUrl}}/css/toImage.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1 class="title">
|
||||||
|
{{.blog.Title}}
|
||||||
|
</h1>
|
||||||
|
<div class="created-time">
|
||||||
|
{{ if .userBlog.Logo}}
|
||||||
|
<img src="{{.userBlog.Logo}}" id="logo">
|
||||||
|
{{else}}
|
||||||
|
<img src="{{$.siteUrl}}/images/blog/default_avatar.png" id="logo">
|
||||||
|
{{end}}
|
||||||
|
{{.userInfo.Username}}
|
||||||
|
|
||||||
|
{{if .blog.Tags}}
|
||||||
|
<img src="{{$.siteUrl}}/images/blog/tag.png" id="tag">
|
||||||
|
{{blogTags .blog.Tags}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="desc">
|
||||||
|
{{if .blog.IsMarkdown }}
|
||||||
|
<div id="markdownContent" style="display: none">
|
||||||
|
<!-- 用textarea装html, 防止得到的值失真 -->
|
||||||
|
<textarea>
|
||||||
|
{{.content | raw}}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
<div id="parsedContent">
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{.content | raw}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
<p>
|
||||||
|
{{ if .userBlog.Logo}}
|
||||||
|
<img src="{{.userBlog.Logo}}" id="logo">
|
||||||
|
{{else}}
|
||||||
|
<img src="{{$.siteUrl}}/images/blog/default_avatar.png" id="logo">
|
||||||
|
{{end}}
|
||||||
|
(<a href="#">http://blog.leanote.com/{{.userInfo.Username}}</a>)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<img src="{{.siteUrl}}/images/logo/leanote_white.png" id="leanote_logo"/>
|
||||||
|
<p>
|
||||||
|
leanote, {{msg $ "moto"}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="{{.siteUrl}}/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/js/bootstrap-min.js"></script>
|
||||||
|
|
||||||
|
<link href="{{.siteUrl}}/public/mdeditor/editor/google-code-prettify/prettify.css" type="text/css" rel="stylesheet">
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||||
|
<script>
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{if .blog.IsMarkdown }}
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/pagedown/Markdown.Converter.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/pagedown/Markdown.Sanitizer.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/pagedown/local/Markdown.local.zh.js"></script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/Markdown.Extra.js"></script>
|
||||||
|
|
||||||
|
<!--mathjax-->
|
||||||
|
<script type="text/x-mathjax-config">
|
||||||
|
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||||
|
</script>
|
||||||
|
<script src="{{.siteUrl}}/public/mdeditor/editor/mathJax.js"></script>
|
||||||
|
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
<script>
|
||||||
|
var content = $.trim($("#markdownContent textarea").val());
|
||||||
|
var converter = Markdown.getSanitizingConverter();
|
||||||
|
Markdown.Extra.init(converter, {extensions: ["tables", "fenced_code_gfm", "def_list"]});
|
||||||
|
var html = converter.makeHtml(content);
|
||||||
|
$("#parsedContent").html(html);
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
lif------------
|
||||||
|
e
|
||||||
|
|
||||||
|
you can
|
||||||
@@ -40,32 +40,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<style>
|
|
||||||
.mce-btn.mce-active, .mce-btn.mce-active:hover {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
}
|
|
||||||
.mce-btn {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{template "member/footer.html" .}}
|
{{template "member/footer.html" .}}
|
||||||
<script type="text/javascript" src="/tinymce/tinymce.js"></script>
|
<script type="text/javascript" src="/tinymce/tinymce.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var urlPrefix = "{{.siteUrl}}";
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
var LeaAce = {nowIsInAce: function() {return false;}};
|
|
||||||
$(function() {
|
$(function() {
|
||||||
tinymce.init({
|
tinymce.init({
|
||||||
selector : "#content1",
|
selector : "#content1",
|
||||||
content_css : ["/css/editor/editor.css" ],
|
content_css : [ "/css/bootstrap.css", "/css/editor/editor.css" ],
|
||||||
theme : "leanote",
|
skin : "custom",
|
||||||
language : "{{.locale}}",
|
language : "{{.locale}}",
|
||||||
height : 300,
|
height : 300,
|
||||||
width : "100%",
|
width : "100%",
|
||||||
// skin : "custom",
|
skin : "custom",
|
||||||
plugins : [
|
plugins : [
|
||||||
"advlist autolink link lists charmap hr ",
|
"advlist autolink link leanote_image lists charmap hr ",
|
||||||
"searchreplace visualblocks visualchars tabfocus",
|
"searchreplace visualblocks visualchars tabfocus",
|
||||||
"table contextmenu directionality textcolor fullpage textcolor"],
|
"table contextmenu directionality textcolor paste fullpage textcolor"],
|
||||||
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
|
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
|
||||||
menubar : false,
|
menubar : false,
|
||||||
statusbar : false,
|
statusbar : false,
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
{{range .myTpls}}
|
{{range .myTpls}}
|
||||||
<a href="#" class="list-group-item " data-file="{{.}}">
|
<a href="#" class="list-group-item " data-file="{{.}}">
|
||||||
<i class="fa fa-remove icon-muted remove-file" title="delete file" ></i>
|
<i class="fa fa-remove icon-muted remove-file" title="delete file" ></i>
|
||||||
<span class="filename" data-filename="{{.}}">{{.}}</span>
|
{{.}}
|
||||||
<span class="badge"></span>
|
<span class="badge"></span>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -123,7 +123,7 @@ var theme = {
|
|||||||
saveBtnO: $("#saveBtn"),
|
saveBtnO: $("#saveBtn"),
|
||||||
newFileO: $("#newFile"),
|
newFileO: $("#newFile"),
|
||||||
curTpl: "",
|
curTpl: "",
|
||||||
tplInfos: {"header.html": "{{msg . "header"}}", "footer.html": "{{msg . "footer"}}", "index.html": "{{msg . "index"}}", "cate.html": "{{msg . "cate"}}", "search.html": "{{msg . "search"}}", "single.html": "{{msg . "single"}}", "archive.html": "{{msg . "archive"}}", "post.html": "{{msg . "post"}}", "tags.html": "{{msg . "tags"}}", "tag_posts.html": "{{msg . "tag_posts"}}", "share_comment.html": "{{msg . "share_comment"}}", "404.html":"404", "theme.json": "{{msg . "themeJson"}}", "paging.html": "{{msg . "paging"}}", "highlight.html": "{{msg . "highlight"}}"},
|
tplInfos: {"header.html": "{{msg . "header"}}", "footer.html": "{{msg . "footer"}}", "index.html": "{{msg . "header"}}", "cate.html": "{{msg . "cate"}}", "search.html": "{{msg . "search"}}", "single.html": "{{msg . "single"}}", "archive.html": "{{msg . "archive"}}", "post.html": "{{msg . "post"}}", "tags.html": "{{msg . "tags"}}", "tag_posts.html": "{{msg . "tag_posts"}}", "share_comment.html": "{{msg . "share_comment"}}", "404.html":"404", "theme.json": "{{msg . "themeJson"}}", "paging.html": "{{msg . "paging"}}", "highlight.html": "{{msg . "highlight"}}"},
|
||||||
init: function() {
|
init: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.showTplInfo();
|
self.showTplInfo();
|
||||||
@@ -171,22 +171,12 @@ var theme = {
|
|||||||
newFile: function() {
|
newFile: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.newFileO.click(function() {
|
self.newFileO.click(function() {
|
||||||
// 文件是否存在?
|
art.prompt("文件名", function(file){
|
||||||
|
|
||||||
|
|
||||||
art.prompt("Filename", function(file) {
|
|
||||||
if(!file) {
|
if(!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if($('[data-filename="' + file + '"]').length > 0) {
|
var t = '<a href="#" class="list-group-item " data-file="' + file + '"> <i class="fa fa-remove icon-muted remove-file" title="delete file" ></i> ' + file + '<span class="badge"></span></a>';
|
||||||
art.alert('File exists');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var t = $('<a href="#" class="list-group-item " data-file="' + file + '"> <i class="fa fa-remove icon-muted remove-file" title="delete file" ></i> <span class="filename" data-filename="' + file + '">' + file + '</span><span class="badge"></span></a>');
|
|
||||||
$(".file-list").append(t);
|
$(".file-list").append(t);
|
||||||
self.cache[file] = "";
|
|
||||||
// trigger click, 选中之
|
|
||||||
t.click();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -216,9 +206,6 @@ var theme = {
|
|||||||
var content = editor.getValue()
|
var content = editor.getValue()
|
||||||
|
|
||||||
var filename = self.curTpl;
|
var filename = self.curTpl;
|
||||||
if(!filename) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 之前的内容是否有改动
|
// 之前的内容是否有改动
|
||||||
if(self.cache[filename] == content) {
|
if(self.cache[filename] == content) {
|
||||||
return;
|
return;
|
||||||
@@ -247,7 +234,7 @@ var theme = {
|
|||||||
renderContent: function(name, content) {
|
renderContent: function(name, content) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.curTplO.html(name);
|
self.curTplO.html(name);
|
||||||
self.curTpl = name; // 这里才设置
|
self.curTpl = name; // 这里设计
|
||||||
var lang = "html";
|
var lang = "html";
|
||||||
if(name.indexOf(".js") > 0 || name.indexOf(".json") > 0) {
|
if(name.indexOf(".js") > 0 || name.indexOf(".json") > 0) {
|
||||||
lang = "javascript";
|
lang = "javascript";
|
||||||
@@ -264,8 +251,8 @@ var theme = {
|
|||||||
renderTpl: function(name) {
|
renderTpl: function(name) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var content = "";
|
var content = "";
|
||||||
self.curTpl = ""; // 这里设置为空
|
self.curTpl = name; // 这里设置
|
||||||
if(self.cache[name] != undefined) {
|
if(self.cache[name]) {
|
||||||
content = self.cache[name];
|
content = self.cache[name];
|
||||||
self.renderContent(name, content);
|
self.renderContent(name, content);
|
||||||
return;
|
return;
|
||||||
@@ -277,7 +264,6 @@ var theme = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//-----------------
|
//-----------------
|
||||||
// theme images
|
// theme images
|
||||||
imageListO: $("#imageList"),
|
imageListO: $("#imageList"),
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
<meta name="apple-touch-fullscreen" content="yes">
|
<meta name="apple-touch-fullscreen" content="yes">
|
||||||
<meta name=”apple-mobile-web-app-capable” content=”yes” />
|
<meta name=”apple-mobile-web-app-capable” content=”yes” />
|
||||||
<meta name="keywords" content="leanote,leanote.com">
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
<meta name="description" content="Leanote, {{msg $ "moto"}}">
|
<meta name="description" content="leanote, Not Just A Notebook">
|
||||||
<title>Leanote, {{msg $ "moto"}}</title>
|
<title>leanote, Not Just A Notebook</title>
|
||||||
|
|
||||||
<link href="/css/bootstrap.css" rel="stylesheet" />
|
<link href="/css/bootstrap.css" rel="stylesheet" />
|
||||||
<!-- 先加载, 没有样式, 宽度不定 -->
|
<!-- 先加载, 没有样式, 宽度不定 -->
|
||||||
@@ -186,11 +186,13 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
<div class="pull-right top-nav writting-hide lea-blog">
|
<div class="pull-right top-nav writting-hide lea-blog">
|
||||||
<a target="_blank" href="http://lea.leanote.com">
|
<a target="_blank" href="http://lea.leanote.com">
|
||||||
lea++
|
lea++
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
<div class="pull-right top-nav writting-hide" id="myBlog">
|
<div class="pull-right top-nav writting-hide" id="myBlog">
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
@@ -414,7 +416,29 @@ function log(o) {
|
|||||||
<div class="noteSplit" id="noteSplitter"></div>
|
<div class="noteSplit" id="noteSplitter"></div>
|
||||||
|
|
||||||
<div id="note">
|
<div id="note">
|
||||||
|
<!-- 只读模式 -->
|
||||||
|
<div id="noteRead">
|
||||||
|
<div id="noteReadContainer">
|
||||||
|
<div id="noteReadTop">
|
||||||
|
<h2 id="noteReadTitle"></h2>
|
||||||
|
<div class="clearfix" id="noteReadInfo">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
<span id="noteReadTags"></span>
|
||||||
|
|
||||||
|
<!-- 修改时间 -->
|
||||||
|
<i class="fa fa-clock-o"></i>{{msg . "update"}}
|
||||||
|
<span id="noteReadUpdatedTime"></span>
|
||||||
|
|
||||||
|
<!-- 修改时间 -->
|
||||||
|
<i class="fa fa-clock-o"></i>{{msg . "create"}}
|
||||||
|
<span id="noteReadCreatedTime"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="noteReadContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 遮罩, 为了resize3Columns用 -->
|
<!-- 遮罩, 为了resize3Columns用 -->
|
||||||
<div id="noteMask" class="note-mask"></div>
|
<div id="noteMask" class="note-mask"></div>
|
||||||
<div id="noteMaskForLoading" class="note-mask">
|
<div id="noteMaskForLoading" class="note-mask">
|
||||||
@@ -522,38 +546,17 @@ function log(o) {
|
|||||||
<div id="noteTitleDiv">
|
<div id="noteTitleDiv">
|
||||||
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}" tabindex="1" />
|
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}" tabindex="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 只读时 -->
|
|
||||||
<div id="noteReadTop">
|
|
||||||
<h2 id="noteReadTitle"></h2>
|
|
||||||
<div class="clearfix" id="noteReadInfo">
|
|
||||||
<i class="fa fa-bookmark-o"></i>
|
|
||||||
<span id="noteReadTags"></span>
|
|
||||||
|
|
||||||
<!-- 修改时间 -->
|
|
||||||
<i class="fa fa-clock-o"></i> {{msg . "update"}}
|
|
||||||
<span id="noteReadUpdatedTime"></span>
|
|
||||||
|
|
||||||
<!-- 修改时间 -->
|
|
||||||
<i class="fa fa-clock-o"></i> {{msg . "create"}}
|
|
||||||
<span id="noteReadCreatedTime"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="editor">
|
<div id="editor">
|
||||||
<!-- 编辑器 -->
|
<!-- 编辑器 -->
|
||||||
<div id="mceToolbar">
|
<div id="mceToolbar">
|
||||||
<div id="mceToolbarContainer">
|
<div id="popularToolbar"
|
||||||
<div id="popularToolbar" style="position: absolute; right: 30px; left: 0"></div>
|
style="position: absolute; right: 30px; left: 0"></div>
|
||||||
<a id="moreBtn"> <i class="fa more-fa"></i></a>
|
<a
|
||||||
</div>
|
style="dispaly: block; position: absolute; cursor: pointer; right: 10px; padding: 3px 10px"
|
||||||
<!-- 查看信息 -->
|
id="moreBtn"> <i class="fa fa-angle-down"></i>
|
||||||
<div id="infoToolbar" class="info-toolbar">
|
</a>
|
||||||
<a class="toolbar-update"><i class="fa fa-pencil"></i> <span class="lang">{{msg . "modify"}}</span></a>
|
|
||||||
<span class="lang">{{msg . "created"}}</span>: <span class="created-time">2015-04-03</span>
|
|
||||||
<span class="lang">{{msg . "updated"}}</span>: <span class="updated-time">2015-05-01</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="editorBg"></div>
|
<div class="editorBg"></div>
|
||||||
<div id="leanoteNav" class="leanoteNav">
|
<div id="leanoteNav" class="leanoteNav">
|
||||||
@@ -583,17 +586,11 @@ function log(o) {
|
|||||||
|
|
||||||
<div id="mdEditor">
|
<div id="mdEditor">
|
||||||
|
|
||||||
|
|
||||||
<div class="layout-wrapper-l1">
|
<div class="layout-wrapper-l1">
|
||||||
<div class="layout-wrapper-l2">
|
<div class="layout-wrapper-l2">
|
||||||
<div class="navbar navbar-default">
|
<div class="navbar navbar-default">
|
||||||
<div class="navbar-inner" id="wmd-button-bar">
|
<div class="navbar-inner" id="wmd-button-bar">
|
||||||
<div id="mdInfoToolbar" class="info-toolbar">
|
|
||||||
<a class="toolbar-update"><i class="fa fa-pencil"></i> <span class="lang">{{msg . "modify"}}</span></a>
|
|
||||||
<span class="lang">{{msg . "created"}}</span>: <span class="created-time">2015-04-03</span>
|
|
||||||
<span class="lang">{{msg . "updated"}}</span>: <span class="updated-time">2015-05-01</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wmd-button-bar-inner">
|
|
||||||
<ul class="nav left-buttons">
|
<ul class="nav left-buttons">
|
||||||
<li class="wmd-button-group1 btn-group"></li>
|
<li class="wmd-button-group1 btn-group"></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -632,7 +629,6 @@ function log(o) {
|
|||||||
</ul>
|
</ul>
|
||||||
-->
|
-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="editorBg"></div>
|
<div class="editorBg"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-wrapper-l3">
|
<div class="layout-wrapper-l3">
|
||||||
@@ -717,7 +713,7 @@ function log(o) {
|
|||||||
|
|
||||||
<!-- 插入图片 -->
|
<!-- 插入图片 -->
|
||||||
<div class="modal fade modal-insert-image">
|
<div class="modal fade modal-insert-image">
|
||||||
<div class="modal-dialog" style="width: 840px;max-width:100%;">
|
<div class="modal-dialog" style="width: 840px">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal"
|
<button type="button" class="close" data-dismiss="modal"
|
||||||
@@ -904,7 +900,6 @@ var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
|
|||||||
|
|
||||||
<!-- 渲染view -->
|
<!-- 渲染view -->
|
||||||
<script src="/tinymce/tinymce.js"></script>
|
<script src="/tinymce/tinymce.js"></script>
|
||||||
|
|
||||||
<script src="/public/libs/ace/ace.js"></script>
|
<script src="/public/libs/ace/ace.js"></script>
|
||||||
<script src="/js/app/page.js"></script>
|
<script src="/js/app/page.js"></script>
|
||||||
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
|
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
|
||||||
@@ -924,14 +919,13 @@ initPage();
|
|||||||
|
|
||||||
<!-- v2 use require.js, mdeditor -->
|
<!-- v2 use require.js, mdeditor -->
|
||||||
<script>
|
<script>
|
||||||
// 当tinymce.dev.js时, 请注释require
|
window.baseDir = '/public/dist';
|
||||||
window.require = {
|
window.require = {
|
||||||
baseUrl: '/public',
|
baseUrl: window.baseDir,
|
||||||
|
deps: ['main']
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/require.js"></script>
|
<script src="/js/require.js"></script>
|
||||||
<script src="/public/dist/main.min.js"></script>
|
|
||||||
<script src="/public/js/upload_paste/main.js"></script>
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+37
-43
@@ -7,8 +7,8 @@
|
|||||||
<meta name="apple-touch-fullscreen" content="yes">
|
<meta name="apple-touch-fullscreen" content="yes">
|
||||||
<meta name=”apple-mobile-web-app-capable” content=”yes” />
|
<meta name=”apple-mobile-web-app-capable” content=”yes” />
|
||||||
<meta name="keywords" content="leanote,leanote.com">
|
<meta name="keywords" content="leanote,leanote.com">
|
||||||
<meta name="description" content="Leanote, {{msg $ "moto"}}">
|
<meta name="description" content="leanote, Not Just A Notebook">
|
||||||
<title>Leanote, {{msg $ "moto"}}</title>
|
<title>leanote, Not Just A Notebook</title>
|
||||||
|
|
||||||
<link href="/css/bootstrap.css" rel="stylesheet" />
|
<link href="/css/bootstrap.css" rel="stylesheet" />
|
||||||
<!-- 先加载, 没有样式, 宽度不定 -->
|
<!-- 先加载, 没有样式, 宽度不定 -->
|
||||||
@@ -186,11 +186,13 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
<div class="pull-right top-nav writting-hide lea-blog">
|
<div class="pull-right top-nav writting-hide lea-blog">
|
||||||
<a target="_blank" href="http://lea.leanote.com">
|
<a target="_blank" href="http://lea.leanote.com">
|
||||||
lea++
|
lea++
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
<div class="pull-right top-nav writting-hide" id="myBlog">
|
<div class="pull-right top-nav writting-hide" id="myBlog">
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
@@ -414,7 +416,29 @@ function log(o) {
|
|||||||
<div class="noteSplit" id="noteSplitter"></div>
|
<div class="noteSplit" id="noteSplitter"></div>
|
||||||
|
|
||||||
<div id="note">
|
<div id="note">
|
||||||
|
<!-- 只读模式 -->
|
||||||
|
<div id="noteRead">
|
||||||
|
<div id="noteReadContainer">
|
||||||
|
<div id="noteReadTop">
|
||||||
|
<h2 id="noteReadTitle"></h2>
|
||||||
|
<div class="clearfix" id="noteReadInfo">
|
||||||
|
<i class="fa fa-bookmark-o"></i>
|
||||||
|
<span id="noteReadTags"></span>
|
||||||
|
|
||||||
|
<!-- 修改时间 -->
|
||||||
|
<i class="fa fa-clock-o"></i>{{msg . "update"}}
|
||||||
|
<span id="noteReadUpdatedTime"></span>
|
||||||
|
|
||||||
|
<!-- 修改时间 -->
|
||||||
|
<i class="fa fa-clock-o"></i>{{msg . "create"}}
|
||||||
|
<span id="noteReadCreatedTime"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="noteReadContent">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 遮罩, 为了resize3Columns用 -->
|
<!-- 遮罩, 为了resize3Columns用 -->
|
||||||
<div id="noteMask" class="note-mask"></div>
|
<div id="noteMask" class="note-mask"></div>
|
||||||
<div id="noteMaskForLoading" class="note-mask">
|
<div id="noteMaskForLoading" class="note-mask">
|
||||||
@@ -522,38 +546,17 @@ function log(o) {
|
|||||||
<div id="noteTitleDiv">
|
<div id="noteTitleDiv">
|
||||||
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}" tabindex="1" />
|
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}" tabindex="1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 只读时 -->
|
|
||||||
<div id="noteReadTop">
|
|
||||||
<h2 id="noteReadTitle"></h2>
|
|
||||||
<div class="clearfix" id="noteReadInfo">
|
|
||||||
<i class="fa fa-bookmark-o"></i>
|
|
||||||
<span id="noteReadTags"></span>
|
|
||||||
|
|
||||||
<!-- 修改时间 -->
|
|
||||||
<i class="fa fa-clock-o"></i> {{msg . "update"}}
|
|
||||||
<span id="noteReadUpdatedTime"></span>
|
|
||||||
|
|
||||||
<!-- 修改时间 -->
|
|
||||||
<i class="fa fa-clock-o"></i> {{msg . "create"}}
|
|
||||||
<span id="noteReadCreatedTime"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="editor">
|
<div id="editor">
|
||||||
<!-- 编辑器 -->
|
<!-- 编辑器 -->
|
||||||
<div id="mceToolbar">
|
<div id="mceToolbar">
|
||||||
<div id="mceToolbarContainer">
|
<div id="popularToolbar"
|
||||||
<div id="popularToolbar" style="position: absolute; right: 30px; left: 0"></div>
|
style="position: absolute; right: 30px; left: 0"></div>
|
||||||
<a id="moreBtn"> <i class="fa more-fa"></i></a>
|
<a
|
||||||
</div>
|
style="dispaly: block; position: absolute; cursor: pointer; right: 10px; padding: 3px 10px"
|
||||||
<!-- 查看信息 -->
|
id="moreBtn"> <i class="fa fa-angle-down"></i>
|
||||||
<div id="infoToolbar" class="info-toolbar">
|
</a>
|
||||||
<a class="toolbar-update"><i class="fa fa-pencil"></i> <span class="lang">{{msg . "modify"}}</span></a>
|
|
||||||
<span class="lang">{{msg . "created"}}</span>: <span class="created-time">2015-04-03</span>
|
|
||||||
<span class="lang">{{msg . "updated"}}</span>: <span class="updated-time">2015-05-01</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="editorBg"></div>
|
<div class="editorBg"></div>
|
||||||
<div id="leanoteNav" class="leanoteNav">
|
<div id="leanoteNav" class="leanoteNav">
|
||||||
@@ -583,17 +586,11 @@ function log(o) {
|
|||||||
|
|
||||||
<div id="mdEditor">
|
<div id="mdEditor">
|
||||||
|
|
||||||
|
|
||||||
<div class="layout-wrapper-l1">
|
<div class="layout-wrapper-l1">
|
||||||
<div class="layout-wrapper-l2">
|
<div class="layout-wrapper-l2">
|
||||||
<div class="navbar navbar-default">
|
<div class="navbar navbar-default">
|
||||||
<div class="navbar-inner" id="wmd-button-bar">
|
<div class="navbar-inner" id="wmd-button-bar">
|
||||||
<div id="mdInfoToolbar" class="info-toolbar">
|
|
||||||
<a class="toolbar-update"><i class="fa fa-pencil"></i> <span class="lang">{{msg . "modify"}}</span></a>
|
|
||||||
<span class="lang">{{msg . "created"}}</span>: <span class="created-time">2015-04-03</span>
|
|
||||||
<span class="lang">{{msg . "updated"}}</span>: <span class="updated-time">2015-05-01</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="wmd-button-bar-inner">
|
|
||||||
<ul class="nav left-buttons">
|
<ul class="nav left-buttons">
|
||||||
<li class="wmd-button-group1 btn-group"></li>
|
<li class="wmd-button-group1 btn-group"></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -632,7 +629,6 @@ function log(o) {
|
|||||||
</ul>
|
</ul>
|
||||||
-->
|
-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="editorBg"></div>
|
<div class="editorBg"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-wrapper-l3">
|
<div class="layout-wrapper-l3">
|
||||||
@@ -717,7 +713,7 @@ function log(o) {
|
|||||||
|
|
||||||
<!-- 插入图片 -->
|
<!-- 插入图片 -->
|
||||||
<div class="modal fade modal-insert-image">
|
<div class="modal fade modal-insert-image">
|
||||||
<div class="modal-dialog" style="width: 840px;max-width:100%;">
|
<div class="modal-dialog" style="width: 840px">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal"
|
<button type="button" class="close" data-dismiss="modal"
|
||||||
@@ -904,7 +900,6 @@ var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
|
|||||||
|
|
||||||
<!-- 渲染view -->
|
<!-- 渲染view -->
|
||||||
<script src="/tinymce/tinymce.min.js"></script>
|
<script src="/tinymce/tinymce.min.js"></script>
|
||||||
|
|
||||||
<script src="/public/libs/ace/ace.js"></script>
|
<script src="/public/libs/ace/ace.js"></script>
|
||||||
<script src="/js/app/page-min.js"></script>
|
<script src="/js/app/page-min.js"></script>
|
||||||
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js"></script>
|
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js"></script>
|
||||||
@@ -924,14 +919,13 @@ initPage();
|
|||||||
|
|
||||||
<!-- v2 use require.js, mdeditor -->
|
<!-- v2 use require.js, mdeditor -->
|
||||||
<script>
|
<script>
|
||||||
// 当tinymce.min.js时, 请注释require
|
window.baseDir = '/public/dist';
|
||||||
window.require = {
|
window.require = {
|
||||||
baseUrl: '/public',
|
baseUrl: window.baseDir,
|
||||||
|
deps: ['main']
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/require.js"></script>
|
<script src="/js/require.js"></script>
|
||||||
<script src="/public/dist/main.min.js"></script>
|
|
||||||
<script src="/public/js/upload_paste/main.js"></script>
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{{template "home/header_box.html" .}}
|
||||||
|
|
||||||
|
<section id="box" class="animated fadeInUp">
|
||||||
|
<div>
|
||||||
|
<h1 id="logo">leanote</h1>
|
||||||
|
<div id="boxForm">
|
||||||
|
<div id="boxHeader">We got a error</div>
|
||||||
|
<form>
|
||||||
|
<div class="alert alert-danger" id="loginMsg" style="display: block">
|
||||||
|
Sorry, we can't get your infomation.
|
||||||
|
|
||||||
|
<br />
|
||||||
|
Please <a href="/login">{{msg . "login"}}</a> Or <a href="/register?email={{.email}}">{{msg . "register"}}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div id="boxFooter">
|
||||||
|
<p>
|
||||||
|
<a href="/login">{{msg . "login"}}</a>
|
||||||
|
|
||||||
|
<a href="/index">{{msg . "home"}}</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="/index">leanote</a> © 2014
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -5,11 +5,14 @@
|
|||||||
<h4 class="modal-title" id="modalTitle">{{msg . "share"}} <b>{{.title}}</b></h4>
|
<h4 class="modal-title" id="modalTitle">{{msg . "share"}} <b>{{.title}}</b></h4>
|
||||||
</div>
|
</div>
|
||||||
{{$noteOrNotebookId := .noteOrNotebookId}}
|
{{$noteOrNotebookId := .noteOrNotebookId}}
|
||||||
|
{{$isNote := .isNote}}
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ul id="myTab" class="nav nav-tabs">
|
<ul id="myTab" class="nav nav-tabs">
|
||||||
<li class="active"><a href="#baseInfo" data-toggle="tab">分享给好友</a></li>
|
<li class="active"><a href="#baseInfo" data-toggle="tab">分享给好友</a></li>
|
||||||
<li class=""><a href="#groupInfo" data-toggle="tab">分享给项目组</a></li>
|
<li class=""><a href="#groupInfo" data-toggle="tab">分享给项目组</a></li>
|
||||||
|
{{if $isNote}}
|
||||||
|
<li class=""><a href="#shareInfo" data-toggle="tab">分享给未注册好友</a></li>
|
||||||
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@@ -95,6 +98,19 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane" id="shareInfo">
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-default" id="genShareLink">生成该笔记的分享链接和密码</button>
|
||||||
|
<span id="showMsg"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
分享链接:<input type="text" id="shareLink" value="" size=50> <br/><br/>
|
||||||
|
查看密码:<input type="text" id="sharePass" value="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -108,11 +124,55 @@
|
|||||||
<script>
|
<script>
|
||||||
Share.dialogIsNote = {{.isNote}};
|
Share.dialogIsNote = {{.isNote}};
|
||||||
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
||||||
|
|
||||||
|
var getHost = function(url) {
|
||||||
|
var host = "null";
|
||||||
|
if(typeof url == "undefined"
|
||||||
|
|| null == url)
|
||||||
|
url = window.location.href;
|
||||||
|
var regex = /.*\:\/\/([^\/]*).*/;
|
||||||
|
var match = url.match(regex);
|
||||||
|
if(typeof match != "undefined"
|
||||||
|
&& null != match)
|
||||||
|
host = match[1];
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$("#tr1 #friendsEmail").focus();
|
$("#tr1 #friendsEmail").focus();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
var host = getHost();
|
||||||
|
if (Share.dialogIsNote) {
|
||||||
|
var url = "/share/querySharePass";
|
||||||
|
var data = {noteId: Share.dialogNoteOrNotebookId};
|
||||||
|
ajaxPost(url, data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
if (re.Item >= 1000 && re.Item < 10000) {
|
||||||
|
var shareLink = host + '/share/note/{{.noteOrNotebookId}}';
|
||||||
|
$("#shareLink").val(shareLink);
|
||||||
|
$("#sharePass").val(re.Item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#shareLink").hover(function() {
|
||||||
|
$("#shareLink").focus(function(){
|
||||||
|
$(this).css({'background-color' : '#f5f5dc'});
|
||||||
|
}).select();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
$("#sharePass").hover(function() {
|
||||||
|
$("#sharePass").focus(function(){
|
||||||
|
$(this).css({'background-color' : '#f5f5dc'});
|
||||||
|
}).select();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
// 分享/删除给分组
|
// 分享/删除给分组
|
||||||
$("#groupInfo").on("click", ".btn-share-or-not", function() {
|
$("#groupInfo").on("click", ".btn-share-or-not", function() {
|
||||||
var $t = $(this);
|
var $t = $(this);
|
||||||
@@ -155,6 +215,28 @@ $("#groupInfo").on("click", ".btn-share-or-not", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//生成分享链接和密码
|
||||||
|
$("#genShareLink").on("click", function() {
|
||||||
|
var sharePass = $("#sharePass").val();
|
||||||
|
if (sharePass != '' && sharePass > 1000 && sharePass < 10000) {
|
||||||
|
$("#showMsg").html("<font color='red'>不能重复生成分享链接和密码</font>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = "/share/genShareLinkPass";
|
||||||
|
var shareLink = host + '/share/note/{{.noteOrNotebookId}}';
|
||||||
|
var data = {noteId: Share.dialogNoteOrNotebookId};
|
||||||
|
ajaxPost(url, data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
$("#shareLink").val(shareLink);
|
||||||
|
$("#sharePass").val(re.Item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(".group-perm").click(function() {
|
$(".group-perm").click(function() {
|
||||||
var $t = $(this);
|
var $t = $(this);
|
||||||
var $ptr = $t.closest("tr");
|
var $ptr = $t.closest("tr");
|
||||||
@@ -179,5 +261,6 @@ $(".group-perm").click(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
{{template "home/header.html" .}}
|
||||||
|
|
||||||
|
<section>
|
||||||
|
</section>
|
||||||
|
{{$isMarkDown := .isMarkDown}}
|
||||||
|
|
||||||
|
<div id="queryNote" style="height:300px;padding-top:80px" align="center">
|
||||||
|
{{ .userName }}分享了笔记<br/><br>
|
||||||
|
|
||||||
|
您需要输入分享密码才能查看:<br><br>
|
||||||
|
<input type="password" id="sharePass" />
|
||||||
|
<button id="showShareNote">点击查看</button><br/><br/>
|
||||||
|
<span id="showMsg"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="noteContainer" style="display:none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{template "home/footer.html"}}
|
||||||
|
|
||||||
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.js"></script>
|
||||||
|
<script src="/js/common-min.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var noteId = {{ .noteId }};
|
||||||
|
var isMarkDown = {{ .isMarkDown}}
|
||||||
|
|
||||||
|
String.prototype.format = function() {
|
||||||
|
var s = this,
|
||||||
|
i = arguments.length;
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var getHost = function(url) {
|
||||||
|
var host = "null";
|
||||||
|
if(typeof url == "undefined"
|
||||||
|
|| null == url)
|
||||||
|
url = window.location.href;
|
||||||
|
var regex = /.*\:\/\/([^\/]*).*/;
|
||||||
|
var match = url.match(regex);
|
||||||
|
if(typeof match != "undefined"
|
||||||
|
&& null != match)
|
||||||
|
host = match[1];
|
||||||
|
return "http://" + host;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$("#showShareNote").on("click", function() {
|
||||||
|
$("#showMsg").html("");
|
||||||
|
var url = "/share/verify4ShareNote";
|
||||||
|
|
||||||
|
var sharePass = $("#sharePass").val();
|
||||||
|
var data = {noteId: noteId, sharePass: sharePass};
|
||||||
|
ajaxPost(url, data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
$("#queryNote").css("display", "none");
|
||||||
|
var title = re.Item.Title;
|
||||||
|
var content = re.Msg;
|
||||||
|
var imgSrc = re.Item.ImgSrc;
|
||||||
|
var htmlContent = "<div><h1 height='50px'>{0}</h1></div><hr/><div style='vertical-align:center'><p height='auto'>{1}<br>{2}</p>";
|
||||||
|
|
||||||
|
var attaches = re.List;
|
||||||
|
var attachesHtml = "";
|
||||||
|
if (attaches.length > 0) {
|
||||||
|
var token = re.Id;
|
||||||
|
for (var i=0; i<attaches.length; i++) {
|
||||||
|
var linkUrl = "{0}/attach/download?attachId={1}&token={2}".format(getHost(), attaches[i].AttachId, token);
|
||||||
|
attachesHtml += "<p><a href='{0}' target='_blank' data-mce-href='{1}' >附件{2}</a></p><br/>".format(linkUrl, linkUrl, i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlContent = htmlContent.format(title, content, attachesHtml) + "</div>";
|
||||||
|
|
||||||
|
|
||||||
|
/* if (isMarkDown) {
|
||||||
|
var converter = Markdown.getSanitizingConverter();
|
||||||
|
Markdown.Extra.init(converter, {extensions: ["tables", "fenced_code_gfm", "def_list"]});
|
||||||
|
var mdDesc = converter.makeHtml(desc);
|
||||||
|
$("pre").addClass("prettyprint linenums");
|
||||||
|
prettyPrint();
|
||||||
|
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
|
||||||
|
htmlContent = "<div><h1 height='50px'>"+title+"</h1></div><hr/><div style='vertical-align:center'><p height='auto'>"
|
||||||
|
+mdDesc+"</p></div>";
|
||||||
|
} else {
|
||||||
|
htmlContent = "<div><h1 height='50px'>"+title+"</h1></div><hr/><div style='vertical-align:center'><p height='auto'>"
|
||||||
|
+desc+"</p></div>";
|
||||||
|
} */
|
||||||
|
|
||||||
|
|
||||||
|
$("#noteContainer").css("display", "block").css("height", "auto")
|
||||||
|
.css("padding-top", "20px").css("text-align", "center")
|
||||||
|
.css("margin-left", "auto").css("margin-right", "auto");
|
||||||
|
|
||||||
|
$("#noteContainer").html(htmlContent);
|
||||||
|
} else {
|
||||||
|
$("#showMsg").html("<font color='red'>密码错误</font>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 平滑滚动
|
||||||
|
$(".smooth-scroll").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var t = $(this).attr("target");
|
||||||
|
var targetOffset = $(t).offset().top - 80;
|
||||||
|
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{if $isMarkDown}}
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/Markdown.Extra.js"></script>
|
||||||
|
<script src="/public/mdeditor/editor/editor.js"></script>
|
||||||
|
<script src="/public/js/google-code-prettify/prettify.js"></script>
|
||||||
|
<!--mathjax-->
|
||||||
|
<script type="text/x-mathjax-config">
|
||||||
|
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||||
|
</script>
|
||||||
|
<script src="/public/mdeditor/editor/mathJax.js"></script>
|
||||||
|
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
{{end}}
|
||||||
+37
-95
@@ -2,83 +2,40 @@
|
|||||||
|
|
||||||
# release leanote
|
# release leanote
|
||||||
|
|
||||||
# 当前路径
|
|
||||||
SP=$(cd "$(dirname "$0")"; pwd)
|
SP=$(cd "$(dirname "$0")"; pwd)
|
||||||
|
|
||||||
|
cd $SP
|
||||||
|
cd ../
|
||||||
|
|
||||||
# tmp path to store leanote release files
|
# tmp path to store leanote release files
|
||||||
tmp="/Users/life/Desktop/leanote_release"
|
tmp="/Users/life/Desktop/leanote_release"
|
||||||
|
|
||||||
# version
|
version=x86_64.v1.0-beta.2
|
||||||
V="v1.0-beta.4"
|
|
||||||
|
|
||||||
##=================================
|
|
||||||
# 1. 先build 成 3个平台, 2种bit = 6种
|
|
||||||
##=================================
|
|
||||||
|
|
||||||
# cd /Documents/Go/package2/src/github.com/leanote/leanote/bin
|
|
||||||
# GOOS=darwin GOARCH=amd64 go build -o leanote-darwin-amd64 ../app/tmp
|
|
||||||
|
|
||||||
cd $SP
|
|
||||||
|
|
||||||
# $1 = darwin, linux
|
|
||||||
# $2 = amd64
|
|
||||||
function build()
|
|
||||||
{
|
|
||||||
echo build-$1-$2
|
|
||||||
if [ $1 = "linux" -o $1 = "darwin" ]
|
|
||||||
then
|
|
||||||
suffix=""
|
|
||||||
else
|
|
||||||
suffix=".exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
GOOS=$1 GOARCH=$2 go build -o leanote-$1-$2$suffix ../app/tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
build "linux" "386";
|
|
||||||
build "linux" "amd64";
|
|
||||||
build "darwin" "386";
|
|
||||||
build "darwin" "amd64";
|
|
||||||
build "windows" "386";
|
|
||||||
build "windows" "amd64";
|
|
||||||
|
|
||||||
|
|
||||||
##======================
|
|
||||||
# 2. release目录准备工作
|
|
||||||
##======================
|
|
||||||
rm -rf $tmp/leanote
|
rm -rf $tmp/leanote
|
||||||
mkdir -p $tmp/leanote/app
|
mkdir -p $tmp/leanote/app
|
||||||
mkdir -p $tmp/leanote/conf
|
mkdir -p $tmp/leanote/conf
|
||||||
mkdir -p $tmp/leanote/bin
|
mkdir -p $tmp/leanote/bin
|
||||||
|
|
||||||
##==================
|
|
||||||
# 3. 复制
|
|
||||||
##==================
|
|
||||||
|
|
||||||
cd $SP
|
|
||||||
cd ../
|
|
||||||
|
|
||||||
# bin
|
# bin
|
||||||
cp -r ./bin/src $tmp/leanote/bin/
|
cp -r ./bin/src $tmp/leanote/bin/
|
||||||
cp ./bin/run.sh $tmp/leanote/bin/
|
cp ./bin/run.sh $tmp/leanote/bin/
|
||||||
cp ./bin/run.bat $tmp/leanote/bin/
|
|
||||||
|
# LICENSE
|
||||||
|
cp ./LICENSE $tmp/leanote/
|
||||||
|
|
||||||
# views
|
# views
|
||||||
cp -r ./app/views $tmp/leanote/app
|
cp -r ./app/views $tmp/leanote/app
|
||||||
# 可不要, 源码
|
# 可不要
|
||||||
#cp -r ./app/service $tmp/leanote/app/service
|
cp -r ./app/service $tmp/leanote/app/service
|
||||||
#cp -r ./app/controllers $tmp/leanote/app/controllers
|
cp -r ./app/controllers $tmp/leanote/app/controllers
|
||||||
#cp -r ./app/db $tmp/leanote/app/db
|
cp -r ./app/db $tmp/leanote/app/db
|
||||||
#cp -r ./app/info $tmp/leanote/app/info
|
cp -r ./app/info $tmp/leanote/app/info
|
||||||
#cp -r ./app/lea $tmp/leanote/app/lea
|
cp -r ./app/lea $tmp/leanote/app/lea
|
||||||
|
|
||||||
# conf
|
# conf
|
||||||
cp ./conf/app.conf $tmp/leanote/conf/app.conf
|
cp ./conf/app.conf-default $tmp/leanote/conf/app.conf
|
||||||
cp ./conf/routes $tmp/leanote/conf/routes
|
cp ./conf/routes-default $tmp/leanote/conf/routes
|
||||||
# 处理app.conf, 还原配置
|
|
||||||
cat $tmp/leanote/conf/app.conf | sed 's/db.dbname=leanote.*#/db.dbname=leanote #/' > $tmp/leanote/conf/app.conf2 # 不能直接覆盖
|
|
||||||
rm $tmp/leanote/conf/app.conf
|
|
||||||
mv $tmp/leanote/conf/app.conf2 $tmp/leanote/conf/app.conf
|
|
||||||
|
|
||||||
# others
|
# others
|
||||||
cp -r ./messages ./public ./mongodb_backup $tmp/leanote/
|
cp -r ./messages ./public ./mongodb_backup $tmp/leanote/
|
||||||
@@ -87,55 +44,40 @@ cp -r ./messages ./public ./mongodb_backup $tmp/leanote/
|
|||||||
rm -r $tmp/leanote/public/tinymce/classes
|
rm -r $tmp/leanote/public/tinymce/classes
|
||||||
rm -r $tmp/leanote/public/upload
|
rm -r $tmp/leanote/public/upload
|
||||||
mkdir $tmp/leanote/public/upload
|
mkdir $tmp/leanote/public/upload
|
||||||
|
mkdir $tmp/leanote/files
|
||||||
rm -r $tmp/leanote/public/.codekit-cache
|
rm -r $tmp/leanote/public/.codekit-cache
|
||||||
rm $tmp/leanote/public/.DS_Store
|
rm $tmp/leanote/public/.DS_Store
|
||||||
rm $tmp/leanote/public/config.codekit
|
rm $tmp/leanote/public/config.codekit
|
||||||
|
|
||||||
# make link
|
# make link
|
||||||
# cd $tmp/leanote/bin
|
cd $tmp/leanote/bin
|
||||||
|
mkdir ./src/github.com/leanote
|
||||||
# ln -s ../../../../ ./src/github.com/leanote/leanote
|
# ln -s ../../../../ ./src/github.com/leanote/leanote
|
||||||
|
|
||||||
# archieve
|
# archieve
|
||||||
# << 'BLOCK
|
# << 'BLOCK
|
||||||
|
# linux
|
||||||
##===========
|
|
||||||
# 4. 打包
|
|
||||||
##===========
|
|
||||||
# $1 = linux
|
|
||||||
# $2 = 386, amd64
|
|
||||||
|
|
||||||
# 创建一个$V的目录存放之
|
|
||||||
rm -rf $tmp/$V
|
|
||||||
mkdir $tmp/$V
|
|
||||||
|
|
||||||
function tarRelease()
|
|
||||||
{
|
|
||||||
echo tar-$1-$2
|
|
||||||
cd $SP
|
cd $SP
|
||||||
cd ../
|
cd ../
|
||||||
rm $tmp/leanote/bin/leanote-* # 删除之前的bin文件
|
cp ./bin/leanote-linux $tmp/leanote/bin/
|
||||||
rm $tmp/leanote/bin/run* # 删除之前的run.sh 或 run.bat
|
|
||||||
|
|
||||||
if [ $1 = "linux" -o $1 = "darwin" ]
|
|
||||||
then
|
|
||||||
suffix=""
|
|
||||||
cp ./bin/run.sh $tmp/leanote/bin/
|
|
||||||
else
|
|
||||||
cp ./bin/run.bat $tmp/leanote/bin/
|
|
||||||
suffix=".exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp ./bin/leanote-$1-$2$suffix $tmp/leanote/bin/
|
|
||||||
cd $tmp
|
cd $tmp
|
||||||
tar -cf $tmp/$V/leanote-$1-$2-$V.bin.tar leanote
|
tar -cvf $tmp/leanote-linux-$version.bin.tar leanote
|
||||||
gzip $tmp/$V/leanote-$1-$2-$V.bin.tar
|
gzip $tmp/leanote-linux-$version.bin.tar
|
||||||
}
|
|
||||||
|
|
||||||
tarRelease "linux" "386";
|
# mac
|
||||||
tarRelease "linux" "amd64";
|
rm $tmp/leanote/bin/leanote-linux
|
||||||
tarRelease "darwin" "386";
|
cd $SP
|
||||||
tarRelease "darwin" "amd64";
|
cd ../
|
||||||
tarRelease "windows" "386";
|
cp ./bin/leanote-mac $tmp/leanote/bin/
|
||||||
tarRelease "windows" "amd64";
|
cd $tmp
|
||||||
|
tar -cvf $tmp/leanote-mac-$version.bin.tar leanote
|
||||||
|
gzip $tmp/leanote-mac-$version.bin.tar
|
||||||
|
|
||||||
|
cd $SP
|
||||||
|
cd ../
|
||||||
|
cp ./bin/leanote-linux $tmp/leanote/bin/
|
||||||
|
|
||||||
|
rm $tmp/bin/src/github.com/leanote/leanote
|
||||||
|
cp -r $tmp/leanote/* $tmp/leanote_release_github
|
||||||
|
|
||||||
# BLOCK'
|
# BLOCK'
|
||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
cd..
|
|
||||||
set SCRIPTPATH=%cd%
|
|
||||||
|
|
||||||
: top src directory
|
|
||||||
set path="%SCRIPTPATH%\bin\src\github.com\leanote"
|
|
||||||
|
|
||||||
if not exist "%path%" mkdir "%path%"
|
|
||||||
|
|
||||||
: create software link
|
|
||||||
if exist "%path%\leanote" del /Q "%path%\leanote"
|
|
||||||
mklink /D "%path%\leanote" %SCRIPTPATH%
|
|
||||||
|
|
||||||
: set GOPATH
|
|
||||||
set GOPATH=%GOPATH%;"%SCRIPTPATH%\bin"
|
|
||||||
|
|
||||||
: run
|
|
||||||
if %processor_architecture%==x86 (
|
|
||||||
"%SCRIPTPATH%\bin\leanote-windows-386.exe" -importPath github.com/leanote/leanote
|
|
||||||
) else (
|
|
||||||
"%SCRIPTPATH%\bin\leanote-windows-amd64.exe" -importPath github.com/leanote/leanote
|
|
||||||
)
|
|
||||||
+6
-12
@@ -7,23 +7,17 @@ path="$SCRIPTPATH/src/github.com/leanote"
|
|||||||
if [ ! -d "$path" ]; then
|
if [ ! -d "$path" ]; then
|
||||||
mkdir -p "$path"
|
mkdir -p "$path"
|
||||||
fi
|
fi
|
||||||
rm -rf $SCRIPTPATH/src/github.com/leanote/leanote # 先删除
|
|
||||||
ln -s ../../../../ $SCRIPTPATH/src/github.com/leanote/leanote
|
ln -s ../../../../ $SCRIPTPATH/src/github.com/leanote/leanote
|
||||||
|
|
||||||
# set GOPATH
|
# set GOPATH
|
||||||
export GOPATH=$GOPATH:$SCRIPTPATH
|
export GOPATH=$GOPATH:$SCRIPTPATH
|
||||||
|
|
||||||
# run
|
# run
|
||||||
osName=`uname` # Darwin or Linux
|
osName=`uname`
|
||||||
osName=`tr '[A-Z]' '[a-z]' <<<"$osName"` # toLowerCase
|
if [ $osName == "Darwin" ]; then
|
||||||
bit=`getconf LONG_BIT` # 32, 64
|
chmod 777 "$SCRIPTPATH/leanote-mac"
|
||||||
if [ $bit = "64" ]
|
"$SCRIPTPATH/leanote-mac" -importPath github.com/leanote/leanote
|
||||||
then
|
|
||||||
bit="amd64"
|
|
||||||
else
|
else
|
||||||
bit="386"
|
chmod 777 "$SCRIPTPATH/leanote-linux"
|
||||||
|
"$SCRIPTPATH/leanote-linux" -importPath github.com/leanote/leanote
|
||||||
fi
|
fi
|
||||||
|
|
||||||
script="$SCRIPTPATH/leanote-$osName-$bit"
|
|
||||||
chmod 777 $script
|
|
||||||
$script -importPath github.com/leanote/leanote
|
|
||||||
@@ -1,545 +0,0 @@
|
|||||||
3dm=x-world/x-3dmf
|
|
||||||
3dmf=x-world/x-3dmf
|
|
||||||
7z=application/x-7z-compressed
|
|
||||||
a=application/octet-stream
|
|
||||||
aab=application/x-authorware-bin
|
|
||||||
aam=application/x-authorware-map
|
|
||||||
aas=application/x-authorware-seg
|
|
||||||
abc=text/vndabc
|
|
||||||
ace=application/x-ace-compressed
|
|
||||||
acgi=text/html
|
|
||||||
afl=video/animaflex
|
|
||||||
ai=application/postscript
|
|
||||||
aif=audio/aiff
|
|
||||||
aifc=audio/aiff
|
|
||||||
aiff=audio/aiff
|
|
||||||
aim=application/x-aim
|
|
||||||
aip=text/x-audiosoft-intra
|
|
||||||
alz=application/x-alz-compressed
|
|
||||||
ani=application/x-navi-animation
|
|
||||||
aos=application/x-nokia-9000-communicator-add-on-software
|
|
||||||
aps=application/mime
|
|
||||||
arc=application/x-arc-compressed
|
|
||||||
arj=application/arj
|
|
||||||
art=image/x-jg
|
|
||||||
asf=video/x-ms-asf
|
|
||||||
asm=text/x-asm
|
|
||||||
asp=text/asp
|
|
||||||
asx=application/x-mplayer2
|
|
||||||
au=audio/basic
|
|
||||||
avi=video/x-msvideo
|
|
||||||
avs=video/avs-video
|
|
||||||
bcpio=application/x-bcpio
|
|
||||||
bin=application/mac-binary
|
|
||||||
bmp=image/bmp
|
|
||||||
boo=application/book
|
|
||||||
book=application/book
|
|
||||||
boz=application/x-bzip2
|
|
||||||
bsh=application/x-bsh
|
|
||||||
bz2=application/x-bzip2
|
|
||||||
bz=application/x-bzip
|
|
||||||
c++=text/plain
|
|
||||||
c=text/x-c
|
|
||||||
cab=application/vnd.ms-cab-compressed
|
|
||||||
cat=application/vndms-pkiseccat
|
|
||||||
cc=text/x-c
|
|
||||||
ccad=application/clariscad
|
|
||||||
cco=application/x-cocoa
|
|
||||||
cdf=application/cdf
|
|
||||||
cer=application/pkix-cert
|
|
||||||
cha=application/x-chat
|
|
||||||
chat=application/x-chat
|
|
||||||
chrt=application/vnd.kde.kchart
|
|
||||||
class=application/java
|
|
||||||
# ? class=application/java-vm
|
|
||||||
com=text/plain
|
|
||||||
conf=text/plain
|
|
||||||
cpio=application/x-cpio
|
|
||||||
cpp=text/x-c
|
|
||||||
cpt=application/mac-compactpro
|
|
||||||
crl=application/pkcs-crl
|
|
||||||
crt=application/pkix-cert
|
|
||||||
crx=application/x-chrome-extension
|
|
||||||
csh=text/x-scriptcsh
|
|
||||||
css=text/css
|
|
||||||
csv=text/csv
|
|
||||||
cxx=text/plain
|
|
||||||
dar=application/x-dar
|
|
||||||
dcr=application/x-director
|
|
||||||
deb=application/x-debian-package
|
|
||||||
deepv=application/x-deepv
|
|
||||||
def=text/plain
|
|
||||||
der=application/x-x509-ca-cert
|
|
||||||
dif=video/x-dv
|
|
||||||
dir=application/x-director
|
|
||||||
divx=video/divx
|
|
||||||
dl=video/dl
|
|
||||||
dmg=application/x-apple-diskimage
|
|
||||||
doc=application/msword
|
|
||||||
dot=application/msword
|
|
||||||
dp=application/commonground
|
|
||||||
drw=application/drafting
|
|
||||||
dump=application/octet-stream
|
|
||||||
dv=video/x-dv
|
|
||||||
dvi=application/x-dvi
|
|
||||||
dwf=drawing/x-dwf=(old)
|
|
||||||
dwg=application/acad
|
|
||||||
dxf=application/dxf
|
|
||||||
dxr=application/x-director
|
|
||||||
el=text/x-scriptelisp
|
|
||||||
elc=application/x-bytecodeelisp=(compiled=elisp)
|
|
||||||
eml=message/rfc822
|
|
||||||
env=application/x-envoy
|
|
||||||
eps=application/postscript
|
|
||||||
es=application/x-esrehber
|
|
||||||
etx=text/x-setext
|
|
||||||
evy=application/envoy
|
|
||||||
exe=application/octet-stream
|
|
||||||
f77=text/x-fortran
|
|
||||||
f90=text/x-fortran
|
|
||||||
f=text/x-fortran
|
|
||||||
fdf=application/vndfdf
|
|
||||||
fif=application/fractals
|
|
||||||
fli=video/fli
|
|
||||||
flo=image/florian
|
|
||||||
flv=video/x-flv
|
|
||||||
flx=text/vndfmiflexstor
|
|
||||||
fmf=video/x-atomic3d-feature
|
|
||||||
for=text/x-fortran
|
|
||||||
fpx=image/vndfpx
|
|
||||||
frl=application/freeloader
|
|
||||||
funk=audio/make
|
|
||||||
g3=image/g3fax
|
|
||||||
g=text/plain
|
|
||||||
gif=image/gif
|
|
||||||
gl=video/gl
|
|
||||||
gsd=audio/x-gsm
|
|
||||||
gsm=audio/x-gsm
|
|
||||||
gsp=application/x-gsp
|
|
||||||
gss=application/x-gss
|
|
||||||
gtar=application/x-gtar
|
|
||||||
gz=application/x-compressed
|
|
||||||
gzip=application/x-gzip
|
|
||||||
h=text/x-h
|
|
||||||
hdf=application/x-hdf
|
|
||||||
help=application/x-helpfile
|
|
||||||
hgl=application/vndhp-hpgl
|
|
||||||
hh=text/x-h
|
|
||||||
hlb=text/x-script
|
|
||||||
hlp=application/hlp
|
|
||||||
hpg=application/vndhp-hpgl
|
|
||||||
hpgl=application/vndhp-hpgl
|
|
||||||
hqx=application/binhex
|
|
||||||
hta=application/hta
|
|
||||||
htc=text/x-component
|
|
||||||
htm=text/html
|
|
||||||
html=text/html
|
|
||||||
htmls=text/html
|
|
||||||
htt=text/webviewhtml
|
|
||||||
htx=text/html
|
|
||||||
ice=x-conference/x-cooltalk
|
|
||||||
ico=image/x-icon
|
|
||||||
ics=text/calendar
|
|
||||||
icz=text/calendar
|
|
||||||
idc=text/plain
|
|
||||||
ief=image/ief
|
|
||||||
iefs=image/ief
|
|
||||||
iges=application/iges
|
|
||||||
igs=application/iges
|
|
||||||
ima=application/x-ima
|
|
||||||
imap=application/x-httpd-imap
|
|
||||||
inf=application/inf
|
|
||||||
ins=application/x-internett-signup
|
|
||||||
ip=application/x-ip2
|
|
||||||
isu=video/x-isvideo
|
|
||||||
it=audio/it
|
|
||||||
iv=application/x-inventor
|
|
||||||
ivr=i-world/i-vrml
|
|
||||||
ivy=application/x-livescreen
|
|
||||||
jam=audio/x-jam
|
|
||||||
jav=text/x-java-source
|
|
||||||
java=text/x-java-source
|
|
||||||
jcm=application/x-java-commerce
|
|
||||||
jfif-tbnl=image/jpeg
|
|
||||||
jfif=image/jpeg
|
|
||||||
jnlp=application/x-java-jnlp-file
|
|
||||||
jpe=image/jpeg
|
|
||||||
jpeg=image/jpeg
|
|
||||||
jpg=image/jpeg
|
|
||||||
jps=image/x-jps
|
|
||||||
js=application/javascript
|
|
||||||
json=application/json
|
|
||||||
jut=image/jutvision
|
|
||||||
kar=audio/midi
|
|
||||||
karbon=application/vnd.kde.karbon
|
|
||||||
kfo=application/vnd.kde.kformula
|
|
||||||
flw=application/vnd.kde.kivio
|
|
||||||
kml=application/vnd.google-earth.kml+xml
|
|
||||||
kmz=application/vnd.google-earth.kmz
|
|
||||||
kon=application/vnd.kde.kontour
|
|
||||||
kpr=application/vnd.kde.kpresenter
|
|
||||||
kpt=application/vnd.kde.kpresenter
|
|
||||||
ksp=application/vnd.kde.kspread
|
|
||||||
kwd=application/vnd.kde.kword
|
|
||||||
kwt=application/vnd.kde.kword
|
|
||||||
ksh=text/x-scriptksh
|
|
||||||
la=audio/nspaudio
|
|
||||||
lam=audio/x-liveaudio
|
|
||||||
latex=application/x-latex
|
|
||||||
lha=application/lha
|
|
||||||
lhx=application/octet-stream
|
|
||||||
list=text/plain
|
|
||||||
lma=audio/nspaudio
|
|
||||||
log=text/plain
|
|
||||||
lsp=text/x-scriptlisp
|
|
||||||
lst=text/plain
|
|
||||||
lsx=text/x-la-asf
|
|
||||||
ltx=application/x-latex
|
|
||||||
lzh=application/octet-stream
|
|
||||||
lzx=application/lzx
|
|
||||||
m1v=video/mpeg
|
|
||||||
m2a=audio/mpeg
|
|
||||||
m2v=video/mpeg
|
|
||||||
m3u=audio/x-mpegurl
|
|
||||||
m=text/x-m
|
|
||||||
man=application/x-troff-man
|
|
||||||
manifest=text/cache-manifest
|
|
||||||
map=application/x-navimap
|
|
||||||
mar=text/plain
|
|
||||||
mbd=application/mbedlet
|
|
||||||
mc$=application/x-magic-cap-package-10
|
|
||||||
mcd=application/mcad
|
|
||||||
mcf=text/mcf
|
|
||||||
mcp=application/netmc
|
|
||||||
me=application/x-troff-me
|
|
||||||
mht=message/rfc822
|
|
||||||
mhtml=message/rfc822
|
|
||||||
mid=application/x-midi
|
|
||||||
midi=application/x-midi
|
|
||||||
mif=application/x-frame
|
|
||||||
mime=message/rfc822
|
|
||||||
mjf=audio/x-vndaudioexplosionmjuicemediafile
|
|
||||||
mjpg=video/x-motion-jpeg
|
|
||||||
mm=application/base64
|
|
||||||
mme=application/base64
|
|
||||||
mod=audio/mod
|
|
||||||
moov=video/quicktime
|
|
||||||
mov=video/quicktime
|
|
||||||
movie=video/x-sgi-movie
|
|
||||||
mp2=audio/mpeg
|
|
||||||
mp3=audio/mpeg3
|
|
||||||
mp4=video/mp4
|
|
||||||
mpa=audio/mpeg
|
|
||||||
mpc=application/x-project
|
|
||||||
mpe=video/mpeg
|
|
||||||
mpeg=video/mpeg
|
|
||||||
mpg=video/mpeg
|
|
||||||
mpga=audio/mpeg
|
|
||||||
mpp=application/vndms-project
|
|
||||||
mpt=application/x-project
|
|
||||||
mpv=application/x-project
|
|
||||||
mpx=application/x-project
|
|
||||||
mrc=application/marc
|
|
||||||
ms=application/x-troff-ms
|
|
||||||
mv=video/x-sgi-movie
|
|
||||||
my=audio/make
|
|
||||||
mzz=application/x-vndaudioexplosionmzz
|
|
||||||
nap=image/naplps
|
|
||||||
naplps=image/naplps
|
|
||||||
nc=application/x-netcdf
|
|
||||||
ncm=application/vndnokiaconfiguration-message
|
|
||||||
nif=image/x-niff
|
|
||||||
niff=image/x-niff
|
|
||||||
nix=application/x-mix-transfer
|
|
||||||
nsc=application/x-conference
|
|
||||||
nvd=application/x-navidoc
|
|
||||||
o=application/octet-stream
|
|
||||||
oda=application/oda
|
|
||||||
odb=application/vnd.oasis.opendocument.database
|
|
||||||
odc=application/vnd.oasis.opendocument.chart
|
|
||||||
odf=application/vnd.oasis.opendocument.formula
|
|
||||||
odg=application/vnd.oasis.opendocument.graphics
|
|
||||||
odi=application/vnd.oasis.opendocument.image
|
|
||||||
odm=application/vnd.oasis.opendocument.text-master
|
|
||||||
odp=application/vnd.oasis.opendocument.presentation
|
|
||||||
ods=application/vnd.oasis.opendocument.spreadsheet
|
|
||||||
odt=application/vnd.oasis.opendocument.text
|
|
||||||
oga=audio/ogg
|
|
||||||
ogg=audio/ogg
|
|
||||||
ogv=video/ogg
|
|
||||||
omc=application/x-omc
|
|
||||||
omcd=application/x-omcdatamaker
|
|
||||||
omcr=application/x-omcregerator
|
|
||||||
otc=application/vnd.oasis.opendocument.chart-template
|
|
||||||
otf=application/vnd.oasis.opendocument.formula-template
|
|
||||||
otg=application/vnd.oasis.opendocument.graphics-template
|
|
||||||
oth=application/vnd.oasis.opendocument.text-web
|
|
||||||
oti=application/vnd.oasis.opendocument.image-template
|
|
||||||
otm=application/vnd.oasis.opendocument.text-master
|
|
||||||
otp=application/vnd.oasis.opendocument.presentation-template
|
|
||||||
ots=application/vnd.oasis.opendocument.spreadsheet-template
|
|
||||||
ott=application/vnd.oasis.opendocument.text-template
|
|
||||||
p10=application/pkcs10
|
|
||||||
p12=application/pkcs-12
|
|
||||||
p7a=application/x-pkcs7-signature
|
|
||||||
p7c=application/pkcs7-mime
|
|
||||||
p7m=application/pkcs7-mime
|
|
||||||
p7r=application/x-pkcs7-certreqresp
|
|
||||||
p7s=application/pkcs7-signature
|
|
||||||
p=text/x-pascal
|
|
||||||
part=application/pro_eng
|
|
||||||
pas=text/pascal
|
|
||||||
pbm=image/x-portable-bitmap
|
|
||||||
pcl=application/vndhp-pcl
|
|
||||||
pct=image/x-pict
|
|
||||||
pcx=image/x-pcx
|
|
||||||
pdb=chemical/x-pdb
|
|
||||||
pdf=application/pdf
|
|
||||||
pfunk=audio/make
|
|
||||||
pgm=image/x-portable-graymap
|
|
||||||
pic=image/pict
|
|
||||||
pict=image/pict
|
|
||||||
pkg=application/x-newton-compatible-pkg
|
|
||||||
pko=application/vndms-pkipko
|
|
||||||
pl=text/x-scriptperl
|
|
||||||
plx=application/x-pixclscript
|
|
||||||
pm4=application/x-pagemaker
|
|
||||||
pm5=application/x-pagemaker
|
|
||||||
pm=text/x-scriptperl-module
|
|
||||||
png=image/png
|
|
||||||
pnm=application/x-portable-anymap
|
|
||||||
pot=application/mspowerpoint
|
|
||||||
pov=model/x-pov
|
|
||||||
ppa=application/vndms-powerpoint
|
|
||||||
ppm=image/x-portable-pixmap
|
|
||||||
pps=application/mspowerpoint
|
|
||||||
ppt=application/mspowerpoint
|
|
||||||
ppz=application/mspowerpoint
|
|
||||||
pre=application/x-freelance
|
|
||||||
prt=application/pro_eng
|
|
||||||
ps=application/postscript
|
|
||||||
psd=application/octet-stream
|
|
||||||
pvu=paleovu/x-pv
|
|
||||||
pwz=application/vndms-powerpoint
|
|
||||||
py=text/x-scriptphyton
|
|
||||||
pyc=applicaiton/x-bytecodepython
|
|
||||||
qcp=audio/vndqcelp
|
|
||||||
qd3=x-world/x-3dmf
|
|
||||||
qd3d=x-world/x-3dmf
|
|
||||||
qif=image/x-quicktime
|
|
||||||
qt=video/quicktime
|
|
||||||
qtc=video/x-qtc
|
|
||||||
qti=image/x-quicktime
|
|
||||||
qtif=image/x-quicktime
|
|
||||||
ra=audio/x-pn-realaudio
|
|
||||||
ram=audio/x-pn-realaudio
|
|
||||||
rar=application/x-rar-compressed
|
|
||||||
ras=application/x-cmu-raster
|
|
||||||
rast=image/cmu-raster
|
|
||||||
rexx=text/x-scriptrexx
|
|
||||||
rf=image/vndrn-realflash
|
|
||||||
rgb=image/x-rgb
|
|
||||||
rm=application/vndrn-realmedia
|
|
||||||
rmi=audio/mid
|
|
||||||
rmm=audio/x-pn-realaudio
|
|
||||||
rmp=audio/x-pn-realaudio
|
|
||||||
rng=application/ringing-tones
|
|
||||||
rnx=application/vndrn-realplayer
|
|
||||||
roff=application/x-troff
|
|
||||||
rp=image/vndrn-realpix
|
|
||||||
rpm=audio/x-pn-realaudio-plugin
|
|
||||||
rt=text/vndrn-realtext
|
|
||||||
rtf=text/richtext
|
|
||||||
rtx=text/richtext
|
|
||||||
rv=video/vndrn-realvideo
|
|
||||||
s=text/x-asm
|
|
||||||
s3m=audio/s3m
|
|
||||||
s7z=application/x-7z-compressed
|
|
||||||
saveme=application/octet-stream
|
|
||||||
sbk=application/x-tbook
|
|
||||||
scm=text/x-scriptscheme
|
|
||||||
sdml=text/plain
|
|
||||||
sdp=application/sdp
|
|
||||||
sdr=application/sounder
|
|
||||||
sea=application/sea
|
|
||||||
set=application/set
|
|
||||||
sgm=text/x-sgml
|
|
||||||
sgml=text/x-sgml
|
|
||||||
sh=text/x-scriptsh
|
|
||||||
shar=application/x-bsh
|
|
||||||
shtml=text/x-server-parsed-html
|
|
||||||
sid=audio/x-psid
|
|
||||||
skd=application/x-koan
|
|
||||||
skm=application/x-koan
|
|
||||||
skp=application/x-koan
|
|
||||||
skt=application/x-koan
|
|
||||||
sit=application/x-stuffit
|
|
||||||
sitx=application/x-stuffitx
|
|
||||||
sl=application/x-seelogo
|
|
||||||
smi=application/smil
|
|
||||||
smil=application/smil
|
|
||||||
snd=audio/basic
|
|
||||||
sol=application/solids
|
|
||||||
spc=text/x-speech
|
|
||||||
spl=application/futuresplash
|
|
||||||
spr=application/x-sprite
|
|
||||||
sprite=application/x-sprite
|
|
||||||
spx=audio/ogg
|
|
||||||
src=application/x-wais-source
|
|
||||||
ssi=text/x-server-parsed-html
|
|
||||||
ssm=application/streamingmedia
|
|
||||||
sst=application/vndms-pkicertstore
|
|
||||||
step=application/step
|
|
||||||
stl=application/sla
|
|
||||||
stp=application/step
|
|
||||||
sv4cpio=application/x-sv4cpio
|
|
||||||
sv4crc=application/x-sv4crc
|
|
||||||
svf=image/vnddwg
|
|
||||||
svg=image/svg+xml
|
|
||||||
svr=application/x-world
|
|
||||||
swf=application/x-shockwave-flash
|
|
||||||
t=application/x-troff
|
|
||||||
talk=text/x-speech
|
|
||||||
tar=application/x-tar
|
|
||||||
tbk=application/toolbook
|
|
||||||
tcl=text/x-scripttcl
|
|
||||||
tcsh=text/x-scripttcsh
|
|
||||||
tex=application/x-tex
|
|
||||||
texi=application/x-texinfo
|
|
||||||
texinfo=application/x-texinfo
|
|
||||||
text=text/plain
|
|
||||||
tgz=application/gnutar
|
|
||||||
tif=image/tiff
|
|
||||||
tiff=image/tiff
|
|
||||||
tr=application/x-troff
|
|
||||||
tsi=audio/tsp-audio
|
|
||||||
tsp=application/dsptype
|
|
||||||
tsv=text/tab-separated-values
|
|
||||||
turbot=image/florian
|
|
||||||
txt=text/plain
|
|
||||||
uil=text/x-uil
|
|
||||||
uni=text/uri-list
|
|
||||||
unis=text/uri-list
|
|
||||||
unv=application/i-deas
|
|
||||||
uri=text/uri-list
|
|
||||||
uris=text/uri-list
|
|
||||||
ustar=application/x-ustar
|
|
||||||
uu=text/x-uuencode
|
|
||||||
uue=text/x-uuencode
|
|
||||||
vcd=application/x-cdlink
|
|
||||||
vcf=text/x-vcard
|
|
||||||
vcard=text/x-vcard
|
|
||||||
vcs=text/x-vcalendar
|
|
||||||
vda=application/vda
|
|
||||||
vdo=video/vdo
|
|
||||||
vew=application/groupwise
|
|
||||||
viv=video/vivo
|
|
||||||
vivo=video/vivo
|
|
||||||
vmd=application/vocaltec-media-desc
|
|
||||||
vmf=application/vocaltec-media-file
|
|
||||||
voc=audio/voc
|
|
||||||
vos=video/vosaic
|
|
||||||
vox=audio/voxware
|
|
||||||
vqe=audio/x-twinvq-plugin
|
|
||||||
vqf=audio/x-twinvq
|
|
||||||
vql=audio/x-twinvq-plugin
|
|
||||||
vrml=application/x-vrml
|
|
||||||
vrt=x-world/x-vrt
|
|
||||||
vsd=application/x-visio
|
|
||||||
vst=application/x-visio
|
|
||||||
vsw=application/x-visio
|
|
||||||
w60=application/wordperfect60
|
|
||||||
w61=application/wordperfect61
|
|
||||||
w6w=application/msword
|
|
||||||
wav=audio/wav
|
|
||||||
wb1=application/x-qpro
|
|
||||||
wbmp=image/vnd.wap.wbmp
|
|
||||||
web=application/vndxara
|
|
||||||
wiz=application/msword
|
|
||||||
wk1=application/x-123
|
|
||||||
wmf=windows/metafile
|
|
||||||
wml=text/vnd.wap.wml
|
|
||||||
wmlc=application/vnd.wap.wmlc
|
|
||||||
wmls=text/vnd.wap.wmlscript
|
|
||||||
wmlsc=application/vnd.wap.wmlscriptc
|
|
||||||
word=application/msword
|
|
||||||
wp5=application/wordperfect
|
|
||||||
wp6=application/wordperfect
|
|
||||||
wp=application/wordperfect
|
|
||||||
wpd=application/wordperfect
|
|
||||||
wq1=application/x-lotus
|
|
||||||
wri=application/mswrite
|
|
||||||
wrl=application/x-world
|
|
||||||
wrz=model/vrml
|
|
||||||
wsc=text/scriplet
|
|
||||||
wsrc=application/x-wais-source
|
|
||||||
wtk=application/x-wintalk
|
|
||||||
x-png=image/png
|
|
||||||
xbm=image/x-xbitmap
|
|
||||||
xdr=video/x-amt-demorun
|
|
||||||
xgz=xgl/drawing
|
|
||||||
xif=image/vndxiff
|
|
||||||
xl=application/excel
|
|
||||||
xla=application/excel
|
|
||||||
xlb=application/excel
|
|
||||||
xlc=application/excel
|
|
||||||
xld=application/excel
|
|
||||||
xlk=application/excel
|
|
||||||
xll=application/excel
|
|
||||||
xlm=application/excel
|
|
||||||
xls=application/excel
|
|
||||||
xlt=application/excel
|
|
||||||
xlv=application/excel
|
|
||||||
xlw=application/excel
|
|
||||||
xm=audio/xm
|
|
||||||
xml=text/xml
|
|
||||||
xmz=xgl/movie
|
|
||||||
xpix=application/x-vndls-xpix
|
|
||||||
xpm=image/x-xpixmap
|
|
||||||
xsr=video/x-amt-showrun
|
|
||||||
xwd=image/x-xwd
|
|
||||||
xyz=chemical/x-pdb
|
|
||||||
z=application/x-compress
|
|
||||||
zip=application/zip
|
|
||||||
zoo=application/octet-stream
|
|
||||||
zsh=text/x-scriptzsh
|
|
||||||
# Office 2007 mess - http://wdg.uncc.edu/Microsoft_Office_2007_MIME_Types_for_Apache_and_IIS
|
|
||||||
docx=application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
||||||
docm=application/vnd.ms-word.document.macroEnabled.12
|
|
||||||
dotx=application/vnd.openxmlformats-officedocument.wordprocessingml.template
|
|
||||||
dotm=application/vnd.ms-word.template.macroEnabled.12
|
|
||||||
xlsx=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
||||||
xlsm=application/vnd.ms-excel.sheet.macroEnabled.12
|
|
||||||
xltx=application/vnd.openxmlformats-officedocument.spreadsheetml.template
|
|
||||||
xltm=application/vnd.ms-excel.template.macroEnabled.12
|
|
||||||
xlsb=application/vnd.ms-excel.sheet.binary.macroEnabled.12
|
|
||||||
xlam=application/vnd.ms-excel.addin.macroEnabled.12
|
|
||||||
pptx=application/vnd.openxmlformats-officedocument.presentationml.presentation
|
|
||||||
pptm=application/vnd.ms-powerpoint.presentation.macroEnabled.12
|
|
||||||
ppsx=application/vnd.openxmlformats-officedocument.presentationml.slideshow
|
|
||||||
ppsm=application/vnd.ms-powerpoint.slideshow.macroEnabled.12
|
|
||||||
potx=application/vnd.openxmlformats-officedocument.presentationml.template
|
|
||||||
potm=application/vnd.ms-powerpoint.template.macroEnabled.12
|
|
||||||
ppam=application/vnd.ms-powerpoint.addin.macroEnabled.12
|
|
||||||
sldx=application/vnd.openxmlformats-officedocument.presentationml.slide
|
|
||||||
sldm=application/vnd.ms-powerpoint.slide.macroEnabled.12
|
|
||||||
thmx=application/vnd.ms-officetheme
|
|
||||||
onetoc=application/onenote
|
|
||||||
onetoc2=application/onenote
|
|
||||||
onetmp=application/onenote
|
|
||||||
onepkg=application/onenote
|
|
||||||
# koffice
|
|
||||||
|
|
||||||
# iWork
|
|
||||||
key=application/x-iwork-keynote-sffkey
|
|
||||||
kth=application/x-iwork-keynote-sffkth
|
|
||||||
nmbtemplate=application/x-iwork-numbers-sfftemplate
|
|
||||||
numbers=application/x-iwork-numbers-sffnumbers
|
|
||||||
pages=application/x-iwork-pages-sffpages
|
|
||||||
template=application/x-iwork-pages-sfftemplate
|
|
||||||
|
|
||||||
# Extensions for Mozilla apps (Firefox and friends)
|
|
||||||
xpi=application/x-xpinstall
|
|
||||||
|
|
||||||
# Opera extensions
|
|
||||||
oex=application/x-opera-extension
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"os"
|
|
||||||
fpath "path/filepath"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Static struct {
|
|
||||||
*revel.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method handles requests for files. The supplied prefix may be absolute
|
|
||||||
// or relative. If the prefix is relative it is assumed to be relative to the
|
|
||||||
// application directory. The filepath may either be just a file or an
|
|
||||||
// additional filepath to search for the given file. This response may return
|
|
||||||
// the following responses in the event of an error or invalid request;
|
|
||||||
// 403(Forbidden): If the prefix filepath combination results in a directory.
|
|
||||||
// 404(Not found): If the prefix and filepath combination results in a non-existent file.
|
|
||||||
// 500(Internal Server Error): There are a few edge cases that would likely indicate some configuration error outside of revel.
|
|
||||||
//
|
|
||||||
// Note that when defining routes in routes/conf the parameters must not have
|
|
||||||
// spaces around the comma.
|
|
||||||
// Bad: Static.Serve("public/img", "favicon.png")
|
|
||||||
// Good: Static.Serve("public/img","favicon.png")
|
|
||||||
//
|
|
||||||
// Examples:
|
|
||||||
// Serving a directory
|
|
||||||
// Route (conf/routes):
|
|
||||||
// GET /public/{<.*>filepath} Static.Serve("public")
|
|
||||||
// Request:
|
|
||||||
// public/js/sessvars.js
|
|
||||||
// Calls
|
|
||||||
// Static.Serve("public","js/sessvars.js")
|
|
||||||
//
|
|
||||||
// Serving a file
|
|
||||||
// Route (conf/routes):
|
|
||||||
// GET /favicon.ico Static.Serve("public/img","favicon.png")
|
|
||||||
// Request:
|
|
||||||
// favicon.ico
|
|
||||||
// Calls:
|
|
||||||
// Static.Serve("public/img", "favicon.png")
|
|
||||||
func (c Static) Serve(prefix, filepath string) revel.Result {
|
|
||||||
var basePath string
|
|
||||||
|
|
||||||
if !fpath.IsAbs(prefix) {
|
|
||||||
basePath = revel.BasePath
|
|
||||||
}
|
|
||||||
|
|
||||||
basePathPrefix := fpath.Join(basePath, fpath.FromSlash(prefix))
|
|
||||||
fname := fpath.Join(basePathPrefix, fpath.FromSlash(filepath))
|
|
||||||
if !strings.HasPrefix(fname, basePathPrefix) {
|
|
||||||
revel.WARN.Printf("Attempted to read file outside of base path: %s", fname)
|
|
||||||
return c.NotFound("")
|
|
||||||
}
|
|
||||||
|
|
||||||
finfo, err := os.Stat(fname)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) || err.(*os.PathError).Err == syscall.ENOTDIR {
|
|
||||||
revel.WARN.Printf("File not found (%s): %s ", fname, err)
|
|
||||||
return c.NotFound("File not found")
|
|
||||||
}
|
|
||||||
revel.ERROR.Printf("Error trying to get fileinfo for '%s': %s", fname, err)
|
|
||||||
return c.RenderError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if finfo.Mode().IsDir() {
|
|
||||||
revel.WARN.Printf("Attempted directory listing of %s", fname)
|
|
||||||
return c.Forbidden("Directory listing not allowed")
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(fname)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
revel.WARN.Printf("File not found (%s): %s ", fname, err)
|
|
||||||
return c.NotFound("File not found")
|
|
||||||
}
|
|
||||||
revel.ERROR.Printf("Error opening '%s': %s", fname, err)
|
|
||||||
return c.RenderError(err)
|
|
||||||
}
|
|
||||||
return c.RenderFile(file, revel.Inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method allows modules to serve binary files. The parameters are the same
|
|
||||||
// as Static.Serve with the additional module name pre-pended to the list of
|
|
||||||
// arguments.
|
|
||||||
func (c Static) ServeModule(moduleName, prefix, filepath string) revel.Result {
|
|
||||||
var basePath string
|
|
||||||
for _, module := range revel.Modules {
|
|
||||||
if module.Name == moduleName {
|
|
||||||
basePath = module.Path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
absPath := fpath.Join(basePath, fpath.FromSlash(prefix))
|
|
||||||
|
|
||||||
return c.Serve(absPath, filepath)
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
"html"
|
|
||||||
"html/template"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestRunner struct {
|
|
||||||
*revel.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestSuiteDesc struct {
|
|
||||||
Name string
|
|
||||||
Tests []TestDesc
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestDesc struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestSuiteResult struct {
|
|
||||||
Name string
|
|
||||||
Passed bool
|
|
||||||
Results []TestResult
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestResult struct {
|
|
||||||
Name string
|
|
||||||
Passed bool
|
|
||||||
ErrorHtml template.HTML
|
|
||||||
ErrorSummary string
|
|
||||||
}
|
|
||||||
|
|
||||||
var NONE = []reflect.Value{}
|
|
||||||
|
|
||||||
func (c TestRunner) Index() revel.Result {
|
|
||||||
var testSuites []TestSuiteDesc
|
|
||||||
for _, testSuite := range revel.TestSuites {
|
|
||||||
testSuites = append(testSuites, DescribeSuite(testSuite))
|
|
||||||
}
|
|
||||||
return c.Render(testSuites)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run runs a single test, given by the argument.
|
|
||||||
func (c TestRunner) Run(suite, test string) revel.Result {
|
|
||||||
result := TestResult{Name: test}
|
|
||||||
for _, testSuite := range revel.TestSuites {
|
|
||||||
t := reflect.TypeOf(testSuite).Elem()
|
|
||||||
if t.Name() != suite {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found the suite, create a new instance and run the named method.
|
|
||||||
v := reflect.New(t)
|
|
||||||
func() {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
error := revel.NewErrorFromPanic(err)
|
|
||||||
if error == nil {
|
|
||||||
result.ErrorHtml = template.HTML(html.EscapeString(fmt.Sprint(err)))
|
|
||||||
} else {
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
tmpl, _ := revel.MainTemplateLoader.Template("TestRunner/FailureDetail.html")
|
|
||||||
tmpl.Render(&buffer, error)
|
|
||||||
result.ErrorSummary = errorSummary(error)
|
|
||||||
result.ErrorHtml = template.HTML(buffer.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Initialize the test suite with a NewTestSuite()
|
|
||||||
testSuiteInstance := v.Elem().FieldByName("TestSuite")
|
|
||||||
testSuiteInstance.Set(reflect.ValueOf(revel.NewTestSuite()))
|
|
||||||
|
|
||||||
// Call Before(), call the test, and call After().
|
|
||||||
if m := v.MethodByName("Before"); m.IsValid() {
|
|
||||||
m.Call(NONE)
|
|
||||||
}
|
|
||||||
|
|
||||||
if m := v.MethodByName("After"); m.IsValid() {
|
|
||||||
defer m.Call(NONE)
|
|
||||||
}
|
|
||||||
|
|
||||||
v.MethodByName(test).Call(NONE)
|
|
||||||
|
|
||||||
// No panic means success.
|
|
||||||
result.Passed = true
|
|
||||||
}()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return c.RenderJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List returns a JSON list of test suites and tests.
|
|
||||||
// Used by the "test" command line tool.
|
|
||||||
func (c TestRunner) List() revel.Result {
|
|
||||||
var testSuites []TestSuiteDesc
|
|
||||||
for _, testSuite := range revel.TestSuites {
|
|
||||||
testSuites = append(testSuites, DescribeSuite(testSuite))
|
|
||||||
}
|
|
||||||
return c.RenderJson(testSuites)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DescribeSuite(testSuite interface{}) TestSuiteDesc {
|
|
||||||
t := reflect.TypeOf(testSuite)
|
|
||||||
|
|
||||||
// Get a list of methods of the embedded test type.
|
|
||||||
super := t.Elem().Field(0).Type
|
|
||||||
superMethodNameSet := map[string]struct{}{}
|
|
||||||
for i := 0; i < super.NumMethod(); i++ {
|
|
||||||
superMethodNameSet[super.Method(i).Name] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of methods on the test suite that take no parameters, return
|
|
||||||
// no results, and were not part of the embedded type's method set.
|
|
||||||
var tests []TestDesc
|
|
||||||
for i := 0; i < t.NumMethod(); i++ {
|
|
||||||
m := t.Method(i)
|
|
||||||
mt := m.Type
|
|
||||||
_, isSuperMethod := superMethodNameSet[m.Name]
|
|
||||||
if mt.NumIn() == 1 &&
|
|
||||||
mt.NumOut() == 0 &&
|
|
||||||
mt.In(0) == t &&
|
|
||||||
!isSuperMethod &&
|
|
||||||
strings.HasPrefix(m.Name, "Test") {
|
|
||||||
tests = append(tests, TestDesc{m.Name})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TestSuiteDesc{
|
|
||||||
Name: t.Elem().Name(),
|
|
||||||
Tests: tests,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorSummary(error *revel.Error) string {
|
|
||||||
var message = fmt.Sprintf("%4sStatus: %s\n%4sIn %s", "", error.Description, "", error.Path)
|
|
||||||
if error.Line != 0 {
|
|
||||||
message += fmt.Sprintf(" (around line %d): ", error.Line)
|
|
||||||
for _, line := range error.ContextSource() {
|
|
||||||
if line.IsError {
|
|
||||||
message += line.Source
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/revel/revel"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
revel.OnAppStart(func() {
|
|
||||||
fmt.Println("Go to /@tests to run the tests.")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
<b>{{.Description}}</b><br>
|
|
||||||
In {{.Path}}
|
|
||||||
{{if .Line}}
|
|
||||||
(around {{if .Line}}line {{.Line}}{{end}}{{if .Column}} column {{.Column}}{{end}})
|
|
||||||
{{end}}:
|
|
||||||
{{range .ContextSource}}{{if .IsError}}<code>{{.Source}}</code>{{end}}{{end}}<br>
|
|
||||||
<a style="cursor:pointer;"
|
|
||||||
onclick="x=this.nextSibling.style;if(!x.display)x.display='none';else x.display=''">
|
|
||||||
Show Stack</a><pre style="display:none;">{{.Stack}}</pre>
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Revel Test Runner</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
||||||
<link href="/@tests/public/css/bootstrap.css" type="text/css" rel="stylesheet"></link>
|
|
||||||
<script src="/@tests/public/js/jquery-1.9.1.min.js" type="text/javascript"></script>
|
|
||||||
<style>
|
|
||||||
header { padding:20px 0; background-color:#ADD8E6 }
|
|
||||||
.passed td { background-color: #90EE90 !important; }
|
|
||||||
.failed td { background-color: #FFB6C1 !important; }
|
|
||||||
.tests td.name, .tests td.result { padding-top: 13px; }
|
|
||||||
pre { font-size:10px; white-space: pre; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<div class="container">
|
|
||||||
<table><tr><td>
|
|
||||||
<h1>Test Runner</h1>
|
|
||||||
<p class="lead">Run all of your application's tests from here.</p>
|
|
||||||
</td><td style="padding-left:150px;">
|
|
||||||
<button class="btn btn-large" all-tests="">Run All Tests</button>
|
|
||||||
</td></tr></table>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
{{range .testSuites}}
|
|
||||||
<p class="lead" style="margin-top:20px;">{{.Name}}</p>
|
|
||||||
<table class="table table-striped tests" suite="{{.Name}}">
|
|
||||||
{{range .Tests}}
|
|
||||||
<tr>
|
|
||||||
<td class="name">{{.Name}}</td>
|
|
||||||
<td class="result">
|
|
||||||
</td>
|
|
||||||
<td><button test="{{.Name}}" class="btn">Run</button></td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var running = 0;
|
|
||||||
|
|
||||||
$("button[test]").click(function() {
|
|
||||||
var button = $(this).addClass("disabled").text("Running");
|
|
||||||
running += 1;
|
|
||||||
runTest(button);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("button[all-tests]").click(function() {
|
|
||||||
var button = $(this).addClass("disabled").text("Running");
|
|
||||||
$("button[test]").click();
|
|
||||||
});
|
|
||||||
|
|
||||||
function runTest(button) {
|
|
||||||
var suite = button.parents("table").attr("suite");
|
|
||||||
var test = button.attr("test");
|
|
||||||
var row = button.parents("tr");
|
|
||||||
var resultCell = row.children(".result");
|
|
||||||
$.ajax({
|
|
||||||
dataType: "json",
|
|
||||||
url: "/@tests/"+suite+"/"+test,
|
|
||||||
async: false,
|
|
||||||
success: function(result) {
|
|
||||||
row.attr("class", result.Passed ? "passed" : "failed");
|
|
||||||
if (result.Passed) {
|
|
||||||
resultCell.html("");
|
|
||||||
} else {
|
|
||||||
resultCell.html(result.ErrorHtml);
|
|
||||||
}
|
|
||||||
button.removeClass("disabled").text("Run");
|
|
||||||
running -= 1;
|
|
||||||
if (running == 0) {
|
|
||||||
$("button[all-tests]").removeClass("disabled").text("Run All Tests");
|
|
||||||
}
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
-47
@@ -1,47 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Revel Test Runner</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #333333;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
header { padding:20px 0; }
|
|
||||||
header.passed { background-color: #90EE90 !important; }
|
|
||||||
header.failed { background-color: #FFB6C1 !important; }
|
|
||||||
table { margin-top: 20px; padding: 8px; line-height: 20px; }
|
|
||||||
td { vertical-align: top; padding-right:20px; }
|
|
||||||
a { color: #0088cc; }
|
|
||||||
.container { margin-left: auto; margin-right: auto; width: 940px; }
|
|
||||||
.result.failed b { font-weight:bold; color: #C00; font-size: 14px; }
|
|
||||||
.result.failed span { color: #C00; font-size: 14px; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header class="{{if .Passed}}passed{{else}}failed{{end}}">
|
|
||||||
<div class="container">
|
|
||||||
<h1>{{.Name}}</h1>
|
|
||||||
<p>{{if .Passed}}PASSED{{else}}FAILED{{end}}</p>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<table>
|
|
||||||
{{range .Results}}
|
|
||||||
<tr class="result {{if .Passed}}passed{{else}}failed{{end}}">
|
|
||||||
<td><span>{{.Name}}</span></td>
|
|
||||||
<td>{{if .ErrorHtml}}{{.ErrorHtml}}{{else}}PASSED{{end}}</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
GET /@tests TestRunner.Index
|
|
||||||
GET /@tests.list TestRunner.List
|
|
||||||
GET /@tests/public/*filepath Static.ServeModule(testrunner,public)
|
|
||||||
GET /@tests/:suite/:test TestRunner.Run
|
|
||||||
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
-5
@@ -1,5 +0,0 @@
|
|||||||
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
|
||||||
//@ sourceMappingURL=jquery.min.map
|
|
||||||
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
|
||||||
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
|
||||||
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Forbidden</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{with .Error}}
|
|
||||||
<h1>
|
|
||||||
{{.Title}}
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
{{.Description}}
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "{{js .Error.Title}}",
|
|
||||||
"description": "{{js .Error.Description}}"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{{.Error.Title}}
|
|
||||||
|
|
||||||
{{.Error.Description}}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<forbidden>{{.Error.Description}}</forbidden>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
<style type="text/css">
|
|
||||||
html, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: Helvetica, Arial, Sans;
|
|
||||||
background: #EEEEEE;
|
|
||||||
}
|
|
||||||
.block {
|
|
||||||
padding: 20px;
|
|
||||||
border-bottom: 1px solid #aaa;
|
|
||||||
}
|
|
||||||
#header h1 {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 28px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#more {
|
|
||||||
color: #666;
|
|
||||||
font-size: 80%;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
#header {
|
|
||||||
background: #FFFFCC;
|
|
||||||
}
|
|
||||||
#header p {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
#routes {
|
|
||||||
background: #f6f6f6;
|
|
||||||
}
|
|
||||||
#routes h2 {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 18px;
|
|
||||||
margin: 0 0 10px 0;
|
|
||||||
}
|
|
||||||
#routes ol {
|
|
||||||
|
|
||||||
}
|
|
||||||
#routes li {
|
|
||||||
font-size: 14px;
|
|
||||||
font-family: monospace;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="header" class="block">
|
|
||||||
{{with .Error}}
|
|
||||||
<h1>
|
|
||||||
{{.Title}}
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
{{.Description}}
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div id="routes" class="block">
|
|
||||||
<h2>These routes have been tried, in this order :</h2>
|
|
||||||
<ol>
|
|
||||||
{{range .Router.Routes}}
|
|
||||||
<li>{{pad .Method 10}}{{pad .Path 50}}{{.Action}}</li>
|
|
||||||
{{end}}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
Loaded 100 of 2199 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user