Compare commits
90 Commits
feature-ap
...
dev-binnch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb484b2132 | ||
|
|
4d5a3ffd0f | ||
|
|
f78eb4db49 | ||
|
|
8a61b64575 | ||
|
|
419585ff7d | ||
|
|
ffaaa8c11a | ||
|
|
3417e71d04 | ||
|
|
014a141808 | ||
|
|
c35aa1eaa4 | ||
|
|
96b094844e | ||
|
|
9af13bcc32 | ||
|
|
29215a1d64 | ||
|
|
d828a10e7b | ||
|
|
a851aaa399 | ||
|
|
ac99e20aa4 | ||
|
|
d5dabecb81 | ||
|
|
df9bc37e1d | ||
|
|
4277caa571 | ||
|
|
1d18908cd0 | ||
|
|
916ee52cdb | ||
|
|
289e7b16d9 | ||
|
|
016ef5de2d | ||
|
|
52d0a7ed21 | ||
|
|
ddf3236c4f | ||
|
|
9515f1e58f | ||
|
|
c514d0bc1c | ||
|
|
d24531dc78 | ||
|
|
2cfc89ca5f | ||
|
|
a393bb8723 | ||
|
|
599e54de5b | ||
|
|
b0d4005ad6 | ||
|
|
c0cd433c3f | ||
|
|
792c8cfd40 | ||
|
|
4f102ff883 | ||
|
|
40973c4615 | ||
|
|
58bf623d05 | ||
|
|
46e97abe91 | ||
|
|
be01c9c3f7 | ||
|
|
17718732cc | ||
|
|
e2e90f8618 | ||
|
|
25d5df6bfc | ||
|
|
b781f8318c | ||
|
|
0e07cbab8b | ||
|
|
ed75704032 | ||
|
|
c49593171c | ||
|
|
45d72051d0 | ||
|
|
10b387faa6 | ||
|
|
30ebc95abf | ||
|
|
9bc65bc099 | ||
|
|
39809dc4c6 | ||
|
|
8c4a203d96 | ||
|
|
034ad821ca | ||
|
|
c894b7b308 | ||
|
|
c0979be9f3 | ||
|
|
b45e9eacb0 | ||
|
|
16d47418ad | ||
|
|
5d48d1853d | ||
|
|
f503da30b7 | ||
|
|
11e282de9a | ||
|
|
8f86754bf2 | ||
|
|
e2f125b253 | ||
|
|
0e55b1d83d | ||
|
|
52a3ac13b3 | ||
|
|
6f12e179eb | ||
|
|
4669fbcbdd | ||
|
|
51fedfa6dc | ||
|
|
cd3c2f7b12 | ||
|
|
a6d3fe9cb8 | ||
|
|
9d47b4eac9 | ||
|
|
163215d547 | ||
|
|
4d7a9c8089 | ||
|
|
4e1f8f3d6e | ||
|
|
320c78e925 | ||
|
|
6a4d7d1056 | ||
|
|
1f45666ec4 | ||
|
|
d979a0c3e2 | ||
|
|
6555384e5c | ||
|
|
954c4e5e95 | ||
|
|
8ef91b7418 | ||
|
|
e5f7c66d1e | ||
|
|
346abfe91d | ||
|
|
2a457d6027 | ||
|
|
274782b89e | ||
|
|
5f186f4455 | ||
|
|
f20565d54b | ||
|
|
af9a820cbf | ||
|
|
33e2428b64 | ||
|
|
35c06771e7 | ||
|
|
2f81a529fc | ||
|
|
5d559da2a6 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,8 +8,6 @@ bin/release
|
||||
bin/tmp
|
||||
bin/test
|
||||
bin/src
|
||||
conf/app.conf
|
||||
conf/routes
|
||||
public/upload
|
||||
app/routes/routes.go
|
||||
app/tmp/main.go
|
||||
@@ -18,3 +16,4 @@ app/tmp/main.go
|
||||
.project
|
||||
public/config.codekit
|
||||
files
|
||||
conf/app.conf
|
||||
|
||||
17
.project
17
.project
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>leanote2</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>
|
||||
119
README.md
119
README.md
@@ -1,8 +1,10 @@
|
||||
[中文](https://github.com/leanote/leanote#1-介绍)
|
||||
|
||||
# Leanote
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
Leanote, note just a notebook!
|
||||
Leanote, not just a notebook!
|
||||

|
||||
|
||||
**Some Features**
|
||||
|
||||
@@ -20,12 +22,18 @@ To be honest, our inspiration comes from Evernote. We use Evernote to manage our
|
||||
|
||||
## 3. How to install leanote
|
||||
|
||||
More information about how to install leanote please see:
|
||||
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
||||
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
||||
|
||||
### 3.1. Download leanote
|
||||
|
||||
Leanote V1.0-beta has been released. Binaries:
|
||||
Leanote V1.0.2-beta has been released. Binaries:
|
||||
|
||||
* Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
|
||||
* 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
|
||||
|
||||
@@ -89,106 +97,17 @@ this project. Your help is much appreciated.
|
||||
|
||||
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||
|
||||
## Docs
|
||||
* [leanote binary distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-binary-distribution-installation-tutorial)
|
||||
* [leanote develop distribution installation tutorial](https://github.com/leanote/leanote/wiki/leanote-develop-distribution-installation-tutorial)
|
||||
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
|
||||
|
||||
## Discussion
|
||||
* [leanote bbs](http://bbs.leanote.com)
|
||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||
* QQ Group: 158716820
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
[中文](README_zh.md)
|
||||
|
||||
## 1. 介绍
|
||||
|
||||
Leanote, 不只是笔记!
|
||||
|
||||
**特性**
|
||||
|
||||
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||
|
||||
## 2. 为什么我们要创建leanote?
|
||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||
* 还有...
|
||||
|
||||
## 3.安装leanote
|
||||
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||
|
||||
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||
|
||||
### 3.1. 下载leanote
|
||||
|
||||
Leanote V1.0-beta 已发布, 二进制文件(暂时没有windows版的):
|
||||
|
||||
* Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
|
||||
|
||||
### 3.2. 安装 MongodbDB
|
||||
|
||||
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||
|
||||
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||
|
||||
### 3.3. 导入初始数据
|
||||
|
||||
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||
|
||||
```
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||
```
|
||||
|
||||
初始数据包含两个用户:
|
||||
|
||||
```
|
||||
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||
```
|
||||
|
||||
### 3.4. 配置
|
||||
|
||||
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||
|
||||
``mongodb`` **必须配置!**
|
||||
|
||||
```Shell
|
||||
db.host=localhost
|
||||
db.port=27017
|
||||
db.dbname=leanote
|
||||
db.username=
|
||||
db.password=
|
||||
```
|
||||
|
||||
``app.secret`` **重要**
|
||||
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
|
||||
|
||||
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
|
||||
|
||||
### 3.5. 运行leanote
|
||||
|
||||
```
|
||||
$> cd PATH_TO_LEANOTE/bin
|
||||
$> sudo sh run.sh
|
||||
```
|
||||
|
||||
## 4. 如何对leanote进行二次开发
|
||||
|
||||
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||
|
||||
## 5. 贡献者
|
||||
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
||||
|
||||
## 6. 加入我们
|
||||
|
||||
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
||||
|
||||
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
||||
|
||||
## 讨论
|
||||
* [leanote 社区](http://bbs.leanote.com)
|
||||
* QQ群: 158716820
|
||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||
|
||||
113
README_zh.md
Normal file
113
README_zh.md
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
# Leanote<74><65>Ʒ
|
||||
|
||||
## 1. <20><><EFBFBD><EFBFBD>
|
||||
|
||||
Leanote, <20><>ֻ<EFBFBD>DZʼ<C7B1>!
|
||||

|
||||
|
||||
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**
|
||||
|
||||
* ֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD>: ͨ<><CDA8>leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ, leanote<74><65><EFBFBD>ײ<EFBFBD><D7B2><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>༭<EFBFBD><E0BCAD>tinymce<63><65>markdown. <20><>leanote, <20><><EFBFBD><EFBFBD><EFBFBD>Ծ<EFBFBD><D4BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>.
|
||||
* <20><><EFBFBD><EFBFBD>: <20><>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20>ú<EFBFBD><C3BA><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ.
|
||||
* Э<><D0AD>: <20>ڷ<EFBFBD><DAB7><EFBFBD><EFBFBD><EFBFBD>ͬʱҲ<CAB1><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Э<EFBFBD><D0AD>֪ʶ.
|
||||
* <20><><EFBFBD><EFBFBD>: leanoteҲ<65><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>, <20><>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD>ɲ<EFBFBD><C9B2><EFBFBD>, <20><>leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD>Զ!
|
||||
|
||||
## 2. Ϊʲô<CAB2><C3B4><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>leanote?
|
||||
˵ʵ<EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>evernote<74><65><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>˿, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>evernote<74>IJ<EFBFBD><C4B2><EFBFBD>:
|
||||
* evernote<74>ı༭<C4B1><E0BCAD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><>ʽ<EFBFBD><CABD><EFBFBD>ҵ<EFBFBD>, <20><>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>Ա, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵĻ<C7B5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>), ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>markdown<77>İ<EFBFBD><C4B0><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>evernote<74><65>Ȼû<C8BB><C3BB>.
|
||||
* <20><><EFBFBD><EFBFBD>Ҳ<EFBFBD>뽫֪ʶ<D6AA><CAB6><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><D4BC>IJ<EFBFBD><C4B2><EFBFBD>, <20><>wordpress, <20><>Ϊʲô<CAB2><C3B4><EFBFBD><EFBFBD><EFBFBD>߲<EFBFBD><DFB2>ܺ϶<DCBA>Ϊһ<CEAA><D2BB>?
|
||||
* <20><><EFBFBD><EFBFBD>...
|
||||
|
||||
## 3.<2E><>װleanote
|
||||
leanote<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>˽<EFBFBD><EFBFBD><EFBFBD>Ʊʼ<EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><D7B0><EFBFBD>Լ<EFBFBD><D4BC>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><>ȻҲ<C8BB><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> http://leanote.com <20><>ע<EFBFBD><D7A2>.
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>İ<EFBFBD>װ<EFBFBD>̳<EFBFBD>, <20><><EFBFBD>Ʋ<EFBFBD><C6B2><EFBFBD>:
|
||||
* [leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||
|
||||
### 3.1. <20><><EFBFBD><EFBFBD>leanote
|
||||
|
||||
Leanote V1.0-beta.2 <20>ѷ<EFBFBD><D1B7><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>(<28><>ʱû<CAB1><C3BB>windows<77><73><EFBFBD><EFBFBD>):
|
||||
|
||||
* 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)
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӽ<EFBFBD><EFBFBD><EFBFBD>[Leanote bin repository](https://github.com/leanote/leanote-bin) (<28>Ƽ<EFBFBD>, <20><>ΪΪ<CEAA><CEAA><EFBFBD>°汾)
|
||||
|
||||
### 3.2. <20><>װ MongodbDB
|
||||
|
||||
Leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD>golang(ʹ<><CAB9>[revel](https://revel.github.io/)<29><><EFBFBD><EFBFBD> <20><> [MongoDB](https://www.mongodb.org)<29><><EFBFBD>ݿ<EFBFBD>), <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD>Ȱ<EFBFBD>װMongodb.
|
||||
|
||||
<EFBFBD><EFBFBD>װMongodbDB, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD><EFBFBD><EFBFBD>鿴: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||
|
||||
### 3.3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
||||
|
||||
MongodbDB<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||
|
||||
```
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||
```
|
||||
|
||||
<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>ݰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>:
|
||||
|
||||
```
|
||||
user2 username: admin, password: abc123 (<28><><EFBFBD><EFBFBD>Ա, <20><>Ҫ!)
|
||||
user3 username: demo@leanote.com, password: demo@leanote.com (Ϊ<><CEAA><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>)
|
||||
```
|
||||
|
||||
### 3.4. <20><><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD> `[PATH_TO_LEANOTE]/conf/app.conf`. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>:
|
||||
|
||||
``mongodb`` **<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!**
|
||||
|
||||
```Shell
|
||||
db.host=localhost
|
||||
db.port=27017
|
||||
db.dbname=leanote
|
||||
db.username=
|
||||
db.password=
|
||||
```
|
||||
|
||||
``app.secret`` **<2A><>Ҫ**
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>, app<70><70><EFBFBD><EFBFBD>Կ, <20><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>Ĭ<EFBFBD>ϵ<EFBFBD>, <20><>Ȼ<EFBFBD><C8BB><EFBFBD>а<EFBFBD>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鿴 `app/app.conf` <20><> [revel <20>ֲ<EFBFBD>](https://revel.github.io/)
|
||||
|
||||
### 3.5. <20><><EFBFBD><EFBFBD>leanote
|
||||
|
||||
```
|
||||
$> cd PATH_TO_LEANOTE/bin
|
||||
$> sudo sh run.sh
|
||||
```
|
||||
|
||||
## 4. <20><><EFBFBD>ζ<EFBFBD>leanote<74><65><EFBFBD>ж<EFBFBD><D0B6>ο<EFBFBD><CEBF><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD><EFBFBD>鿴 [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. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>л [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>](https://github.com/leanote/leanote/graphs/contributors) <20>Ĺ<EFBFBD><C4B9><EFBFBD>, leanote<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><C7B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!
|
||||
|
||||
## 6. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
<EFBFBD><EFBFBD>ӭ<EFBFBD>ύ[pull requests](https://github.com/leanote/leanote/pulls) <20><>leanote.
|
||||
|
||||
leanote<EFBFBD><EFBFBD><EFBFBD>кܶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD>, <20><>ӭ<EFBFBD><D3AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>leanote.
|
||||
|
||||
## <20><><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
|
||||
* [leanote<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ư<EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>װ<EFBFBD>̳<EFBFBD>](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Դ<65>뵼<EFBFBD><EBB5BC>](https://github.com/leanote/leanote/wiki/Leanote-source-leanoteԴ<65>뵼<EFBFBD><EBB5BC>)
|
||||
* [leanote blog theme api(<28><><EFBFBD>İ<EFBFBD>)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
||||
* [How to develop leanote <20><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-<2D><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>leanote)
|
||||
|
||||
|
||||
## <20><><EFBFBD><EFBFBD>
|
||||
* [leanote <20><><EFBFBD><EFBFBD>](http://bbs.leanote.com)
|
||||
* QQȺ: 158716820
|
||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||
|
||||
----------------------------------------------------------------
|
||||
[English](README.md)
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
"io"
|
||||
"fmt"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
)
|
||||
@@ -56,8 +57,12 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
return re
|
||||
}
|
||||
// > 5M?
|
||||
if(len(data) > 5 * 1024 * 1024) {
|
||||
resultMsg = "File is bigger than 5M"
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
resultMsg = fmt.Sprintf("The file's size is bigger than %vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
@@ -95,11 +100,15 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
id := bson.NewObjectId();
|
||||
fileInfo.AttachId = id
|
||||
fileId = id.Hex()
|
||||
Ok = attachService.AddAttach(fileInfo)
|
||||
Ok, resultMsg = attachService.AddAttach(fileInfo)
|
||||
if resultMsg != "" {
|
||||
resultMsg = c.Message(resultMsg)
|
||||
}
|
||||
|
||||
fileInfo.Path = ""; // 不要返回
|
||||
resultMsg = "success"
|
||||
|
||||
if Ok {
|
||||
resultMsg = "success"
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
@@ -120,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
|
||||
|
||||
// 下载附件
|
||||
// 权限判断
|
||||
func (c Attach) Download(attachId string) revel.Result {
|
||||
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
|
||||
func (c Attach) Download(attachId, token string) revel.Result {
|
||||
if c.GetUserId() == "" && token == "" {
|
||||
return c.RenderText("你需要从分享页面下载附件!")
|
||||
}
|
||||
|
||||
sessionId := c.Session.Id()
|
||||
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
|
||||
path := attach.Path
|
||||
|
||||
if token != "" && attach.Path == "" {
|
||||
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
|
||||
}
|
||||
if path == "" {
|
||||
return c.RenderText("")
|
||||
}
|
||||
@@ -207,4 +225,4 @@ func (c Attach) DownloadAll(noteId string) revel.Result {
|
||||
// file, _ := os.Open(dir + "/" + filename)
|
||||
// fw.Seek(0, 0)
|
||||
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "strconv"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 用户登录/注销/找回密码
|
||||
@@ -40,7 +41,7 @@ func (c Auth) Login(email, from string) revel.Result {
|
||||
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||
sessionId := c.Session.Id()
|
||||
var msg = ""
|
||||
|
||||
fmt.Println(sessionId)
|
||||
userInfo := authService.Login(email, pwd)
|
||||
if userInfo.Email != "" {
|
||||
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 {
|
||||
sessionId := c.Session.Id()
|
||||
var msg = ""
|
||||
|
||||
var msg = ""
|
||||
// > 5次需要验证码, 直到登录成功
|
||||
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||
msg = "captchaError"
|
||||
@@ -91,18 +92,19 @@ func (c Auth) Demo() revel.Result {
|
||||
|
||||
//--------
|
||||
// 注册
|
||||
func (c Auth) Register(from string) revel.Result {
|
||||
func (c Auth) Register(from, iu string) revel.Result {
|
||||
if !configService.IsOpenRegister() {
|
||||
return c.Redirect("/index")
|
||||
}
|
||||
c.SetLocale()
|
||||
c.RenderArgs["from"] = from
|
||||
c.RenderArgs["iu"] = iu
|
||||
|
||||
c.RenderArgs["title"] = c.Message("register")
|
||||
c.RenderArgs["subTitle"] = c.Message("register")
|
||||
return c.RenderTemplate("home/register.html")
|
||||
}
|
||||
func (c Auth) DoRegister(email, pwd string) revel.Result {
|
||||
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
||||
if !configService.IsOpenRegister() {
|
||||
return c.Redirect("/index")
|
||||
}
|
||||
@@ -117,7 +119,7 @@ func (c Auth) DoRegister(email, pwd string) revel.Result {
|
||||
}
|
||||
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd)
|
||||
re.Ok, re.Msg = authService.Register(email, pwd, iu)
|
||||
|
||||
// 注册成功, 则立即登录之
|
||||
if re.Ok {
|
||||
|
||||
@@ -183,7 +183,7 @@ func (c BaseController) SetLocale() string {
|
||||
lang = "en";
|
||||
}
|
||||
c.RenderArgs["locale"] = lang;
|
||||
c.RenderArgs["siteUrl"] = siteUrl;
|
||||
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||
@@ -193,9 +193,13 @@ func (c BaseController) SetLocale() string {
|
||||
}
|
||||
|
||||
// 设置userInfo
|
||||
func (c BaseController) SetUserInfo() {
|
||||
func (c BaseController) SetUserInfo() info.User {
|
||||
userInfo := c.GetUserInfo()
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
if(userInfo.Username == configService.GetAdminUsername()) {
|
||||
c.RenderArgs["isAdmin"] = true
|
||||
}
|
||||
return userInfo
|
||||
}
|
||||
|
||||
// life
|
||||
@@ -221,6 +225,7 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
|
||||
// 为了msg
|
||||
// msg-v1-v2-v3
|
||||
func (c BaseController) RenderRe(re info.Re) revel.Result {
|
||||
oldMsg := re.Msg
|
||||
if re.Msg != "" {
|
||||
if(strings.Contains(re.Msg, "-")) {
|
||||
msgAndValues := strings.Split(re.Msg, "-")
|
||||
@@ -238,5 +243,8 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
|
||||
re.Msg = c.Message(re.Msg)
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(re.Msg, "???") {
|
||||
re.Msg = oldMsg
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,9 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
// "strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 首页
|
||||
@@ -21,7 +22,7 @@ type File struct {
|
||||
// 上传的是博客logo
|
||||
// TODO logo不要设置权限, 另外的目录
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
re := c.uploadImage("logo", "");
|
||||
re := c.uploadImage("blogLogo", "");
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
@@ -84,7 +85,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
var fileUrlPath = ""
|
||||
var fileId = ""
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultMsg = "内部错误" // 错误信息
|
||||
var resultMsg = "error" // 错误信息
|
||||
var Ok = false
|
||||
|
||||
defer func() {
|
||||
@@ -100,7 +101,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
if(from == "logo") {
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||
} else {
|
||||
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||
@@ -119,7 +120,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
} else {
|
||||
_, ext = SplitFilename(filename)
|
||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||
resultMsg = "不是图片"
|
||||
resultMsg = "Please upload image"
|
||||
return re
|
||||
}
|
||||
}
|
||||
@@ -131,10 +132,22 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
return re
|
||||
}
|
||||
|
||||
var maxFileSize float64
|
||||
if(from == "logo") {
|
||||
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
|
||||
} else if from == "blogLogo" {
|
||||
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
|
||||
} else {
|
||||
maxFileSize = configService.GetUploadSize("uploadImageSize");
|
||||
}
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
|
||||
// > 2M?
|
||||
if(len(data) > 5 * 1024 * 1024) {
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
resultCode = 0
|
||||
resultMsg = "图片大于2M"
|
||||
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
@@ -150,7 +163,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
filesize := GetFilesize(toPathGif)
|
||||
fileUrlPath += "/" + filename
|
||||
resultCode = 1
|
||||
resultMsg = "上传成功!"
|
||||
resultMsg = "Upload Success!"
|
||||
|
||||
// File
|
||||
fileInfo := info.File{Name: filename,
|
||||
@@ -161,11 +174,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
id := bson.NewObjectId();
|
||||
fileInfo.FileId = id
|
||||
fileId = id.Hex()
|
||||
if(from == "logo") {
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||
}
|
||||
|
||||
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
|
||||
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
|
||||
resultMsg = c.Message(resultMsg)
|
||||
|
||||
fileInfo.Path = ""; // 不要返回
|
||||
re.Item = fileInfo
|
||||
@@ -190,61 +204,13 @@ func (c File) DeleteImage(fileId string) revel.Result {
|
||||
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// update image uploader to leaui image,
|
||||
// scan all user's images and insert into db
|
||||
func (c File) UpgradeLeauiImage() revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
if ok, _ := revel.Config.Bool("upgradeLeauiImage"); !ok {
|
||||
re.Msg = "Not allowed"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
uploadPath := revel.BasePath + "/public/upload";
|
||||
userIds := ListDir(uploadPath)
|
||||
if userIds == nil {
|
||||
re.Msg = "no user"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
msg := "";
|
||||
|
||||
for _, userId := range userIds {
|
||||
dirPath := uploadPath + "/" + userId + "/images"
|
||||
images := ListDir(dirPath)
|
||||
if images == nil {
|
||||
msg += userId + " no images "
|
||||
continue;
|
||||
}
|
||||
|
||||
hadImages := fileService.GetAllImageNamesMap(userId)
|
||||
|
||||
i := 0
|
||||
for _, filename := range images {
|
||||
if _, ok := hadImages[filename]; !ok {
|
||||
fileUrlPath := "/upload/" + userId + "/images/" + filename
|
||||
fileInfo := info.File{Name: filename,
|
||||
Title: filename,
|
||||
Path: fileUrlPath,
|
||||
Size: GetFilesize(dirPath + "/" + filename)}
|
||||
fileService.AddImage(fileInfo, "", userId)
|
||||
i++
|
||||
}
|
||||
}
|
||||
msg += userId + ": " + strconv.Itoa(len(images)) + " -- " + strconv.Itoa(i) + " images "
|
||||
}
|
||||
|
||||
re.Msg = msg
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//-----------
|
||||
|
||||
// 输出image
|
||||
// 权限判断
|
||||
func (c File) OutputImage(noteId, fileId string) revel.Result {
|
||||
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
|
||||
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
|
||||
sessionId := c.Session.Id()
|
||||
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
|
||||
if path == "" {
|
||||
return c.RenderText("")
|
||||
}
|
||||
@@ -254,15 +220,15 @@ func (c File) OutputImage(noteId, fileId string) revel.Result {
|
||||
}
|
||||
|
||||
// 协作时复制图片到owner
|
||||
// 需要计算对方大小
|
||||
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 复制外网的图片, 成公共图片 放在/upload下
|
||||
// 都要好好的计算大小
|
||||
func (c File) CopyHttpImage(src string) revel.Result {
|
||||
re := info.NewRe()
|
||||
fileUrlPath := "upload/" + c.GetUserId() + "/images"
|
||||
@@ -289,29 +255,7 @@ func (c File) CopyHttpImage(src string) revel.Result {
|
||||
|
||||
re.Id = id.Hex()
|
||||
re.Item = fileInfo.Path
|
||||
re.Ok = fileService.AddImage(fileInfo, "", c.GetUserId())
|
||||
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//------------
|
||||
// 过时 已弃用!
|
||||
func (c File) UploadImage(renderHtml string) revel.Result {
|
||||
if renderHtml == "" {
|
||||
renderHtml = "file/image.html"
|
||||
}
|
||||
|
||||
re := c.uploadImage("", "");
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
|
||||
return c.RenderTemplate(renderHtml)
|
||||
}
|
||||
|
||||
// 已弃用
|
||||
func (c File) UploadImageJson(from, noteId string) revel.Result {
|
||||
re := c.uploadImage(from, "");
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -12,8 +12,16 @@ type Index struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
func (c Index) Default() revel.Result {
|
||||
if configService.HomePageIsAdminsBlog(){
|
||||
blog := Blog{c.BaseController}
|
||||
return blog.Index(configService.GetAdminUsername());
|
||||
}
|
||||
return c.Index()
|
||||
}
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Index) Index() revel.Result {
|
||||
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "leanote"
|
||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// 首页
|
||||
type Mobile struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Mobile) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
userInfo := c.GetUserInfo()
|
||||
userId := userInfo.UserId.Hex()
|
||||
|
||||
// 没有登录
|
||||
if userId == "" {
|
||||
return c.RenderTemplate("mobile/login.html")
|
||||
}
|
||||
|
||||
/*
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||
*/
|
||||
|
||||
return c.RenderTemplate("mobile/angular.html");
|
||||
}
|
||||
|
||||
func (c Mobile) Logout() revel.Result {
|
||||
c.ClearSession()
|
||||
return c.RenderTemplate("mobile/login.html");
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"os/exec"
|
||||
// "time"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
@@ -21,9 +22,8 @@ type Note struct {
|
||||
// 笔记首页, 判断是否已登录
|
||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||
// 否则, 转向登录页面
|
||||
func (c Note) Index() revel.Result {
|
||||
func (c Note) Index(noteId string) revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
userInfo := c.GetUserInfo()
|
||||
|
||||
userId := userInfo.UserId.Hex()
|
||||
@@ -34,7 +34,7 @@ func (c Note) Index() revel.Result {
|
||||
}
|
||||
|
||||
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
||||
|
||||
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
@@ -42,29 +42,90 @@ func (c Note) Index() revel.Result {
|
||||
// 还需要按时间排序(DESC)得到notes
|
||||
notes := []info.Note{}
|
||||
noteContent := info.NoteContent{}
|
||||
|
||||
if len(notebooks) > 0 {
|
||||
// _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||
// 变成最新
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
if len(notes) > 0 {
|
||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
||||
// noteId是否存在
|
||||
// 是否传入了正确的noteId
|
||||
hasRightNoteId := false
|
||||
if IsObjectId(noteId) {
|
||||
note := noteService.GetNoteById(noteId)
|
||||
var noteOwner = note.UserId.Hex()
|
||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||
|
||||
if note.NoteId != "" {
|
||||
hasRightNoteId = true
|
||||
c.RenderArgs["curNoteId"] = noteId
|
||||
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
||||
|
||||
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
|
||||
if noteOwner != c.GetUserId() {
|
||||
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
|
||||
// 不要获取notebook下的笔记
|
||||
// 在前端下发请求
|
||||
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
|
||||
c.RenderArgs["curSharedUserId"] = noteOwner;
|
||||
// 没有读写权限
|
||||
} else {
|
||||
hasRightNoteId = false
|
||||
}
|
||||
} else {
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), note.NotebookId.Hex(), false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
|
||||
// 如果指定了某笔记, 则该笔记放在首位
|
||||
lenNotes := len(notes)
|
||||
if lenNotes > 1 {
|
||||
notes2 := make([]info.Note, len(notes))
|
||||
notes2[0] = note
|
||||
i := 1
|
||||
for _, note := range notes {
|
||||
if note.NoteId.Hex() != noteId {
|
||||
if i == lenNotes { // 防止越界
|
||||
break;
|
||||
}
|
||||
notes2[i] = note
|
||||
i++
|
||||
}
|
||||
}
|
||||
notes = notes2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 得到最近的笔记
|
||||
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
c.RenderArgs["latestNotes"] = latestNotes
|
||||
}
|
||||
|
||||
// 没有传入笔记
|
||||
// 那么得到最新笔记
|
||||
if !hasRightNoteId {
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
if len(notes) > 0 {
|
||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
||||
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当然, 还需要得到第一个notes的content
|
||||
//...
|
||||
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||
|
||||
c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
||||
c.RenderArgs["notebooks"] = notebooks
|
||||
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
|
||||
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
|
||||
|
||||
c.RenderArgs["notes"] = c.Json(notes)
|
||||
c.RenderArgs["noteContentJson"] = c.Json(noteContent)
|
||||
c.RenderArgs["notes"] = notes
|
||||
c.RenderArgs["noteContentJson"] = noteContent
|
||||
c.RenderArgs["noteContent"] = noteContent.Content
|
||||
|
||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||
c.RenderArgs["tags"] = tagService.GetTags(c.GetUserId())
|
||||
|
||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||
|
||||
|
||||
// return c.RenderTemplate("note/note.html")
|
||||
|
||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||
return c.RenderTemplate("note/note-dev.html")
|
||||
@@ -121,7 +182,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
// 新添加note
|
||||
if noteOrContent.IsNew {
|
||||
userId := c.GetObjectUserId();
|
||||
myUserId := userId
|
||||
// myUserId := userId
|
||||
// 为共享新建?
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
@@ -143,7 +204,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract};
|
||||
|
||||
note = noteService.AddNoteAndContent(note, noteContent, myUserId)
|
||||
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||
return c.RenderJson(note)
|
||||
}
|
||||
|
||||
@@ -296,7 +357,7 @@ func (c Note) Html2Image(noteId string) revel.Result {
|
||||
appKey, _ := revel.Config.String("app.secret")
|
||||
cookieDomain, _ := revel.Config.String("cookie.domain")
|
||||
// 生成之
|
||||
url := siteUrl + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
||||
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 == "" {
|
||||
@@ -350,4 +411,10 @@ func (c Note) Html2Image(noteId string) revel.Result {
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 设置/取消Blog; 置顶
|
||||
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
@@ -68,4 +68,10 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
|
||||
json.Unmarshal([]byte(data), &info)
|
||||
|
||||
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
||||
}
|
||||
|
||||
// 设置notebook <-> blog
|
||||
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
103
app/controllers/PreviewController.go
Normal file
103
app/controllers/PreviewController.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "strings"
|
||||
// "time"
|
||||
// "encoding/json"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/lea/blog"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
)
|
||||
|
||||
type Preview struct {
|
||||
Blog
|
||||
}
|
||||
|
||||
// 得到要预览的主题绝对路径
|
||||
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
||||
if themeId != "" {
|
||||
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
|
||||
} else {
|
||||
themeId = c.Session["themeId"] // 直接从session中获取
|
||||
}
|
||||
if themeId == "" {
|
||||
return false
|
||||
}
|
||||
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
||||
|
||||
c.RenderArgs["isPreview"] = true
|
||||
c.RenderArgs["themeId"] = themeId
|
||||
c.RenderArgs["themeInfoPreview"] = theme.Info
|
||||
c.RenderArgs["themePath"] = theme.Path
|
||||
if theme.Path == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath(themeId) {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Index(c.GetUserId())
|
||||
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||
}
|
||||
|
||||
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Tag(c.GetUserId(), tag)
|
||||
}
|
||||
func (c Preview) Tags(userIdOrEmail string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Tags(c.GetUserId())
|
||||
// if tag == "" {
|
||||
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
// }
|
||||
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
|
||||
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Cate(userIdOrEmail, notebookId)
|
||||
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Post(userIdOrEmail, noteId)
|
||||
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Single(userIdOrEmail, singleId)
|
||||
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
||||
if !c.getPreviewThemeAbsolutePath("") {
|
||||
return c.E404()
|
||||
}
|
||||
return c.Blog.Search(c.GetUserId(), keywords)
|
||||
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||
}
|
||||
@@ -4,17 +4,20 @@ import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "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/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "time"
|
||||
)
|
||||
|
||||
type Share struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
const AttachToken = 2
|
||||
|
||||
// 添加共享note
|
||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
@@ -36,6 +39,8 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
||||
return c.RenderJson(status)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 添加共享notebook
|
||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
@@ -87,6 +92,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||
|
||||
c.RenderArgs["isNote"] = true
|
||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||
c.RenderArgs["title"] = note.Title
|
||||
@@ -99,6 +106,9 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
||||
|
||||
c.RenderArgs["isNote"] = false
|
||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||
c.RenderArgs["title"] = notebook.Title
|
||||
@@ -139,4 +149,105 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str
|
||||
// 删除fromUserId分享给我的所有note, notebook
|
||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
||||
}
|
||||
|
||||
//-------------
|
||||
// 用户组
|
||||
|
||||
|
||||
// 将笔记分享给分组
|
||||
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
// 删除
|
||||
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
// 更新, 也是一样, 先删后加
|
||||
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
|
||||
return c.AddShareNoteGroup(noteId, groupId, perm)
|
||||
}
|
||||
|
||||
|
||||
//------
|
||||
|
||||
// 将笔记分享给分组
|
||||
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
// 删除
|
||||
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
// 更新, 也是一样, 先删后加
|
||||
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||
}
|
||||
|
||||
//生成笔记分享密码及更新到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)
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type AdminBlog struct {
|
||||
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
|
||||
pageInfo, blogs := blogService.ListAllBlogs("", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["blogs"] = blogs
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
@@ -27,4 +27,4 @@ func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.SetRecommend(noteId, recommend);
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ func (c Admin) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
c.RenderArgs["countUser"] = userService.CountUser()
|
||||
c.RenderArgs["countNote"] = noteService.CountNote()
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog()
|
||||
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||
|
||||
return c.RenderTemplate("admin/index.html");
|
||||
}
|
||||
@@ -30,6 +30,7 @@ func (c Admin) T(t string) revel.Result {
|
||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||
c.RenderArgs["version"] = configService.GetVersion()
|
||||
return c.RenderTemplate("admin/" + t + ".html")
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -110,10 +111,28 @@ func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c AdminSetting) HomePage(homePage string) revel.Result {
|
||||
re := info.NewRe()
|
||||
if homePage == "0" {
|
||||
homePage = ""
|
||||
}
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadImageSize", fmt.Sprintf("%v", uploadImageSize))
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package admin
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
@@ -15,4 +15,10 @@ type AdminUpgrade struct {
|
||||
func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
||||
upgradeService.UpgradeBlog()
|
||||
return nil;
|
||||
}
|
||||
|
||||
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package admin
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "time"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -13,10 +15,13 @@ type AdminUser struct {
|
||||
|
||||
// admin 主页
|
||||
var userPageSize = 10
|
||||
func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
||||
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
|
||||
pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
||||
if userPageSize == 0 {
|
||||
pageSize = userPageSize
|
||||
}
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
|
||||
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["users"] = users
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
@@ -26,3 +31,36 @@ func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
||||
func (c AdminUser) Add() revel.Result {
|
||||
return c.RenderTemplate("admin/user/add.html");
|
||||
}
|
||||
|
||||
// 添加
|
||||
func (c AdminUser) Register(email, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
|
||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
||||
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 修改帐户
|
||||
func (c AdminUser) ResetPwd(userId string) revel.Result {
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
return c.RenderTemplate("admin/user/reset_pwd.html");
|
||||
}
|
||||
|
||||
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||
return c.RenderRe(re);
|
||||
}
|
||||
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
@@ -28,7 +28,6 @@ var configService *service.ConfigService
|
||||
var emailService *service.EmailService
|
||||
var upgradeService *service.UpgradeService
|
||||
|
||||
var adminUsername = "admin"
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
@@ -83,7 +82,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
|
||||
// 验证是否已登录
|
||||
// 必须是管理员
|
||||
if username, ok := c.Session["Username"]; ok && username == adminUsername {
|
||||
if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
@@ -129,4 +128,4 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/lea/blog"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
@@ -19,53 +20,58 @@ var blogService *service.BlogService
|
||||
var tagService *service.TagService
|
||||
var pwdService *service.PwdService
|
||||
var tokenService *service.TokenService
|
||||
var suggestionService *service.SuggestionService
|
||||
var albumService *service.AlbumService
|
||||
var noteImageService *service.NoteImageService
|
||||
var suggestionService *service.SuggestionService
|
||||
var albumService *service.AlbumService
|
||||
var noteImageService *service.NoteImageService
|
||||
var fileService *service.FileService
|
||||
var attachService *service.AttachService
|
||||
var configService *service.ConfigService
|
||||
var emailService *service.EmailService
|
||||
var sessionService *service.SessionService
|
||||
var themeService *service.ThemeService
|
||||
|
||||
var pageSize = 1000
|
||||
var defaultSortField = "UpdatedTime"
|
||||
var leanoteUserId = "admin" // 不能更改
|
||||
var siteUrl = "http://leanote.com"
|
||||
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Note": map[string]bool{"ToImage": true},
|
||||
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"Cate": true,
|
||||
"Search": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"Cate": true,
|
||||
"ListCateLatest": true,
|
||||
"Search": true,
|
||||
"GetLikeAndComments": true,
|
||||
"IncReadNum": true,
|
||||
"ListComments": true,
|
||||
},
|
||||
"IncReadNum": true,
|
||||
"ListComments": true,
|
||||
"Single": true,
|
||||
"Archive": true,
|
||||
"Tags": true,
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
"ActiveEmail":true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"ActiveEmail": true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||
}
|
||||
|
||||
func needValidate(controller, method string) bool {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
@@ -76,31 +82,31 @@ func needValidate(controller, method string) bool {
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
// 全部变成首字大写
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
|
||||
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// 验证是否已登录
|
||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
|
||||
// 没有登录, 判断是否是ajax操作
|
||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
re := info.NewRe()
|
||||
re.Msg = "NOTLOGIN"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
@@ -118,7 +124,7 @@ func InitService() {
|
||||
tokenService = service.TokenS
|
||||
noteImageService = service.NoteImageS
|
||||
fileService = service.FileS
|
||||
albumService= service.AlbumS
|
||||
albumService = service.AlbumS
|
||||
attachService = service.AttachS
|
||||
pwdService = service.PwdS
|
||||
suggestionService = service.SuggestionS
|
||||
@@ -126,6 +132,12 @@ func InitService() {
|
||||
configService = service.ConfigS
|
||||
emailService = service.EmailS
|
||||
sessionService = service.SessionS
|
||||
themeService = service.ThemeS
|
||||
}
|
||||
|
||||
// 初始化博客模板
|
||||
// 博客模板不由revel的
|
||||
func initBlogTemplate() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -137,10 +149,11 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||
|
||||
|
||||
revel.OnAppStart(func() {
|
||||
siteUrl, _ = revel.Config.String("site.url")
|
||||
// 博客初始化模板
|
||||
blog.Init()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
59
app/controllers/member/MemberBaseController.go
Normal file
59
app/controllers/member/MemberBaseController.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
// "github.com/revel/revel"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// "encoding/json"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 公用Controller, 其它Controller继承它
|
||||
type MemberBaseController struct {
|
||||
controllers.BaseController // 不能用*BaseController
|
||||
}
|
||||
|
||||
// 得到sorterField 和 isAsc
|
||||
// okSorter = ['email', 'username']
|
||||
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||
sorter := ""
|
||||
c.Params.Bind(&sorter, "sorter")
|
||||
if sorter == "" {
|
||||
return sorterField, isAsc;
|
||||
}
|
||||
|
||||
// sorter形式 email-up, email-down
|
||||
s2 := strings.Split(sorter, "-")
|
||||
if len(s2) != 2 {
|
||||
return sorterField, isAsc;
|
||||
}
|
||||
|
||||
// 必须是可用的sorter
|
||||
if okSorter != nil && len(okSorter) > 0 {
|
||||
if !InArray(okSorter, s2[0]) {
|
||||
return sorterField, isAsc;
|
||||
}
|
||||
}
|
||||
|
||||
sorterField = strings.Title(s2[0])
|
||||
if s2[1] == "up" {
|
||||
isAsc = true
|
||||
} else {
|
||||
isAsc = false
|
||||
}
|
||||
c.RenderArgs["sorter"] = sorter
|
||||
return sorterField, isAsc;
|
||||
}
|
||||
|
||||
func (c MemberBaseController) updateConfig(keys []string) {
|
||||
userId := c.GetUserId()
|
||||
for _, key := range keys {
|
||||
v := c.Params.Values.Get(key)
|
||||
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||
}
|
||||
}
|
||||
526
app/controllers/member/MemberBlogController.go
Normal file
526
app/controllers/member/MemberBlogController.go
Normal file
@@ -0,0 +1,526 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
// "github.com/leanote/leanote/app/lea/blog"
|
||||
)
|
||||
|
||||
// 博客管理
|
||||
|
||||
type MemberBlog struct {
|
||||
MemberBaseController
|
||||
}
|
||||
|
||||
func (c MemberBlog) common() info.UserBlog {
|
||||
userId := c.GetUserId()
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
// 得到博客设置信息
|
||||
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
||||
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
c.RenderArgs["userBlog"] = userBlog
|
||||
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
return userBlog
|
||||
}
|
||||
|
||||
// 得到sorterField 和 isAsc
|
||||
// okSorter = ['email', 'username']
|
||||
func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool) {
|
||||
sorter := ""
|
||||
c.Params.Bind(&sorter, "sorter")
|
||||
if sorter == "" {
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
// sorter形式 email-up, email-down
|
||||
s2 := strings.Split(sorter, "-")
|
||||
if len(s2) != 2 {
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
// 必须是可用的sorter
|
||||
if okSorter != nil && len(okSorter) > 0 {
|
||||
if !InArray(okSorter, s2[0]) {
|
||||
return sorterField, isAsc
|
||||
}
|
||||
}
|
||||
|
||||
sorterField = strings.Title(s2[0])
|
||||
if s2[1] == "up" {
|
||||
isAsc = true
|
||||
} else {
|
||||
isAsc = false
|
||||
}
|
||||
c.RenderArgs["sorter"] = sorter
|
||||
return sorterField, isAsc
|
||||
}
|
||||
|
||||
// 博客列表
|
||||
var userPageSize = 15
|
||||
|
||||
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
||||
userId := c.GetUserId()
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
c.RenderArgs["title"] = "Posts"
|
||||
pageNumber := c.GetPage()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
|
||||
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
||||
c.RenderArgs["pageInfo"] = pageInfo
|
||||
c.RenderArgs["blogs"] = blogs
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
|
||||
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
|
||||
c.RenderArgs["userAndBlog"] = userAndBlog
|
||||
|
||||
return c.RenderTemplate("member/blog/list.html")
|
||||
}
|
||||
|
||||
// 修改笔记的urlTitle
|
||||
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 修改笔记的urlTitle
|
||||
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
||||
c.RenderArgs["title"] = "Update Post Abstract"
|
||||
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
|
||||
if !note.Note.IsBlog {
|
||||
return c.E404()
|
||||
}
|
||||
c.RenderArgs["note"] = note
|
||||
c.RenderArgs["noteId"] = noteId
|
||||
return c.RenderTemplate("member/blog/update_abstract.html")
|
||||
}
|
||||
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
|
||||
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 基本信息设置
|
||||
func (c MemberBlog) Base() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Blog Base Info"
|
||||
return c.RenderTemplate("member/blog/base.html")
|
||||
}
|
||||
func (c MemberBlog) Comment() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Comment"
|
||||
return c.RenderTemplate("member/blog/comment.html")
|
||||
}
|
||||
|
||||
func (c MemberBlog) Paging() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Paging"
|
||||
return c.RenderTemplate("member/blog/paging.html")
|
||||
}
|
||||
|
||||
func (c MemberBlog) Cate() revel.Result {
|
||||
userBlog := c.common()
|
||||
c.RenderArgs["title"] = "Cate"
|
||||
|
||||
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
||||
notebooksMap := map[string]info.Notebook{}
|
||||
for _, each := range notebooks {
|
||||
notebooksMap[each.NotebookId.Hex()] = each
|
||||
}
|
||||
|
||||
var i = 0
|
||||
notebooks2 := make([]info.Notebook, len(notebooks))
|
||||
|
||||
// 先要保证已有的是正确的排序
|
||||
cateIds := userBlog.CateIds
|
||||
has := map[string]bool{} // cateIds中有的
|
||||
if cateIds != nil && len(cateIds) > 0 {
|
||||
for _, cateId := range cateIds {
|
||||
if n, ok := notebooksMap[cateId]; ok {
|
||||
notebooks2[i] = n
|
||||
i++
|
||||
has[cateId] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// 之后
|
||||
for _, each := range notebooks {
|
||||
id := each.NotebookId.Hex()
|
||||
if !has[id] {
|
||||
notebooks2[i] = each
|
||||
i++
|
||||
}
|
||||
}
|
||||
c.RenderArgs["notebooks"] = notebooks2
|
||||
|
||||
return c.RenderTemplate("member/blog/cate.html")
|
||||
}
|
||||
|
||||
// 修改分类排序
|
||||
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 保存之, 包含增加与保存
|
||||
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Add Single"
|
||||
c.RenderArgs["singleId"] = singleId
|
||||
if singleId != "" {
|
||||
c.RenderArgs["title"] = "Update Single"
|
||||
c.RenderArgs["single"] = blogService.GetSingle(singleId)
|
||||
}
|
||||
return c.RenderTemplate("member/blog/add_single.html")
|
||||
}
|
||||
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 修改页面标题
|
||||
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) Single() revel.Result {
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Cate"
|
||||
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
||||
|
||||
return c.RenderTemplate("member/blog/single.html")
|
||||
}
|
||||
|
||||
// 主题
|
||||
func (c MemberBlog) Theme() revel.Result {
|
||||
c.common()
|
||||
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
|
||||
c.RenderArgs["activeTheme"] = activeTheme
|
||||
c.RenderArgs["otherThemes"] = otherThemes
|
||||
|
||||
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
|
||||
|
||||
c.RenderArgs["title"] = "Theme"
|
||||
return c.RenderTemplate("member/blog/theme.html")
|
||||
}
|
||||
|
||||
// 编辑主题
|
||||
var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"}
|
||||
|
||||
func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
||||
// 查看用户是否有该theme, 若没有则复制default之
|
||||
// 得到主题的文件列表
|
||||
userBlog := blogService.GetUserBlog(c.GetUserId())
|
||||
if themeId == "" {
|
||||
_, themeId = themeService.NewThemeForFirst(userBlog)
|
||||
return c.Redirect("/member/blog/updateTheme?themeId=" + themeId)
|
||||
}
|
||||
|
||||
c.common()
|
||||
c.RenderArgs["title"] = "Upate Theme"
|
||||
c.RenderArgs["isNew"] = isNew
|
||||
|
||||
// 先复制之
|
||||
c.RenderArgs["themeId"] = themeId
|
||||
|
||||
// 得到脚本目录
|
||||
userId := c.GetUserId()
|
||||
|
||||
theme := themeService.GetTheme(userId, themeId)
|
||||
if theme.ThemeId == "" {
|
||||
return c.E404()
|
||||
}
|
||||
c.RenderArgs["theme"] = theme
|
||||
|
||||
path := revel.BasePath + "/" + theme.Path
|
||||
|
||||
tpls := ListDir(path)
|
||||
myTpls := make([]string, len(baseTpls))
|
||||
tplMap := map[string]bool{}
|
||||
for i, t := range baseTpls {
|
||||
myTpls[i] = t
|
||||
tplMap[t] = true
|
||||
}
|
||||
// 得到没有的tpls
|
||||
for _, t := range tpls {
|
||||
if t == "images" {
|
||||
continue
|
||||
}
|
||||
if !tplMap[t] {
|
||||
myTpls = append(myTpls, t)
|
||||
}
|
||||
}
|
||||
|
||||
c.RenderArgs["myTpls"] = myTpls
|
||||
|
||||
return c.RenderTemplate("member/blog/update_theme.html")
|
||||
}
|
||||
|
||||
// 得到文件内容
|
||||
func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = true
|
||||
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
userId := c.GetUserId()
|
||||
path := themeService.GetThemeAbsolutePath(userId, themeId) + "/images"
|
||||
os.MkdirAll(path, 0755)
|
||||
images := ListDir(path)
|
||||
re.List = images
|
||||
re.Ok = true
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
|
||||
re := info.NewRe()
|
||||
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
|
||||
re.Ok = DeleteFile(path)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 上传主题图片
|
||||
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
|
||||
re := c.uploadImage(themeId)
|
||||
c.RenderArgs["fileUrlPath"] = re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
return c.RenderTemplate("file/blog_logo.html")
|
||||
}
|
||||
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
||||
var fileId = ""
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultMsg = "内部错误" // 错误信息
|
||||
var Ok = false
|
||||
|
||||
defer func() {
|
||||
re.Id = fileId // 只是id, 没有其它信息
|
||||
re.Code = resultCode
|
||||
re.Msg = resultMsg
|
||||
re.Ok = Ok
|
||||
}()
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images"
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
|
||||
var ext string
|
||||
|
||||
_, ext = SplitFilename(filename)
|
||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
||||
resultMsg = "不是图片"
|
||||
return re
|
||||
}
|
||||
|
||||
filename = filename
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
return re
|
||||
}
|
||||
|
||||
// > 2M?
|
||||
if len(data) > 5*1024*1024 {
|
||||
resultCode = 0
|
||||
resultMsg = "图片大于2M"
|
||||
return re
|
||||
}
|
||||
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
return re
|
||||
}
|
||||
TransToGif(toPath, 0, true)
|
||||
resultCode = 1
|
||||
resultMsg = "上传成功!"
|
||||
|
||||
return re
|
||||
}
|
||||
|
||||
//
|
||||
// 使用主题
|
||||
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 删除主题
|
||||
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 管理员公开主题
|
||||
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 导出
|
||||
func (c MemberBlog) ExportTheme(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
var path string
|
||||
re.Ok, path = themeService.ExportTheme(c.GetUserId(), themeId)
|
||||
if !re.Ok {
|
||||
return c.RenderText("error...")
|
||||
}
|
||||
fw, err := os.Open(path)
|
||||
if err != nil {
|
||||
return c.RenderText("error")
|
||||
}
|
||||
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
|
||||
}
|
||||
|
||||
// 导入主题
|
||||
func (c MemberBlog) ImportTheme() revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
re.Msg = fmt.Sprintf("%v", err)
|
||||
return c.RenderJson(re)
|
||||
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
userId := c.GetUserId()
|
||||
dir := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
re.Msg = fmt.Sprintf("%v", err)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
|
||||
var ext string
|
||||
_, ext = SplitFilename(filename)
|
||||
if ext != ".zip" {
|
||||
re.Msg = "请上传zip文件"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
filename = filename
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// > 10M?
|
||||
if len(data) > 10*1024*1024 {
|
||||
re.Msg = "文件大于10M"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
toPath := dir + "/" + filename
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
re.Msg = fmt.Sprintf("%v", err)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 上传好后, 增加之
|
||||
re.Ok, re.Msg = themeService.ImportTheme(c.GetUserId(), toPath)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 安装
|
||||
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 新建主题
|
||||
func (c MemberBlog) NewTheme() revel.Result {
|
||||
_, themeId := themeService.NewTheme(c.GetUserId())
|
||||
return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId)
|
||||
}
|
||||
|
||||
//-----------
|
||||
//
|
||||
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
58
app/controllers/member/MemberGroupController.go
Normal file
58
app/controllers/member/MemberGroupController.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// 分组管理
|
||||
type MemberGroup struct {
|
||||
MemberBaseController
|
||||
}
|
||||
|
||||
// 首页, 显示所有分组和用户
|
||||
func (c MemberGroup) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "My Group"
|
||||
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
|
||||
return c.RenderTemplate("member/group/index.html");
|
||||
}
|
||||
|
||||
// 添加分组
|
||||
func (c MemberGroup) AddGroup(title string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = groupService.DeleteGroup(c.GetUserId(), groupId)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
// 添加用户
|
||||
func (c MemberGroup) AddUser(groupId, email string) revel.Result {
|
||||
re := info.NewRe()
|
||||
userInfo := userService.GetUserInfoByAny(email)
|
||||
if userInfo.UserId == "" {
|
||||
re.Msg = "userNotExists"
|
||||
} else {
|
||||
re.Ok, re.Msg = groupService.AddUser(c.GetUserId(), groupId, userInfo.UserId.Hex())
|
||||
re.Item = userInfo
|
||||
}
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
|
||||
func (c MemberGroup) DeleteUser(groupId, userId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = groupService.DeleteUser(c.GetUserId(), groupId, userId)
|
||||
return c.RenderRe(re)
|
||||
}
|
||||
37
app/controllers/member/MemberIndexController.go
Normal file
37
app/controllers/member/MemberIndexController.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
|
||||
type MemberIndex struct {
|
||||
MemberBaseController
|
||||
}
|
||||
|
||||
// admin 主页
|
||||
func (c MemberIndex) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "Leanote Member Center"
|
||||
|
||||
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
||||
|
||||
c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("member/index.html");
|
||||
}
|
||||
|
||||
// 模板
|
||||
func (c MemberIndex) T(t string) revel.Result {
|
||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||
return c.RenderTemplate("admin/" + t + ".html")
|
||||
}
|
||||
|
||||
func (c MemberIndex) GetView(view string) revel.Result {
|
||||
return c.RenderTemplate("admin/" + view);
|
||||
}
|
||||
46
app/controllers/member/MemberUserController.go
Normal file
46
app/controllers/member/MemberUserController.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// 帐户信息
|
||||
|
||||
type MemberUser struct {
|
||||
MemberBaseController
|
||||
}
|
||||
|
||||
func (c MemberUser) Username() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Username"
|
||||
return c.RenderTemplate("member/user/username.html");
|
||||
}
|
||||
|
||||
func (c MemberUser) Email() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Email"
|
||||
return c.RenderTemplate("member/user/email.html");
|
||||
}
|
||||
|
||||
func (c MemberUser) Password() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Password"
|
||||
return c.RenderTemplate("member/user/password.html");
|
||||
}
|
||||
|
||||
func (c MemberUser) Avatar() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Avatar"
|
||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||
return c.RenderTemplate("member/user/avatar.html");
|
||||
}
|
||||
func (c MemberUser) AddAccount() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.SetLocale()
|
||||
c.RenderArgs["title"] = "Add Account"
|
||||
return c.RenderTemplate("member/user/add_account.html");
|
||||
}
|
||||
134
app/controllers/member/init.go
Normal file
134
app/controllers/member/init.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
var userService *service.UserService
|
||||
var groupService *service.GroupService
|
||||
var noteService *service.NoteService
|
||||
var trashService *service.TrashService
|
||||
var notebookService *service.NotebookService
|
||||
var noteContentHistoryService *service.NoteContentHistoryService
|
||||
var authService *service.AuthService
|
||||
var shareService *service.ShareService
|
||||
var blogService *service.BlogService
|
||||
var tagService *service.TagService
|
||||
var pwdService *service.PwdService
|
||||
var tokenService *service.TokenService
|
||||
var suggestionService *service.SuggestionService
|
||||
var albumService *service.AlbumService
|
||||
var noteImageService *service.NoteImageService
|
||||
var fileService *service.FileService
|
||||
var attachService *service.AttachService
|
||||
var configService *service.ConfigService
|
||||
var emailService *service.EmailService
|
||||
var upgradeService *service.UpgradeService
|
||||
var themeService *service.ThemeService
|
||||
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"SearchBlog": true,
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
"ActiveEmail":true,
|
||||
},
|
||||
"Oauth": map[string]bool{"GithubCallback": true},
|
||||
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||
}
|
||||
func needValidate(controller, method string) bool {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
// 在commonUrl里
|
||||
if _, ok2 := v[method]; ok2 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
// 全部变成首字大写
|
||||
/*
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// 验证是否已登录
|
||||
// 必须是管理员
|
||||
if _, ok := c.Session["Username"]; ok {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
// 没有登录, 判断是否是ajax操作
|
||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
re := info.NewRe()
|
||||
re.Msg = "NOTLOGIN"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
// 最外层init.go调用
|
||||
// 获取service, 单例
|
||||
func InitService() {
|
||||
notebookService = service.NotebookS
|
||||
noteService = service.NoteS
|
||||
noteContentHistoryService = service.NoteContentHistoryS
|
||||
trashService = service.TrashS
|
||||
shareService = service.ShareS
|
||||
userService = service.UserS
|
||||
groupService = service.GroupS
|
||||
tagService = service.TagS
|
||||
blogService = service.BlogS
|
||||
tokenService = service.TokenS
|
||||
noteImageService = service.NoteImageS
|
||||
fileService = service.FileS
|
||||
albumService= service.AlbumS
|
||||
attachService = service.AttachS
|
||||
pwdService = service.PwdS
|
||||
suggestionService = service.SuggestionS
|
||||
authService = service.AuthS
|
||||
configService = service.ConfigS
|
||||
emailService = service.EmailS
|
||||
upgradeService = service.UpgradeS
|
||||
themeService = service.ThemeS
|
||||
}
|
||||
|
||||
func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberGroup{})
|
||||
revel.OnAppStart(func() {
|
||||
})
|
||||
}
|
||||
2
app/controllers/member/个人中心.md
Normal file
2
app/controllers/member/个人中心.md
Normal file
@@ -0,0 +1,2 @@
|
||||
包括基本信息设置
|
||||
博客设置
|
||||
@@ -2,9 +2,10 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// Init mgo and the common DAO
|
||||
@@ -23,9 +24,12 @@ var ShareNotebooks *mgo.Collection
|
||||
var HasShareNotes *mgo.Collection
|
||||
var Blogs *mgo.Collection
|
||||
var Users *mgo.Collection
|
||||
var Groups *mgo.Collection
|
||||
var GroupUsers *mgo.Collection
|
||||
|
||||
var Tags *mgo.Collection
|
||||
var TagNotes *mgo.Collection
|
||||
//var TagNotes *mgo.Collection
|
||||
var TagCounts *mgo.Collection
|
||||
|
||||
var UserBlogs *mgo.Collection
|
||||
|
||||
@@ -46,17 +50,22 @@ var EmailLogs *mgo.Collection
|
||||
var BlogLikes *mgo.Collection
|
||||
var BlogComments *mgo.Collection
|
||||
var Reports *mgo.Collection
|
||||
var BlogSingles *mgo.Collection
|
||||
var Themes *mgo.Collection
|
||||
|
||||
// session
|
||||
var Sessions *mgo.Collection
|
||||
|
||||
// 初始化时连接数据库
|
||||
func Init() {
|
||||
var url string
|
||||
var ok bool
|
||||
config := revel.Config;
|
||||
url, ok = config.String("db.url")
|
||||
dbname, _ := config.String("db.dbname")
|
||||
func Init(url, dbname string) {
|
||||
ok := true
|
||||
config := revel.Config
|
||||
if url == "" {
|
||||
url, ok = config.String("db.url")
|
||||
}
|
||||
if dbname == "" {
|
||||
dbname, _ = config.String("db.dbname")
|
||||
}
|
||||
if !ok {
|
||||
host, _ := revel.Config.String("db.host")
|
||||
port, _ := revel.Config.String("db.port")
|
||||
@@ -66,9 +75,10 @@ func Init() {
|
||||
if username == "" || password == "" {
|
||||
usernameAndPassword = ""
|
||||
}
|
||||
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
||||
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
||||
}
|
||||
|
||||
Log(url)
|
||||
|
||||
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
||||
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||
var err error
|
||||
@@ -82,55 +92,61 @@ func Init() {
|
||||
|
||||
// notebook
|
||||
Notebooks = Session.DB(dbname).C("notebooks")
|
||||
|
||||
|
||||
// notes
|
||||
Notes = Session.DB(dbname).C("notes")
|
||||
|
||||
|
||||
// noteContents
|
||||
NoteContents = Session.DB(dbname).C("note_contents")
|
||||
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
||||
|
||||
|
||||
// share
|
||||
ShareNotes = Session.DB(dbname).C("share_notes")
|
||||
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
||||
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
||||
|
||||
|
||||
// user
|
||||
Users = Session.DB(dbname).C("users")
|
||||
|
||||
// group
|
||||
Groups = Session.DB(dbname).C("groups")
|
||||
GroupUsers = Session.DB(dbname).C("group_users")
|
||||
|
||||
// blog
|
||||
Blogs = Session.DB(dbname).C("blogs")
|
||||
|
||||
|
||||
// tag
|
||||
Tags = Session.DB(dbname).C("tags")
|
||||
TagNotes = Session.DB(dbname).C("tag_notes")
|
||||
|
||||
// TagNotes = Session.DB(dbname).C("tag_notes")
|
||||
TagCounts = Session.DB(dbname).C("tag_count")
|
||||
|
||||
// blog
|
||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||
|
||||
BlogSingles = Session.DB(dbname).C("blog_singles")
|
||||
Themes = Session.DB(dbname).C("themes")
|
||||
|
||||
// find password
|
||||
Tokens = Session.DB(dbname).C("tokens")
|
||||
|
||||
|
||||
// Suggestion
|
||||
Suggestions = Session.DB(dbname).C("suggestions")
|
||||
|
||||
|
||||
// Album & file
|
||||
Albums = Session.DB(dbname).C("albums")
|
||||
Files = Session.DB(dbname).C("files")
|
||||
Attachs = Session.DB(dbname).C("attachs")
|
||||
|
||||
|
||||
NoteImages = Session.DB(dbname).C("note_images")
|
||||
|
||||
|
||||
Configs = Session.DB(dbname).C("configs")
|
||||
EmailLogs = Session.DB(dbname).C("email_logs")
|
||||
|
||||
|
||||
// 社交
|
||||
BlogLikes = Session.DB(dbname).C("blog_likes")
|
||||
BlogComments = Session.DB(dbname).C("blog_comments")
|
||||
|
||||
|
||||
// 举报
|
||||
Reports = Session.DB(dbname).C("reports")
|
||||
|
||||
|
||||
// session
|
||||
Sessions = Session.DB(dbname).C("sessions")
|
||||
}
|
||||
@@ -174,22 +190,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId,
|
||||
return Err(err)
|
||||
}
|
||||
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||
}
|
||||
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
|
||||
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||
}
|
||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
//
|
||||
|
||||
//
|
||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||
return Err(err)
|
||||
}
|
||||
func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
// 查询条件和值
|
||||
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||
@@ -255,6 +278,7 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i
|
||||
}
|
||||
collection.Find(q).Select(selector).One(i)
|
||||
}
|
||||
|
||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||
selector := make(bson.M, len(fields))
|
||||
@@ -270,6 +294,11 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i
|
||||
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
||||
}
|
||||
|
||||
// 按field去重
|
||||
func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) {
|
||||
collection.Find(q).Distinct(field, i)
|
||||
}
|
||||
|
||||
//----------------------
|
||||
|
||||
func Count(collection *mgo.Collection, q interface{}) int {
|
||||
@@ -303,9 +332,9 @@ func Err(err error) bool {
|
||||
fmt.Println(err)
|
||||
// 删除时, 查找
|
||||
if err.Error() == "not found" {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
49
app/info/BlogCustom.go
Normal file
49
app/info/BlogCustom.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 仅仅为了博客的主题
|
||||
|
||||
type BlogInfoCustom struct {
|
||||
UserId string
|
||||
Username string
|
||||
UserLogo string
|
||||
Title string
|
||||
SubTitle string
|
||||
Logo string
|
||||
OpenComment bool
|
||||
CommentType string
|
||||
ThemeId string
|
||||
SubDomain string
|
||||
Domain string
|
||||
}
|
||||
|
||||
type Post struct {
|
||||
NoteId string
|
||||
Title string
|
||||
UrlTitle string
|
||||
ImgSrc string
|
||||
CreatedTime time.Time
|
||||
UpdatedTime time.Time
|
||||
PublicTime time.Time
|
||||
Desc string
|
||||
Abstract string
|
||||
Content string
|
||||
Tags []string
|
||||
CommentNum int
|
||||
ReadNum int
|
||||
LikeNum int
|
||||
IsMarkdown bool
|
||||
}
|
||||
// 归档
|
||||
type ArchiveMonth struct {
|
||||
Month int
|
||||
Posts []*Post
|
||||
}
|
||||
type Archive struct {
|
||||
Year int
|
||||
MonthAchives []ArchiveMonth
|
||||
Posts []*Post
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
type BlogItem struct {
|
||||
Note
|
||||
Abstract string
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
User User // 用户信息
|
||||
@@ -18,13 +19,13 @@ type UserBlogBase struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
// AboutMe string `AboutMe` // 关于我
|
||||
}
|
||||
|
||||
type UserBlogComment struct {
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
CommentType string `CommentType` // default 或 disqus
|
||||
DisqusId string `DisqusId`
|
||||
DisqusId string `DisqusId`
|
||||
}
|
||||
|
||||
type UserBlogStyle struct {
|
||||
@@ -38,18 +39,48 @@ type UserBlog struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
AboutMe string `AboutMe` // 关于我, 弃用
|
||||
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
|
||||
CommentType string `CommentType` // default 或 disqus
|
||||
DisqusId string `DisqusId`
|
||||
DisqusId string `DisqusId`
|
||||
|
||||
Style string `Style` // 风格
|
||||
Css string `Css` // 自定义css
|
||||
|
||||
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
|
||||
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
|
||||
|
||||
CateIds []string `CateIds,omitempty` // 分类Id, 排序好的
|
||||
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
|
||||
|
||||
PerPageSize int `PerPageSize,omitempty`
|
||||
SortField string `SortField` // 排序字段
|
||||
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
|
||||
|
||||
SubDomain string `SubDomain` // 二级域名
|
||||
Domain string `Domain` // 自定义域名
|
||||
|
||||
}
|
||||
|
||||
// 博客统计信息
|
||||
type BlogStat struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||
}
|
||||
|
||||
// 单页
|
||||
type BlogSingle struct {
|
||||
SingleId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `UserId`
|
||||
Title string `Title`
|
||||
UrlTitle string `UrlTitle` // 2014/11/11
|
||||
Content string `Content`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
}
|
||||
|
||||
//------------------------
|
||||
@@ -57,7 +88,7 @@ type UserBlog struct {
|
||||
|
||||
// 点赞记录
|
||||
type BlogLike struct {
|
||||
LikeId bson.ObjectId `bson:"_id"`
|
||||
LikeId bson.ObjectId `bson:"_id,omitempty"`
|
||||
NoteId bson.ObjectId `NoteId`
|
||||
UserId bson.ObjectId `UserId`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
@@ -65,7 +96,7 @@ type BlogLike struct {
|
||||
|
||||
// 评论
|
||||
type BlogComment struct {
|
||||
CommentId bson.ObjectId `bson:"_id"`
|
||||
CommentId bson.ObjectId `bson:"_id,omitempty"`
|
||||
NoteId bson.ObjectId `NoteId`
|
||||
|
||||
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
||||
@@ -84,3 +115,14 @@ type BlogCommentPublic struct {
|
||||
BlogComment
|
||||
IsILikeIt bool
|
||||
}
|
||||
|
||||
type BlogUrls struct {
|
||||
IndexUrl string
|
||||
CateUrl string
|
||||
SearchUrl string
|
||||
SingleUrl string
|
||||
PostUrl string
|
||||
ArchiveUrl string
|
||||
TagsUrl string
|
||||
TagPostsUrl string
|
||||
}
|
||||
|
||||
25
app/info/GroupInfo.go
Normal file
25
app/info/GroupInfo.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 分组
|
||||
type Group struct {
|
||||
GroupId bson.ObjectId `bson:"_id"` // 谁的
|
||||
UserId bson.ObjectId `UserId` // 所有者Id
|
||||
Title string `Title` // 标题
|
||||
UserCount int `UserCount` // 用户数
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
Users []User `Users,omitempty` // 分组下的用户, 不保存, 仅查看
|
||||
}
|
||||
|
||||
// 分组好友
|
||||
type GroupUser struct {
|
||||
GroupUserId bson.ObjectId `bson:"_id"` // 谁的
|
||||
GroupId bson.ObjectId `GroupId` // 分组
|
||||
UserId bson.ObjectId `UserId` // 用户
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
}
|
||||
@@ -20,9 +20,11 @@ type Note struct {
|
||||
|
||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||
|
||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||
UrlTitle string `UrlTitle,omitempty` // 博客的url标题, 为了更友好的url, 在UserId, UrlName下唯一
|
||||
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||
HasSelfDefined bool `HasSelfDefined` // 是否已经自定义博客图片, desc, abstract
|
||||
|
||||
// 2014/9/28 添加评论社交功能
|
||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||
@@ -35,9 +37,11 @@ type Note struct {
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
|
||||
SharePass int `SharePass` //分享笔记的密码
|
||||
}
|
||||
|
||||
// 内容
|
||||
|
||||
@@ -13,6 +13,7 @@ type Notebook struct {
|
||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
||||
Seq int `Seq` // 排序
|
||||
Title string `Title` // 标题
|
||||
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
||||
NumberNotes int `NumberNotes` // 笔记数
|
||||
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||
|
||||
@@ -10,10 +10,11 @@ type Session struct {
|
||||
Id bson.ObjectId `bson:"_id,omitempty"` // 没有意义
|
||||
|
||||
SessionId string `bson:"SessionId"` // SessionId
|
||||
|
||||
|
||||
LoginTimes int `LoginTimes` // 登录错误时间
|
||||
Captcha string `Captcha` // 验证码
|
||||
|
||||
Token string `Token` //attach token
|
||||
TokenTime time.Time `TokenTime` //token生成时间
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
|
||||
}
|
||||
|
||||
@@ -76,7 +76,9 @@ type SharingNotebookAndNotes struct {
|
||||
type ShareNotebook struct {
|
||||
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||
Seq int `bson:"Seq"` // 排序
|
||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||
@@ -134,7 +136,9 @@ type ShareNotebooksByUser struct {
|
||||
type ShareNote struct {
|
||||
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
@@ -5,15 +5,38 @@ import (
|
||||
)
|
||||
|
||||
// 这里主要是为了统计每个tag的note数目
|
||||
// 暂时没用
|
||||
/*
|
||||
type TagNote struct {
|
||||
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
Tag string `Title` // 标题
|
||||
NoteNum int `NoteNum` // note数目
|
||||
}
|
||||
*/
|
||||
|
||||
// 每个用户一条记录, 存储用户的所有tags
|
||||
type Tag struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Tags []string `Tags`
|
||||
}
|
||||
}
|
||||
|
||||
type TagCount struct {
|
||||
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `UserId` // 谁的
|
||||
Tag string `Tag`
|
||||
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||
Count int `Count` // 统计数量
|
||||
}
|
||||
/*
|
||||
type TagsCounts []TagCount
|
||||
func (this TagsCounts) Len() int {
|
||||
return len(this)
|
||||
}
|
||||
func (this TagsCounts) Less(i, j int) bool {
|
||||
return this[i].Count > this[j].Count
|
||||
}
|
||||
func (this TagsCounts) Swap(i, j int) {
|
||||
this[i], this[j] = this[j], this[i]
|
||||
}
|
||||
*/
|
||||
26
app/info/ThemeInfo.go
Normal file
26
app/info/ThemeInfo.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 主题, 每个用户有多个主题, 这里面有主题的配置信息
|
||||
// 模板, css, js, images, 都在路径Path下
|
||||
type Theme struct {
|
||||
ThemeId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `UserId`
|
||||
Name string `Name`
|
||||
Version string `Version`
|
||||
Author string `Author`
|
||||
AuthorUrl string `AuthorUrl`
|
||||
Path string `Path` // 文件夹路径
|
||||
Info map[string]interface{} `Info` // 所有信息
|
||||
IsActive bool `IsActive` // 是否在用
|
||||
|
||||
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
|
||||
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
}
|
||||
@@ -34,4 +34,47 @@ type User struct {
|
||||
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||
ThirdType int `ThirdType` // 第三方类型
|
||||
|
||||
// 用户的帐户类型
|
||||
|
||||
ImageNum int `bson:"ImageNum" json:"-"` // 图片数量
|
||||
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
|
||||
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
|
||||
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
|
||||
FromUserId bson.ObjectId `FromUserId,omitempty` // 邀请的用户
|
||||
|
||||
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||
// 阈值
|
||||
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||
}
|
||||
|
||||
type UserAccount struct {
|
||||
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||
// 阈值
|
||||
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||
}
|
||||
|
||||
// 用户与博客信息结合, 公开
|
||||
type UserAndBlog struct {
|
||||
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
Email string `Email` // 全是小写
|
||||
Username string `Username` // 不区分大小写, 全是小写
|
||||
Logo string `Logo`
|
||||
BlogTitle string `BlogTitle` // 博客标题
|
||||
BlogLogo string `BlogLogo` // 博客Logo
|
||||
BlogUrl string `BlogUrl` // 博客链接, 主页
|
||||
|
||||
BlogUrls // 各个页面
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type Page struct {
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
PerPageSize int
|
||||
Count int // 总记录数
|
||||
List interface{}
|
||||
}
|
||||
@@ -18,5 +19,5 @@ func NewPage(page, perPageSize, count int, list interface{}) Page {
|
||||
if count > 0 {
|
||||
totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
|
||||
}
|
||||
return Page{page, totalPage, count, list}
|
||||
}
|
||||
return Page{page, totalPage, perPageSize, count, list}
|
||||
}
|
||||
|
||||
82
app/init.go
82
app/init.go
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
"github.com/leanote/leanote/app/controllers/admin"
|
||||
"github.com/leanote/leanote/app/controllers/member"
|
||||
_ "github.com/leanote/leanote/app/lea/binder"
|
||||
"github.com/leanote/leanote/app/lea/session"
|
||||
"github.com/leanote/leanote/app/lea/memcache"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -56,6 +58,11 @@ func init() {
|
||||
i = i - 1;
|
||||
return i
|
||||
}
|
||||
// 增加或减少
|
||||
revel.TemplateFuncs["incr"] = func(n, i int) int {
|
||||
n = n + i;
|
||||
return n
|
||||
}
|
||||
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
||||
if arr == nil {
|
||||
return template.HTML("")
|
||||
@@ -72,13 +79,24 @@ func init() {
|
||||
}
|
||||
return str
|
||||
}
|
||||
revel.TemplateFuncs["decodeUrlValue"] = func(i string) string {
|
||||
v, _ := url.ParseQuery("a=" + i)
|
||||
return v.Get("a")
|
||||
}
|
||||
revel.TemplateFuncs["json"] = func(i interface{}) string {
|
||||
b, _ := json.Marshal(i)
|
||||
return string(b)
|
||||
}
|
||||
revel.TemplateFuncs["jsonJs"] = func(i interface{}) template.JS {
|
||||
b, _ := json.Marshal(i)
|
||||
return template.JS(string(b))
|
||||
}
|
||||
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML {
|
||||
return template.HTML(t.Format(format))
|
||||
}
|
||||
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
||||
sec, _ := strconv.Atoi(unixSec)
|
||||
t := time.Unix(int64(sec), 0)
|
||||
@@ -93,6 +111,7 @@ func init() {
|
||||
}
|
||||
|
||||
// tags
|
||||
// 2014/12/30 标签添加链接
|
||||
revel.TemplateFuncs["blogTags"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
@@ -100,18 +119,68 @@ func init() {
|
||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
|
||||
tagPostUrl, _ := renderArgs["tagPostsUrl"].(string)
|
||||
|
||||
for i, tag := range tags {
|
||||
str := revel.Message(locale, tag)
|
||||
var classes = "label"
|
||||
if strings.HasPrefix(str, "???") {
|
||||
str = tag
|
||||
}
|
||||
tagStr += str
|
||||
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
|
||||
classes += " label-" + tag
|
||||
} else {
|
||||
classes += " label-default"
|
||||
}
|
||||
|
||||
classes += " label-post"
|
||||
var url = tagPostUrl + "/" + url.QueryEscape(tag)
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
|
||||
if i != lenTags - 1 {
|
||||
tagStr += ","
|
||||
tagStr += " "
|
||||
}
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
|
||||
// lea++
|
||||
revel.TemplateFuncs["blogTagsLea"] = func(renderArgs map[string]interface{}, tags []string, isRecommend bool) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
}
|
||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
|
||||
tagPostUrl := "http://lea.leanote.com/"
|
||||
if isRecommend {
|
||||
tagPostUrl += "?tag=";
|
||||
} else {
|
||||
tagPostUrl += "latest?tag=";
|
||||
}
|
||||
|
||||
for i, tag := range tags {
|
||||
str := revel.Message(locale, tag)
|
||||
var classes = "label"
|
||||
if strings.HasPrefix(str, "???") {
|
||||
str = tag
|
||||
}
|
||||
if InArray([]string{"red", "blue", "yellow", "green"}, tag) {
|
||||
classes += " label-" + tag
|
||||
} else {
|
||||
classes += " label-default"
|
||||
}
|
||||
classes += " label-post"
|
||||
var url = tagPostUrl + url.QueryEscape(tag)
|
||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>";
|
||||
if i != lenTags - 1 {
|
||||
tagStr += " "
|
||||
}
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
|
||||
/*
|
||||
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
@@ -135,8 +204,6 @@ func init() {
|
||||
}
|
||||
*/
|
||||
revel.TemplateFuncs["li"] = func(a string) string {
|
||||
Log(a)
|
||||
Log("life==")
|
||||
return ""
|
||||
}
|
||||
// str连接
|
||||
@@ -248,6 +315,7 @@ func init() {
|
||||
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
||||
// http://play.golang.org/p/snygrVpQva
|
||||
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
||||
/*
|
||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||
switch a1.(type) {
|
||||
case string:
|
||||
@@ -273,6 +341,7 @@ func init() {
|
||||
}
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{range $i := N 1 10}}
|
||||
@@ -293,7 +362,7 @@ func init() {
|
||||
// init Email
|
||||
revel.OnAppStart(func() {
|
||||
// 数据库
|
||||
db.Init()
|
||||
db.Init("", "")
|
||||
// email配置
|
||||
InitEmail()
|
||||
InitVd()
|
||||
@@ -302,6 +371,7 @@ func init() {
|
||||
service.InitService()
|
||||
controllers.InitService()
|
||||
admin.InitService()
|
||||
member.InitService()
|
||||
service.ConfigS.InitGlobalConfigs()
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package lea
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/revel/revel"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Log(i interface{}) {
|
||||
@@ -12,4 +13,14 @@ func Log(i interface{}) {
|
||||
func LogJ(i interface{}) {
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
revel.INFO.Println(string(b))
|
||||
}
|
||||
}
|
||||
|
||||
// 为test用
|
||||
func L(i interface{}) {
|
||||
fmt.Println(i)
|
||||
}
|
||||
|
||||
func LJ(i interface{}) {
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
122
app/lea/File.go
122
app/lea/File.go
@@ -1,10 +1,11 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"os"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 分离文件名与扩展名(包含.)
|
||||
@@ -14,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) {
|
||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||
baseName = strings.TrimRight(filename, ext)
|
||||
ext = strings.ToLower(ext)
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// 转换文件的格式
|
||||
// toExt包含.
|
||||
func TransferExt(path string, toExt string) string {
|
||||
dir := filepath.Dir(path) + "/" // 文件路径
|
||||
name := filepath.Base(path) // 文件名 a.jpg
|
||||
dir := filepath.Dir(path) + "/" // 文件路径
|
||||
name := filepath.Base(path) // 文件名 a.jpg
|
||||
// 获取文件名与路径
|
||||
baseName, _ := SplitFilename(name)
|
||||
return dir + baseName + toExt
|
||||
@@ -38,7 +39,7 @@ func GetFilesize(path string) int64 {
|
||||
if err == nil {
|
||||
return fileinfo.Size()
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
// 清空dir下所有的文件和文件夹
|
||||
@@ -79,12 +80,103 @@ func CopyFile(srcName, dstName string) (written int64, err error) {
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
|
||||
func CopyDir(source string, dest string) (err error) {
|
||||
// get properties of source dir
|
||||
sourceinfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create dest dir
|
||||
|
||||
err = os.MkdirAll(dest, sourceinfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
directory, _ := os.Open(source)
|
||||
|
||||
objects, err := directory.Readdir(-1)
|
||||
|
||||
for _, obj := range objects {
|
||||
|
||||
sourcefilepointer := source + "/" + obj.Name()
|
||||
|
||||
destinationfilepointer := dest + "/" + obj.Name()
|
||||
|
||||
if obj.IsDir() {
|
||||
// create sub-directories - recursively
|
||||
err = CopyDir(sourcefilepointer, destinationfilepointer)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
// perform copy
|
||||
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteFile(path string) bool {
|
||||
err := os.Remove(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func IsDirExists(path string) bool {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return os.IsExist(err)
|
||||
}else{
|
||||
return fi.IsDir()
|
||||
}
|
||||
return false
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return os.IsExist(err)
|
||||
} else {
|
||||
return fi.IsDir()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 获得文件str内容
|
||||
func GetFileStrContent(path string) string {
|
||||
fileBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(fileBytes)
|
||||
}
|
||||
|
||||
func IsFileExist(filename string) bool {
|
||||
var exist = true
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
exist = false
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// 写入string内容
|
||||
func PutFileStrContent(path, content string) bool {
|
||||
var f *os.File
|
||||
var err1 error
|
||||
defer (func() {
|
||||
if f != nil {
|
||||
f.Close()
|
||||
}
|
||||
})()
|
||||
f, err1 = os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) //打开文件
|
||||
// Log(err1)
|
||||
// var n int
|
||||
_, err1 = io.WriteString(f, content) //写入文件(字符串)
|
||||
// Log(content)
|
||||
// Log(err1)
|
||||
// Log(n)
|
||||
// Log(path)
|
||||
|
||||
if err1 != nil {
|
||||
Log(err1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -27,6 +27,12 @@ var rulesStr = `{
|
||||
],
|
||||
"domain": [
|
||||
{"rule": "domain", "msg": "errorDomain"}
|
||||
],
|
||||
"perPageSize": [
|
||||
{"rule": "min", "data": "1", "msg": "errorPerPageSize"}
|
||||
],
|
||||
"sortField": [
|
||||
{"rule": "sortField", "msg": "errorSortField"}
|
||||
]
|
||||
}
|
||||
`
|
||||
@@ -49,6 +55,25 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||
ok = len(value) >= dataI
|
||||
return
|
||||
},
|
||||
"min": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
data := rule["data"]
|
||||
dataI, _ := strconv.Atoi(data)
|
||||
vI, _ := strconv.Atoi(value)
|
||||
ok = vI >= dataI
|
||||
return
|
||||
},
|
||||
|
||||
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
sortFields := []string{"PublicTime", "CreatedTime", "UpdatedTime", "Title"}
|
||||
ok = InArray(sortFields, value)
|
||||
return
|
||||
},
|
||||
|
||||
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||
if value == "" {
|
||||
|
||||
230
app/lea/archive/tar.go
Normal file
230
app/lea/archive/tar.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// main functions shows how to TarGz a directory/file and
|
||||
// UnTarGz a file
|
||||
// Gzip and tar from source directory or file to destination file
|
||||
// you need check file exist before you call this function
|
||||
|
||||
func main() {
|
||||
/*
|
||||
os.Mkdir("/home/ty4z2008/tar", 0777)
|
||||
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
|
||||
//targetfile,sourcefile
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
fmt.Println(w)
|
||||
|
||||
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
|
||||
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
|
||||
os.RemoveAll("/home/ty4z2008/tar")
|
||||
*/
|
||||
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
|
||||
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
func TarGz(srcDirPath string, destFilePath string) (ok bool) {
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
// Gzip writer
|
||||
gw := gzip.NewWriter(fw)
|
||||
defer gw.Close()
|
||||
|
||||
// Tar writer
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
tarGzFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with directories
|
||||
// if find files, handle them with tarGzFile
|
||||
// Every recurrence append the base path to the recPath
|
||||
// recPath is the path inside of tar.gz
|
||||
func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
|
||||
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with files
|
||||
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
// if last character of header name is '/' it also can be directory
|
||||
// but if you don't set Typeflag, error will occur when you untargz
|
||||
hdr.Name = recPath // + "/"
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Typeflag = tar.TypeDir
|
||||
// hdr.Size = 0
|
||||
//hdr.Mode = 0755 | c_ISDIR
|
||||
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
|
||||
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
|
||||
|
||||
// Write hander
|
||||
err := tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Create tar header
|
||||
hdr := new(tar.Header)
|
||||
hdr.Name = recPath
|
||||
// fmt.Println(hdr.Name)
|
||||
hdr.Size = fi.Size()
|
||||
hdr.Mode = int64(fi.Mode())
|
||||
hdr.ModTime = fi.ModTime()
|
||||
|
||||
// Write hander
|
||||
err = tw.WriteHeader(hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write file data
|
||||
_, err = io.Copy(tw, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ungzip and untar from source file to destination directory
|
||||
// you need check file exist before you call this function
|
||||
func UnTarGz(srcFilePath string, destDirPath string) {
|
||||
// fmt.Println("UnTarGzing " + srcFilePath + "...")
|
||||
// Create destination directory
|
||||
os.Mkdir(destDirPath, os.ModePerm)
|
||||
|
||||
fr, err := os.Open(srcFilePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Gzip reader
|
||||
gr, err := gzip.NewReader(fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gr.Close()
|
||||
|
||||
// Tar reader
|
||||
tr := tar.NewReader(gr)
|
||||
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
// End of tar archive
|
||||
break
|
||||
}
|
||||
//handleError(err)
|
||||
// fmt.Println("UnTarGzing file..." + hdr.Name)
|
||||
// Check if it is diretory or file
|
||||
if hdr.Typeflag != tar.TypeDir {
|
||||
// Get files from archive
|
||||
// Create diretory before create file
|
||||
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
|
||||
// Write data to file
|
||||
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, tr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fmt.Println("Well done!")
|
||||
}
|
||||
|
||||
// Copyfile
|
||||
func CopyFile(dstName, srcName string) (written int64, err error) {
|
||||
src, err := os.Open(srcName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer dst.Close()
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
192
app/lea/archive/zip.go
Normal file
192
app/lea/archive/zip.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package archive
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"strings"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// main functions shows how to TarGz a directory/file and
|
||||
// UnTarGz a file
|
||||
// Gzip and tar from source directory or file to destination file
|
||||
// you need check file exist before you call this function
|
||||
|
||||
func Zip(srcDirPath string, destFilePath string) (ok bool) {
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
fw, err := os.Create(destFilePath)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fw.Close()
|
||||
|
||||
// Tar writer
|
||||
tw := zip.NewWriter(fw)
|
||||
defer tw.Close()
|
||||
|
||||
// Check if it's a file or a directory
|
||||
f, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// handle source directory
|
||||
// fmt.Println("Cerating tar.gz from directory...")
|
||||
zipDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||
} else {
|
||||
// handle file directly
|
||||
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||
zipFile(srcDirPath, fi.Name(), tw, fi)
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// Deal with directories
|
||||
// if find files, handle them with zipFile
|
||||
// Every recurrence append the base path to the recPath
|
||||
// recPath is the path inside of tar.gz
|
||||
func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
|
||||
// Open source diretory
|
||||
dir, err := os.Open(srcDirPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
// Get file info slice
|
||||
fis, err := dir.Readdir(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
// Append path
|
||||
curPath := srcDirPath + "/" + fi.Name()
|
||||
// Check it is directory or file
|
||||
if fi.IsDir() {
|
||||
// Directory
|
||||
// (Directory won't add unitl all subfiles are added)
|
||||
// fmt.Printf("Adding path...%s\n", curPath)
|
||||
zipDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||
} else {
|
||||
// File
|
||||
// fmt.Printf("Adding file...%s\n", curPath)
|
||||
}
|
||||
|
||||
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with files
|
||||
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
|
||||
if fi.IsDir() {
|
||||
// fmt.Println("??")
|
||||
// Create tar header
|
||||
/*
|
||||
fh, err := zip.FileInfoHeader(fi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fh.Name = recPath // + "/"
|
||||
err = tw.WriteHeader(hdr)
|
||||
tw.Create(recPath)
|
||||
*/
|
||||
} else {
|
||||
// File reader
|
||||
fr, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
// Write hander
|
||||
w, err2 := tw.Create(recPath)
|
||||
if err2 != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Write file data
|
||||
_, err = io.Copy(w, fr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ungzip and untar from source file to destination directory
|
||||
// you need check file exist before you call this function
|
||||
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
|
||||
ok = false
|
||||
msg = ""
|
||||
|
||||
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||
if err := recover(); err != nil {
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
os.Mkdir(destDirPath, os.ModePerm)
|
||||
r, err := zip.OpenReader(srcFilePath);
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close();
|
||||
for _, f := range r.File {
|
||||
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
|
||||
rc, err := f.Open();
|
||||
if err!=nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
|
||||
paths := strings.Split(f.Name, "/")
|
||||
prePath := ""
|
||||
filename := ""
|
||||
l := len(paths)
|
||||
// fmt.Println(l)
|
||||
if l > 1 {
|
||||
// 去掉第1个文件夹
|
||||
if l == 2 {
|
||||
filename = paths[1]
|
||||
} else {
|
||||
filename = paths[l-1]
|
||||
prePath = strings.Join(paths[1:l-1], "/")
|
||||
}
|
||||
} else {
|
||||
filename = f.Name
|
||||
}
|
||||
// fmt.Println(prePath)
|
||||
|
||||
// 相对于目标文件件下的路径
|
||||
destPath := destDirPath + "/" + filename
|
||||
if prePath != "" {
|
||||
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
|
||||
destPath = destDirPath + "/" + prePath + "/" + filename
|
||||
}
|
||||
// Write data to file
|
||||
// fmt.Println(destPath)
|
||||
fw, _ := os.Create(destPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(fw, rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
302
app/lea/blog/Template.go
Normal file
302
app/lea/blog/Template.go
Normal file
@@ -0,0 +1,302 @@
|
||||
package blog
|
||||
|
||||
import (
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
// "os"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//--------------------
|
||||
// leanote 自定义主题
|
||||
// 不使用revel的模板机制
|
||||
// By life
|
||||
//--------------------
|
||||
|
||||
var ts = []string{"header.html", "footer.html", "highlight.html", "comment.html", "view.html", "404.html"}
|
||||
var selfTs = []string{"header.html", "footer.html", "index.html", "about_me.html"} // 用户自定义的文件列表
|
||||
|
||||
type BlogTpl struct {
|
||||
Template *template.Template
|
||||
PathContent map[string]string // path => content
|
||||
}
|
||||
|
||||
func (this *BlogTpl) Content(name string) string {
|
||||
return this.PathContent[name]
|
||||
}
|
||||
|
||||
var BlogTplObject *BlogTpl
|
||||
var CloneTemplate *template.Template
|
||||
|
||||
type RenderTemplateResult struct {
|
||||
Template *template.Template
|
||||
PathContent map[string]string
|
||||
RenderArgs map[string]interface{}
|
||||
|
||||
IsPreview bool // 是否是预览
|
||||
CurBlogTpl *BlogTpl
|
||||
}
|
||||
|
||||
func parseTemplateError(err error) (templateName string, line int, description string) {
|
||||
description = err.Error()
|
||||
i := regexp.MustCompile(`:\d+:`).FindStringIndex(description)
|
||||
if i != nil {
|
||||
line, err = strconv.Atoi(description[i[0]+1 : i[1]-1])
|
||||
if err != nil {
|
||||
}
|
||||
templateName = description[:i[0]]
|
||||
if colon := strings.Index(templateName, ":"); colon != -1 {
|
||||
templateName = templateName[colon+1:]
|
||||
}
|
||||
templateName = strings.TrimSpace(templateName)
|
||||
description = description[i[1]+1:]
|
||||
}
|
||||
return templateName, line, description
|
||||
}
|
||||
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
|
||||
err := r.Template.Execute(wr, r.RenderArgs)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var templateContent []string
|
||||
templateName, line, description := parseTemplateError(err)
|
||||
var content = ""
|
||||
if templateName == "" {
|
||||
templateName = r.Template.Name()
|
||||
content = r.PathContent[templateName]
|
||||
} else {
|
||||
content = r.PathContent[templateName]
|
||||
}
|
||||
if content != "" {
|
||||
templateContent = strings.Split(content, "\n")
|
||||
}
|
||||
|
||||
compileError := &revel.Error{
|
||||
Title: "Template Execution Error",
|
||||
Path: templateName,
|
||||
Description: description,
|
||||
Line: line,
|
||||
SourceLines: templateContent,
|
||||
}
|
||||
|
||||
// 这里, 错误!!
|
||||
// 这里应该导向到本主题的错误页面
|
||||
resp.Status = 500
|
||||
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
|
||||
}
|
||||
|
||||
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||
// Handle panics when rendering templates.
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
}
|
||||
}()
|
||||
|
||||
chunked := revel.Config.BoolDefault("results.chunked", false)
|
||||
|
||||
// If it's a HEAD request, throw away the bytes.
|
||||
out := io.Writer(resp.Out)
|
||||
if req.Method == "HEAD" {
|
||||
out = ioutil.Discard
|
||||
}
|
||||
|
||||
// In a prod mode, write the status, render, and hope for the best.
|
||||
// (In a dev mode, always render to a temporary buffer first to avoid having
|
||||
// error pages distorted by HTML already written)
|
||||
if chunked && !revel.DevMode {
|
||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||
r.render(req, resp, out) // 这里!!!
|
||||
return
|
||||
}
|
||||
|
||||
// Render the template into a temporary buffer, to see if there was an error
|
||||
// rendering the template. If not, then copy it into the response buffer.
|
||||
// Otherwise, template render errors may result in unpredictable HTML (and
|
||||
// would carry a 200 status code)
|
||||
var b bytes.Buffer
|
||||
r.render(req, resp, &b)
|
||||
if !chunked {
|
||||
resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len()))
|
||||
}
|
||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||
b.WriteTo(out)
|
||||
}
|
||||
|
||||
// 博客模板
|
||||
func Init() {
|
||||
BlogTplObject = &BlogTpl{PathContent: map[string]string{}}
|
||||
BlogTplObject.Template = template.New("blog").Funcs(revel.TemplateFuncs)
|
||||
for _, path := range ts {
|
||||
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
|
||||
fileStr := string(fileBytes)
|
||||
path := "blog/" + path
|
||||
// path := path
|
||||
BlogTplObject.PathContent[path] = fileStr
|
||||
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
|
||||
}
|
||||
// 复制一份
|
||||
CloneTemplate, _ = BlogTplObject.Template.Clone()
|
||||
}
|
||||
|
||||
// name = index.html, search.html, cate.html, page.html
|
||||
// basePath 表未用户主题的基路径, 如/xxx/public/upload/32323232/themes/theme1, 如果没有, 则表示用自带的
|
||||
// isPreview 如果是, 错误提示则显示系统的 500 错误详情信息, 供debug
|
||||
//
|
||||
func RenderTemplate(name string, args map[string]interface{}, basePath string, isPreview bool) revel.Result {
|
||||
var r *RenderTemplateResult
|
||||
// 传来的主题路径为空, 则用系统的
|
||||
// 都不会为空的
|
||||
if basePath == "" {
|
||||
path := "blog/" + name
|
||||
// path := name
|
||||
t := BlogTplObject.Template.Lookup(path)
|
||||
r = &RenderTemplateResult{
|
||||
Template: t,
|
||||
PathContent: BlogTplObject.PathContent, // 为了显示错误
|
||||
RenderArgs: args, // 把args给它
|
||||
}
|
||||
} else {
|
||||
// 复制一份
|
||||
newBlogTplObject := &BlogTpl{}
|
||||
var err error
|
||||
newBlogTplObject.Template, err = CloneTemplate.Clone() // 复制一份, 为防止多用户出现问题, 因为newBlogTplObject是全局的
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
newBlogTplObject.PathContent = map[string]string{}
|
||||
for k, v := range BlogTplObject.PathContent {
|
||||
newBlogTplObject.PathContent[k] = v
|
||||
}
|
||||
|
||||
// 将该basePath下的所有文件提出
|
||||
files := ListDir(basePath)
|
||||
Log(basePath)
|
||||
LogJ(files);
|
||||
for _, t := range files {
|
||||
if !strings.Contains(t, ".html") {
|
||||
continue;
|
||||
}
|
||||
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fileStr := string(fileBytes)
|
||||
newBlogTplObject.PathContent[t] = fileStr
|
||||
newBlogTplObject.Template.New(t).Parse(fileStr)
|
||||
}
|
||||
|
||||
// 如果本主题下没有, 则用系统的
|
||||
t := newBlogTplObject.Template.Lookup(name)
|
||||
|
||||
if t == nil {
|
||||
path := "blog/" + name
|
||||
t = BlogTplObject.Template.Lookup(path)
|
||||
}
|
||||
r = &RenderTemplateResult{
|
||||
Template: t,
|
||||
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
||||
RenderArgs: args,
|
||||
CurBlogTpl: newBlogTplObject,
|
||||
IsPreview: isPreview,
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// 错误显示
|
||||
|
||||
type ErrorResult struct {
|
||||
RenderArgs map[string]interface{}
|
||||
Error error
|
||||
IsPreview bool
|
||||
CurBlogTpl *BlogTpl
|
||||
}
|
||||
|
||||
// 错误显示出
|
||||
func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||
format := req.Format
|
||||
status := resp.Status
|
||||
if status == 0 {
|
||||
status = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
contentType := revel.ContentTypeByFilename("xxx." + format)
|
||||
if contentType == revel.DefaultFileContentType {
|
||||
contentType = "text/plain"
|
||||
}
|
||||
|
||||
// Get the error template.
|
||||
var err error
|
||||
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
|
||||
err = nil
|
||||
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
|
||||
|
||||
// This func shows a plaintext error message, in case the template rendering
|
||||
// doesn't work.
|
||||
showPlaintext := func(err error) {
|
||||
revel.PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+
|
||||
"Additionally, an error occurred when rendering the error page:\n%s",
|
||||
r.Error, err)}.Apply(req, resp)
|
||||
}
|
||||
|
||||
// 根据是否是preview来得到404模板
|
||||
// 是, 则显示系统的错误信息, blog-500.html
|
||||
var tmpl *template.Template
|
||||
if r.IsPreview {
|
||||
tmpl = r.CurBlogTpl.Template.Lookup("blog/404.html")
|
||||
} else {
|
||||
tmpl = r.CurBlogTpl.Template.Lookup("404.html")
|
||||
}
|
||||
if tmpl == nil {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("Couldn't find template %s", templatePath)
|
||||
}
|
||||
showPlaintext(err)
|
||||
return
|
||||
}
|
||||
|
||||
// If it's not a revel error, wrap it in one.
|
||||
var revelError *revel.Error
|
||||
switch e := r.Error.(type) {
|
||||
case *revel.Error:
|
||||
revelError = e
|
||||
case error:
|
||||
revelError = &revel.Error{
|
||||
Title: "Server Error",
|
||||
Description: e.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
if revelError == nil {
|
||||
panic("no error provided")
|
||||
}
|
||||
|
||||
if r.RenderArgs == nil {
|
||||
r.RenderArgs = make(map[string]interface{})
|
||||
}
|
||||
r.RenderArgs["Error"] = revelError
|
||||
r.RenderArgs["Router"] = revel.MainRouter
|
||||
|
||||
// 不是preview就不要显示错误了
|
||||
LogJ(revelError)
|
||||
// if r.IsPreview {
|
||||
var b bytes.Buffer
|
||||
out := io.Writer(resp.Out)
|
||||
// out = ioutil.Discard
|
||||
err = tmpl.Execute(&b, r.RenderArgs)
|
||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||
b.WriteTo(out)
|
||||
// }
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import (
|
||||
"strings"
|
||||
"os"
|
||||
// "path/filepath"
|
||||
"net"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
@@ -89,4 +90,13 @@ func trimQueryParams(url string) string {
|
||||
url = Substr(url, 0, pos);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// 通过domain得到ip
|
||||
func GetIpFromDomain(domain string) string {
|
||||
ip, _ := net.LookupIP(domain)
|
||||
if ip != nil && len(ip) > 0 {
|
||||
return ip[0].String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -44,8 +44,12 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
if route.ControllerName != "Static" {
|
||||
// api设置
|
||||
// leanote.com/api/user/get => ApiUser::Get
|
||||
if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") {
|
||||
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
||||
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
|
||||
route.ControllerName = "Api" + route.ControllerName
|
||||
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
|
||||
// member设置
|
||||
route.ControllerName = "Member" + route.ControllerName
|
||||
}
|
||||
// end
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ func init() {
|
||||
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
||||
// session.
|
||||
func (s Session) Id() string {
|
||||
|
||||
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
||||
return sessionIdStr
|
||||
}
|
||||
@@ -131,7 +132,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
|
||||
return session
|
||||
}
|
||||
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
|
||||
|
||||
|
||||
// Verify the signature.
|
||||
if !revel.Verify(data, sig) {
|
||||
revel.INFO.Println("Session cookie signature failed")
|
||||
@@ -145,7 +146,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
|
||||
if sessionTimeoutExpiredOrMissing(session) {
|
||||
session = make(Session)
|
||||
}
|
||||
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
@@ -157,6 +158,7 @@ func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
// c.Session, 重新生成一个revel.Session给controller!!!
|
||||
// Log("sessoin--------")
|
||||
// LogJ(session)
|
||||
|
||||
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
||||
c.Session = revelSession
|
||||
// 生成sessionId
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
用golang exec 总是说找不到uglifyjs命令, 需要全部路径
|
||||
而且node, npm要在/usr/bin下, 已建ln
|
||||
@@ -31,7 +32,7 @@ import (
|
||||
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
||||
"js/object_id"}
|
||||
|
||||
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
||||
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
||||
@@ -52,7 +53,7 @@ func compressJs(filename string) {
|
||||
to := base + filename + "-min.js"
|
||||
cmd := exec.Command(cmdPath, source, "-o", to)
|
||||
_, err := cmd.CombinedOutput()
|
||||
|
||||
fmt.Println(source);
|
||||
cmdError(err)
|
||||
}
|
||||
|
||||
@@ -80,7 +81,10 @@ func combineJs() {
|
||||
// 改note-dev->note
|
||||
func dev() {
|
||||
// 即替换note.js->note-min.js
|
||||
m := map[string]string{"note.js": "note-min.js",
|
||||
m := map[string]string{"tinymce.dev.js": "tinymce.min.js",
|
||||
"tinymce.js": "tinymce.min.js",
|
||||
"jquery.ztree.all-3.5.js": "jquery.ztree.all-3.5-min.js",
|
||||
"note.js": "note-min.js",
|
||||
"app.js": "app-min.js",
|
||||
"page.js": "page-min.js",
|
||||
"common.js": "common-min.js",
|
||||
@@ -88,6 +92,7 @@ func dev() {
|
||||
"share.js": "share-min.js",
|
||||
"tag.js": "tag-min.js",
|
||||
"main.js": "main-min.js",
|
||||
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||
"editor/editor.js": "editor/editor-min.js",
|
||||
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
||||
@@ -111,12 +116,21 @@ func tinymce() {
|
||||
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
||||
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
|
||||
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||
c, err := cmd.CombinedOutput()
|
||||
|
||||
// 必须要先删除
|
||||
cmd2 := exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.dev.js")
|
||||
cmd2.CombinedOutput()
|
||||
cmd2 = exec.Command("/bin/sh", "-c", "rm " + cmd.Dir + "/js/tinymce/tinymce.jquery.dev.js")
|
||||
c, _ := cmd2.CombinedOutput()
|
||||
fmt.Println(string(c))
|
||||
c, _ = cmd.CombinedOutput()
|
||||
fmt.Println(string(c))
|
||||
cmdError(err)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 压缩tinymce
|
||||
tinymce()
|
||||
|
||||
dev();
|
||||
|
||||
// 其它零散的需要压缩的js
|
||||
@@ -133,6 +147,10 @@ func main() {
|
||||
"mdeditor/editor/underscore",
|
||||
"mdeditor/editor/mathJax",
|
||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||
"js/app/editor_drop_paste",
|
||||
"js/app/attachment_upload",
|
||||
"js/jquery.ztree.all-3.5",
|
||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||
}
|
||||
|
||||
for _, js := range otherJss {
|
||||
@@ -141,7 +159,5 @@ func main() {
|
||||
|
||||
// 先压缩后合并
|
||||
combineJs()
|
||||
|
||||
// 压缩tinymce
|
||||
tinymce()
|
||||
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@ type AttachService struct {
|
||||
}
|
||||
|
||||
// add attach
|
||||
func (this *AttachService) AddAttach(attach info.Attach) bool {
|
||||
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
|
||||
attach.CreatedTime = time.Now()
|
||||
ok := db.Insert(db.Attachs, attach)
|
||||
ok = db.Insert(db.Attachs, attach)
|
||||
|
||||
if ok {
|
||||
// 更新笔记的attachs num
|
||||
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||
}
|
||||
|
||||
return ok
|
||||
return
|
||||
}
|
||||
|
||||
// 更新笔记的附件个数
|
||||
@@ -46,8 +46,8 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
|
||||
// list attachs
|
||||
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||
attachs := []info.Attach{}
|
||||
// 判断是否有权限为笔记添加附件
|
||||
if !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
||||
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||
return attachs
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||
return attachs
|
||||
}
|
||||
|
||||
|
||||
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
||||
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||
}
|
||||
@@ -105,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
|
||||
// 获取文件路径
|
||||
// 要判断是否具有权限
|
||||
// userId是否具有attach的访问权限
|
||||
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
|
||||
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
|
||||
if attachId == "" {
|
||||
return
|
||||
}
|
||||
@@ -136,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
|
||||
return
|
||||
}
|
||||
|
||||
//userId为空则是分享笔记的附件
|
||||
if userId == "" && sessionId != "" {
|
||||
if token != "" {
|
||||
realToken := sessionService.GetToken(sessionId)
|
||||
if token == realToken {
|
||||
Log("attach token is equal!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attach = info.Attach{}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
// "github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/revel/revel"
|
||||
"strings"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@@ -17,6 +18,8 @@ type AuthService struct {
|
||||
|
||||
// pwd已md5了
|
||||
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||
emailOrUsername = strings.Trim(emailOrUsername, " ")
|
||||
// pwd = strings.Trim(pwd, " ")
|
||||
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||
return userInfo
|
||||
}
|
||||
@@ -32,12 +35,16 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||
// 1. 添加用户
|
||||
// 2. 将leanote共享给我
|
||||
// [ok]
|
||||
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
||||
func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string) {
|
||||
// 用户是否已存在
|
||||
if userService.IsExistsUser(email) {
|
||||
return false, email + " 已被注册"
|
||||
return false, "userHasBeenRegistered-" + email
|
||||
}
|
||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||
if fromUserId != "" && IsObjectId(fromUserId) {
|
||||
user.FromUserId = bson.ObjectIdHex(fromUserId)
|
||||
}
|
||||
LogJ(user)
|
||||
return this.register(user)
|
||||
}
|
||||
|
||||
@@ -90,7 +97,10 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
||||
Title: user.Username + " 's Blog",
|
||||
SubTitle: "love leanote!",
|
||||
AboutMe: "Hello, I am (^_^)",
|
||||
CanComment: true,
|
||||
})
|
||||
// 添加一个单页面
|
||||
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
|
||||
}
|
||||
|
||||
return true, ""
|
||||
@@ -126,4 +136,4 @@ func (this *AuthService) ThirdRegister(thirdType, thirdUserId, thirdUsername str
|
||||
}
|
||||
_, _ = this.register(userInfo)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,9 @@ import (
|
||||
// 配置服务
|
||||
// 只是全局的, 用户的配置没有
|
||||
type ConfigService struct {
|
||||
adminUserId string
|
||||
siteUrl string
|
||||
adminUsername string
|
||||
// 全局的
|
||||
GlobalAllConfigs map[string]interface{}
|
||||
GlobalStringConfigs map[string]string
|
||||
@@ -24,9 +27,6 @@ type ConfigService struct {
|
||||
GlobalMapConfigs map[string]map[string]string
|
||||
GlobalArrMapConfigs map[string][]map[string]string
|
||||
}
|
||||
|
||||
var adminUserId = ""
|
||||
|
||||
// appStart时 将全局的配置从数据库中得到作为全局
|
||||
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalAllConfigs = map[string]interface{}{}
|
||||
@@ -35,16 +35,17 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||
|
||||
adminUsername, _ := revel.Config.String("adminUsername")
|
||||
if adminUsername == "" {
|
||||
adminUsername = "admin"
|
||||
this.adminUsername, _ = revel.Config.String("adminUsername")
|
||||
if this.adminUsername == "" {
|
||||
this.adminUsername = "admin"
|
||||
}
|
||||
this.siteUrl, _ = revel.Config.String("site.url")
|
||||
|
||||
userInfo := userService.GetUserInfoByAny(adminUsername)
|
||||
userInfo := userService.GetUserInfoByAny(this.adminUsername)
|
||||
if userInfo.UserId == "" {
|
||||
return false
|
||||
}
|
||||
adminUserId = userInfo.UserId.Hex()
|
||||
this.adminUserId = userInfo.UserId.Hex()
|
||||
|
||||
configs := []info.Config{}
|
||||
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||
@@ -68,6 +69,16 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetSiteUrl() string {
|
||||
return this.siteUrl;
|
||||
}
|
||||
func (this *ConfigService) GetAdminUsername() string {
|
||||
return this.adminUsername
|
||||
}
|
||||
func (this *ConfigService) GetAdminUserId() string {
|
||||
return this.adminUserId
|
||||
}
|
||||
|
||||
// 通用方法
|
||||
func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool {
|
||||
// 判断是否存在
|
||||
@@ -183,7 +194,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
if registerSharedUserId == "" {
|
||||
ok = true
|
||||
msg = "share userId is blank, So it share nothing to register"
|
||||
this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", "")
|
||||
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
|
||||
return
|
||||
} else {
|
||||
user := userService.GetUserInfo(registerSharedUserId)
|
||||
@@ -192,7 +203,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
msg = "no such user: " + registerSharedUserId
|
||||
return
|
||||
} else {
|
||||
this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", registerSharedUserId)
|
||||
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +230,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotebooks", notebooks)
|
||||
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks)
|
||||
|
||||
notes := []map[string]string{}
|
||||
// 共享笔记
|
||||
@@ -244,7 +255,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotes", notes)
|
||||
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
|
||||
|
||||
// 复制
|
||||
noteIds := []string{}
|
||||
@@ -265,7 +276,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrayConfig(adminUserId, "registerCopyNoteIds", noteIds)
|
||||
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds)
|
||||
|
||||
ok = true
|
||||
return
|
||||
@@ -277,7 +288,7 @@ func (this *ConfigService) AddBackup(path, remark string) bool {
|
||||
n := time.Now().Unix()
|
||||
nstr := fmt.Sprintf("%v", n)
|
||||
backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark})
|
||||
return this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
||||
return this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
}
|
||||
|
||||
func (this *ConfigService) getBackupDirname() string {
|
||||
@@ -398,7 +409,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
|
||||
// 删除之
|
||||
backups = append(backups[0:i], backups[i+1:]...)
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
@@ -416,7 +427,7 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
|
||||
}
|
||||
backup["remark"] = remark;
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
@@ -451,7 +462,7 @@ func init() {
|
||||
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://") {
|
||||
defaultDomain = siteUrl[len("http://"):]
|
||||
} else if strings.HasPrefix(siteUrl, "https://") {
|
||||
@@ -461,7 +472,6 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func (this *ConfigService) GetSchema() string {
|
||||
return schema;
|
||||
}
|
||||
@@ -539,3 +549,36 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 上传大小
|
||||
func (this *ConfigService) GetUploadSize(key string) float64 {
|
||||
f, _ := strconv.ParseFloat(this.GetGlobalStringConfig(key), 64)
|
||||
return f;
|
||||
}
|
||||
func (this *ConfigService) GetUploadSizeLimit() map[string]float64 {
|
||||
return map[string]float64{
|
||||
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
|
||||
"uploadBlogLogoSize":this.GetUploadSize("uploadBlogLogoSize"),
|
||||
"uploadAttachSize":this.GetUploadSize("uploadAttachSize"),
|
||||
"uploadAvatarSize":this.GetUploadSize("uploadAvatarSize"),
|
||||
}
|
||||
}
|
||||
// 为用户得到全局的配置
|
||||
// NoteController调用
|
||||
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
|
||||
uploadSizeConfigs := this.GetUploadSizeLimit();
|
||||
config := map[string]interface{}{}
|
||||
for k, v := range uploadSizeConfigs {
|
||||
config[k] = v
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// 主页是否是管理员的博客页
|
||||
func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
||||
return this.GetGlobalStringConfig("homePage") == ""
|
||||
}
|
||||
|
||||
func (this *ConfigService) GetVersion() string {
|
||||
return "1.0-beta2"
|
||||
}
|
||||
|
||||
@@ -82,9 +82,9 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
|
||||
return false
|
||||
}
|
||||
|
||||
tokenUrl := siteUrl + "/user/activeEmail?token=" + token
|
||||
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
"user": map[string]interface{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
@@ -122,9 +122,9 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
|
||||
|
||||
// 发送邮件
|
||||
tokenUrl := siteUrl + "/user/updateEmail?token=" + token
|
||||
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||
"newEmail": email,
|
||||
"user": map[string]interface{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
@@ -148,9 +148,9 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
||||
|
||||
// 发送邮件
|
||||
tokenUrl := siteUrl + "/findPassword/" + token
|
||||
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
|
||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl,
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
|
||||
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
||||
|
||||
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||
@@ -167,8 +167,8 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str
|
||||
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
||||
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl,
|
||||
"registerUrl": siteUrl + "/register?from=" + userInfo.Username,
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
|
||||
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
|
||||
"content": content,
|
||||
"user": map[string]interface{}{
|
||||
"username": userInfo.Username,
|
||||
@@ -225,7 +225,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
|
||||
// {blog.id} {blog.title} {blog.url}
|
||||
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
||||
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "blogUrl": configService.GetBlogUrl(),
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(),
|
||||
"blog": map[string]string{
|
||||
"id": note.NoteId.Hex(),
|
||||
"title": note.Title,
|
||||
@@ -316,7 +316,7 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
|
||||
|
||||
var tpl *template.Template
|
||||
|
||||
values["siteUrl"] = siteUrl;
|
||||
values["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
// subject
|
||||
if subject != "" {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
"os"
|
||||
"strings"
|
||||
// "fmt"
|
||||
)
|
||||
|
||||
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||
@@ -17,7 +18,7 @@ type FileService struct {
|
||||
}
|
||||
|
||||
// add Image
|
||||
func (this *FileService) AddImage(image info.File, albumId, userId string) bool {
|
||||
func (this *FileService) AddImage(image info.File, albumId, userId string, needCheckSize bool) (ok bool, msg string) {
|
||||
image.CreatedTime = time.Now()
|
||||
if albumId != "" {
|
||||
image.AlbumId = bson.ObjectIdHex(albumId)
|
||||
@@ -27,7 +28,8 @@ func (this *FileService) AddImage(image info.File, albumId, userId string) bool
|
||||
}
|
||||
image.UserId = bson.ObjectIdHex(userId)
|
||||
|
||||
return db.Insert(db.Files, image)
|
||||
ok = db.Insert(db.Files, image)
|
||||
return
|
||||
}
|
||||
|
||||
// list images
|
||||
@@ -117,7 +119,8 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
||||
// 获取文件路径
|
||||
// 要判断是否具有权限
|
||||
// userId是否具有fileId的访问权限
|
||||
func (this *FileService) GetFile(userId, fileId string) string {
|
||||
|
||||
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
|
||||
if fileId == "" {
|
||||
return ""
|
||||
}
|
||||
@@ -130,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
}
|
||||
|
||||
// 1. 判断权限
|
||||
|
||||
//未登录用户,判断token
|
||||
noteIds := noteImageService.GetNoteIds(fileId)
|
||||
// 是否是我的文件
|
||||
if userId != "" && file.UserId.Hex() == userId {
|
||||
return path
|
||||
@@ -140,14 +144,41 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
// 这些笔记是否有public的, 若有则ok
|
||||
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||
|
||||
noteIds := noteImageService.GetNoteIds(fileId)
|
||||
|
||||
if noteIds != nil && len(noteIds) > 0 {
|
||||
// 这些笔记是否有public的
|
||||
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
||||
return path
|
||||
}
|
||||
|
||||
//分享给未注册用户
|
||||
if userId == "" && sessionId != "" {
|
||||
if token != "" {
|
||||
realToken := sessionService.GetToken(sessionId)
|
||||
if token == realToken {
|
||||
Log("image token is equal!")
|
||||
return path
|
||||
} else {
|
||||
Log("image token is different!")
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
|
||||
for _, noteId := range noteIds {
|
||||
note := noteService.GetNoteById(noteId.Hex())
|
||||
if shareService.HasReadPerm(note.UserId.Hex(), userId, noteId.Hex()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 若有共享给我的笔记?
|
||||
// 对该笔记可读?
|
||||
if db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
|
||||
return path
|
||||
}
|
||||
@@ -166,6 +197,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
return path
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
|
||||
@@ -180,6 +212,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// 复制图片
|
||||
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
||||
// 是否已经复制过了
|
||||
@@ -222,7 +255,7 @@ func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, strin
|
||||
id := bson.NewObjectId();
|
||||
fileInfo.FileId = id
|
||||
fileId = id.Hex()
|
||||
Ok := this.AddImage(fileInfo, "", toUserId)
|
||||
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
|
||||
|
||||
if Ok {
|
||||
return Ok, id.Hex()
|
||||
|
||||
133
app/service/GroupService.go
Normal file
133
app/service/GroupService.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
// 用户组, 用户组用户管理
|
||||
|
||||
type GroupService struct {
|
||||
}
|
||||
|
||||
// 添加分组
|
||||
func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
|
||||
group := info.Group {
|
||||
GroupId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Title: title,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.Groups, group), group
|
||||
}
|
||||
// 删除分组
|
||||
// 判断是否有好友
|
||||
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
|
||||
/*
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
|
||||
return false, "groupHasUsers"
|
||||
}
|
||||
*/
|
||||
db.DeleteAll(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)})
|
||||
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
||||
|
||||
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
||||
}
|
||||
// 修改group标题
|
||||
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
||||
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
||||
}
|
||||
|
||||
// 得到用户的所有分组(包括下的所有用户)
|
||||
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||
// 得到分组s
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||
// 得到其下的用户
|
||||
for i, group := range groups {
|
||||
group.Users = this.GetUsers(group.GroupId.Hex())
|
||||
groups[i] = group
|
||||
}
|
||||
return groups
|
||||
}
|
||||
// 仅仅得到所有分组
|
||||
func (this *GroupService) GetGroups(userId string) ([]info.Group) {
|
||||
// 得到分组s
|
||||
groups := []info.Group{}
|
||||
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||
return groups
|
||||
}
|
||||
// 得到分组, shareService用
|
||||
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||
// 得到分组s
|
||||
group := info.Group{}
|
||||
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
|
||||
return group
|
||||
}
|
||||
|
||||
// 得到某分组下的用户
|
||||
func (this *GroupService) GetUsers(groupId string) ([]info.User) {
|
||||
// 得到UserIds
|
||||
groupUsers := []info.GroupUser{}
|
||||
db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers)
|
||||
if len(groupUsers) == 0 {
|
||||
return nil
|
||||
}
|
||||
userIds := make([]bson.ObjectId, len(groupUsers))
|
||||
for i, each := range groupUsers {
|
||||
userIds[i] = each.UserId
|
||||
}
|
||||
// 得到userInfos
|
||||
return userService.ListUserInfosByUserIds(userIds)
|
||||
}
|
||||
|
||||
// 得到我所属的所有分组ids
|
||||
func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
||||
// 得到UserIds
|
||||
groupUsers := []info.GroupUser{}
|
||||
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
|
||||
if len(groupUsers) == 0 {
|
||||
return nil
|
||||
}
|
||||
groupIds := make([]bson.ObjectId, len(groupUsers))
|
||||
for i, each := range groupUsers {
|
||||
groupIds[i] = each.GroupId
|
||||
}
|
||||
return groupIds
|
||||
}
|
||||
|
||||
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
||||
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
||||
}
|
||||
// 为group添加用户
|
||||
// 用户是否已存在?
|
||||
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbidden"
|
||||
}
|
||||
|
||||
// 是否已存在
|
||||
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||
return false, "hasUsers"
|
||||
}
|
||||
|
||||
return db.Insert(db.GroupUsers, info.GroupUser{
|
||||
GroupUserId: bson.NewObjectId(),
|
||||
GroupId: bson.ObjectIdHex(groupId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
CreatedTime: time.Now(),
|
||||
}), ""
|
||||
}
|
||||
// 删除用户
|
||||
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||
// groupId是否是ownUserId的?
|
||||
if !this.isMyGroup(ownUserId, groupId) {
|
||||
return false, "forbidden"
|
||||
}
|
||||
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||
}
|
||||
@@ -33,7 +33,8 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
|
||||
// TODO
|
||||
l := len(history.Histories)
|
||||
if l >= maxSize {
|
||||
history.Histories = history.Histories[l-maxSize:]
|
||||
// history.Histories = history.Histories[l-maxSize:] // BUG, 致使都是以前的
|
||||
history.Histories = history.Histories[:maxSize]
|
||||
}
|
||||
newHistory := []info.EachHistory{eachHistory}
|
||||
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
|
||||
@@ -61,4 +62,4 @@ func (this *NoteContentHistoryService) ListHistories(noteId, userId string) []in
|
||||
histories := info.NoteContentHistory{}
|
||||
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &histories)
|
||||
return histories.Histories
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,12 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
||||
// 解析内容中的图片, 建立图片与note的关系
|
||||
// <img src="/file/outputImage?fileId=12323232" />
|
||||
// 图片必须是我的, 不然不添加
|
||||
func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
|
||||
// imgSrc 防止博客修改了, 但内容删除了
|
||||
func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content string) bool {
|
||||
// 让主图成为内容的一员
|
||||
if imgSrc != "" {
|
||||
content = "<img src=\"" + imgSrc + "\" >" + content
|
||||
}
|
||||
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
||||
|
||||
|
||||
@@ -17,6 +17,17 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||
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调用
|
||||
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||
note = info.Note{}
|
||||
@@ -111,10 +122,16 @@ func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (no
|
||||
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
||||
return
|
||||
}
|
||||
func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
|
||||
notes = []info.NoteContent{}
|
||||
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract", "Content"}, ¬es)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加笔记
|
||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||
// [ok]
|
||||
|
||||
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
noteId := bson.NewObjectId();
|
||||
@@ -124,6 +141,7 @@ func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||
note.UpdatedTime = note.CreatedTime
|
||||
note.IsTrash = false
|
||||
note.UpdatedUserId = note.UserId
|
||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||
|
||||
// 设为blog
|
||||
notebookId := note.NotebookId.Hex()
|
||||
@@ -164,13 +182,24 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
||||
db.Insert(db.NoteContents, noteContent)
|
||||
|
||||
// 更新笔记图片
|
||||
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
|
||||
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), "", noteContent.Content)
|
||||
|
||||
return noteContent;
|
||||
}
|
||||
|
||||
// 添加笔记和内容
|
||||
// 这里使用 info.NoteAndContent 接收?
|
||||
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
||||
if note.UserId.Hex() != updatedUserId {
|
||||
if !shareService.HasUpdateNotebookPerm(note.UserId.Hex(), updatedUserId, note.NotebookId.Hex()) {
|
||||
Log("NO AUTH11")
|
||||
return info.Note{}
|
||||
} else {
|
||||
Log("HAS AUTH -----------")
|
||||
}
|
||||
}
|
||||
return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId));
|
||||
}
|
||||
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
noteId := bson.NewObjectId()
|
||||
@@ -189,18 +218,24 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note
|
||||
}
|
||||
|
||||
// 修改笔记
|
||||
// [ok] TODO perm还没测
|
||||
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||
if userId != updatedUserId {
|
||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||
Log("NO AUTH")
|
||||
Log("NO AUTH2")
|
||||
return false
|
||||
} else {
|
||||
Log("HAS AUTH -----------")
|
||||
}
|
||||
}
|
||||
|
||||
// 是否已自定义
|
||||
note := this.GetNoteById(noteId)
|
||||
if note.IsBlog && note.HasSelfDefined {
|
||||
delete(needUpdate, "ImgSrc")
|
||||
delete(needUpdate, "Desc")
|
||||
}
|
||||
|
||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
|
||||
@@ -244,12 +279,18 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
||||
}
|
||||
}
|
||||
|
||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId,
|
||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||
"Content": content,
|
||||
"Abstract": abstract,
|
||||
"UpdatedTime": time.Now()}) {
|
||||
|
||||
"UpdatedTime": time.Now()}
|
||||
|
||||
// 是否已自定义
|
||||
note := this.GetNoteById(noteId)
|
||||
if note.IsBlog && note.HasSelfDefined {
|
||||
delete(data, "Abstract")
|
||||
}
|
||||
|
||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
||||
// 这里, 添加历史记录
|
||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||
Content: content,
|
||||
@@ -257,7 +298,7 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
||||
})
|
||||
|
||||
// 更新笔记图片
|
||||
noteImageService.UpdateNoteImages(userId, noteId, content)
|
||||
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -278,6 +319,29 @@ func (this *NoteService) UpdateTags(noteId string, userId string, tags []string)
|
||||
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
||||
}
|
||||
|
||||
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
||||
noteUpdate := bson.M{}
|
||||
if isTop {
|
||||
isBlog = true
|
||||
}
|
||||
if !isBlog {
|
||||
isTop = false
|
||||
}
|
||||
noteUpdate["IsBlog"] = isBlog
|
||||
noteUpdate["IsTop"] = isTop
|
||||
if isBlog {
|
||||
noteUpdate["PublicTime"] = time.Now()
|
||||
} else {
|
||||
noteUpdate["HasSelfDefined"] = false
|
||||
}
|
||||
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
||||
// 重新计算tags
|
||||
go (func() {
|
||||
blogService.ReCountBlogTags(userId)
|
||||
})()
|
||||
return ok
|
||||
}
|
||||
|
||||
// 移动note
|
||||
// trash, 正常的都可以用
|
||||
// 1. 要检查下notebookId是否是自己的
|
||||
@@ -419,15 +483,20 @@ func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
||||
}
|
||||
|
||||
//------------------
|
||||
// 搜索Note
|
||||
// 搜索Note, 博客使用了
|
||||
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
||||
notes = []info.Note{}
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
|
||||
// 利用标题和desc, 不用content
|
||||
orQ := []bson.M{
|
||||
bson.M{"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||
bson.M{"Desc": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||
}
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
||||
"$or": orQ,
|
||||
}
|
||||
if isBlog {
|
||||
query["IsBlog"] = true
|
||||
@@ -509,11 +578,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//------------
|
||||
// 统计
|
||||
func (this *NoteService) CountNote() int {
|
||||
return db.Count(db.Notes, bson.M{"IsTrash": false})
|
||||
func (this *NoteService) CountNote(userId string) int {
|
||||
q := bson.M{"IsTrash": false}
|
||||
if userId != "" {
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
}
|
||||
return db.Count(db.Notes, q)
|
||||
}
|
||||
func (this *NoteService) CountBlog() int {
|
||||
return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false})
|
||||
func (this *NoteService) CountBlog(userId string) int {
|
||||
q := bson.M{"IsBlog": true, "IsTrash": false}
|
||||
if userId != "" {
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
}
|
||||
return db.Count(db.Notes, q)
|
||||
}
|
||||
@@ -101,6 +101,15 @@ func (this *NotebookService) GetNotebookById(notebookId string) info.Notebook {
|
||||
db.Get(db.Notebooks, notebookId, ¬ebook)
|
||||
return notebook
|
||||
}
|
||||
func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOrUrlTitle string) info.Notebook {
|
||||
notebook := info.Notebook{}
|
||||
if IsObjectId(notebookIdOrUrlTitle) {
|
||||
db.Get(db.Notebooks, notebookIdOrUrlTitle, ¬ebook)
|
||||
} else {
|
||||
db.GetByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(notebookIdOrUrlTitle)}, ¬ebook)
|
||||
}
|
||||
return notebook
|
||||
}
|
||||
|
||||
// 得到用户下所有的notebook
|
||||
// 排序好之后返回
|
||||
@@ -133,6 +142,7 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
||||
// 添加
|
||||
// [ok]
|
||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||
err := db.Notebooks.Insert(notebook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -170,34 +180,43 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin
|
||||
// 更新notebook
|
||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||
}
|
||||
|
||||
// ToBlog or Not
|
||||
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
||||
// 笔记本
|
||||
db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, bson.M{"IsBlog": isBlog})
|
||||
|
||||
// 如果有IsBlog之类的, 需要特殊处理
|
||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||
// 设为blog/取消, 把它下面所有的note都设为isBlog
|
||||
if is, ok2 := isBlog.(bool); ok2 {
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
// 更新笔记
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||
data := bson.M{"IsBlog": is}
|
||||
if is {
|
||||
data["PublicTime"] = time.Now()
|
||||
}
|
||||
db.UpdateByQMap(db.Notes, q, data)
|
||||
|
||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||
// 先查该notebook下所有notes, 得到id
|
||||
notes := []info.Note{}
|
||||
db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es)
|
||||
if len(notes) > 0 {
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, each := range notes {
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
|
||||
}
|
||||
data := bson.M{"IsBlog": isBlog}
|
||||
if isBlog {
|
||||
data["PublicTime"] = time.Now()
|
||||
} else {
|
||||
data["HasSelfDefined"] = false
|
||||
}
|
||||
db.UpdateByQMap(db.Notes, q, data)
|
||||
|
||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||
// 先查该notebook下所有notes, 得到id
|
||||
notes := []info.Note{}
|
||||
db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es)
|
||||
if len(notes) > 0 {
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, each := range notes {
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
|
||||
}
|
||||
|
||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||
// 重新计算tags
|
||||
go (func() {
|
||||
blogService.ReCountBlogTags(userId)
|
||||
})()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 查看是否有子notebook
|
||||
|
||||
@@ -17,6 +17,13 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
|
||||
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||
bson.M{key: value, "UpdatedTime": time.Now()})
|
||||
}
|
||||
|
||||
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
|
||||
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
|
||||
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
|
||||
}
|
||||
|
||||
|
||||
// 注销时清空session
|
||||
func (this *SessionService) Clear(sessionId string) bool {
|
||||
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
|
||||
@@ -69,3 +76,19 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
|
||||
Log(ok)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
// 附件token
|
||||
func (this *SessionService) GetToken(sessionId string) string {
|
||||
session := this.Get(sessionId)
|
||||
return session.Token
|
||||
}
|
||||
|
||||
func (this *SessionService) SetToken(sessionId, token string) bool {
|
||||
this.Get(sessionId)
|
||||
Log(sessionId)
|
||||
Log(token)
|
||||
ok := this.UpdateToken(sessionId, "Token", token)
|
||||
Log(ok)
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -7,13 +7,19 @@ import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"sort"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 共享Notebook, Note服务
|
||||
type ShareService struct {
|
||||
}
|
||||
|
||||
//-----------------
|
||||
//-----------------------------------
|
||||
// 返回shareNotebooks, sharedUserInfos
|
||||
// info.ShareNotebooksByUser, []info.User
|
||||
|
||||
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
||||
|
||||
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
||||
@@ -27,23 +33,49 @@ type ShareService struct {
|
||||
// 3 每个层按seq进行排序
|
||||
// 4 按用户分组
|
||||
// [ok]
|
||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||
//-------------
|
||||
// 查询HasShareNote表得到所有其它用户信息
|
||||
hasShareNotes := []info.HasShareNote{}
|
||||
db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes);
|
||||
|
||||
userIds := make([]bson.ObjectId, len(hasShareNotes))
|
||||
for i, each := range hasShareNotes {
|
||||
userIds[i] = each.UserId
|
||||
|
||||
// 谁共享给了我的Query
|
||||
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||
// 得到我参与的组织
|
||||
groupIds := groupService.GetBelongToGroupIds(userId)
|
||||
q := bson.M{}
|
||||
if len(groupIds) > 0 {
|
||||
orQ := []bson.M{
|
||||
bson.M{"ToUserId": bson.ObjectIdHex(userId)},
|
||||
bson.M{"ToGroupId": bson.M{"$in": groupIds}},
|
||||
}
|
||||
// 不是trash的
|
||||
q["$or"] = orQ
|
||||
} else {
|
||||
q["ToUserId"] = bson.ObjectIdHex(userId);
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// 得到共享给我的笔记本和用户(谁共享给了我)
|
||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||
// 得到共享给我的用户s信息
|
||||
// 得到我参与的组织
|
||||
q := this.getOrQ(userId)
|
||||
|
||||
// 不查hasShareNotes
|
||||
// 直接查shareNotes, shareNotebooks表得到userId
|
||||
userIds1 := []bson.ObjectId{}
|
||||
db.Distinct(db.ShareNotes, q, "UserId", &userIds1)
|
||||
|
||||
userIds2 := []bson.ObjectId{}
|
||||
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds2) // BUG之前是userId1, 2014/12/29
|
||||
|
||||
userIds := append(userIds1, userIds2...)
|
||||
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||
|
||||
//--------------------
|
||||
// 得到他们共享给我的notebooks
|
||||
|
||||
// 这里可能会得到重复的记录
|
||||
// 权限: 笔记本分享给个人 > 笔记本分享给组织
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
db.ShareNotebooks.Find(bson.M{"ToUserId": bson.ObjectIdHex(userId)}).All(&shareNotebooks)
|
||||
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shareNotebooks) // 按ToUserId降序排序, 那么有ToUserId的在前面
|
||||
|
||||
if len(shareNotebooks) == 0 {
|
||||
return nil, userInfos
|
||||
@@ -52,12 +84,15 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
||||
shareNotebooksLen := len(shareNotebooks)
|
||||
|
||||
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
||||
notebookIds := make([]bson.ObjectId, shareNotebooksLen)
|
||||
notebookIds := []bson.ObjectId{}
|
||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
||||
for i, each := range shareNotebooks {
|
||||
// 默认的是没有notebookId的
|
||||
notebookIds[i] = each.NotebookId
|
||||
shareNotebooksMap[each.NotebookId] = each
|
||||
for _, each := range shareNotebooks {
|
||||
// 之后的就不要了, 只留权限高的
|
||||
if _, ok := shareNotebooksMap[each.NotebookId]; !ok {
|
||||
// 默认的是没有notebookId的
|
||||
notebookIds = append(notebookIds, each.NotebookId)
|
||||
shareNotebooksMap[each.NotebookId] = each
|
||||
}
|
||||
}
|
||||
|
||||
// 1, 2
|
||||
@@ -127,9 +162,13 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
|
||||
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
||||
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
||||
q := this.getOrQ(myUserId)
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId);
|
||||
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||
shareNotebook := info.ShareNotebook{}
|
||||
db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
|
||||
db.GetByQ(db.ShareNotebooks,
|
||||
q,
|
||||
&shareNotebook)
|
||||
|
||||
if shareNotebook.NotebookId == "" {
|
||||
return nil
|
||||
@@ -146,7 +185,19 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId);
|
||||
// 笔记的权限
|
||||
shareNotes := []info.ShareNote{}
|
||||
delete(q, "NotebookId")
|
||||
q["NoteId"] = bson.M{"$in": noteIds}
|
||||
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限
|
||||
notePerms := map[bson.ObjectId]int{}
|
||||
for _, each := range shareNotes {
|
||||
if _, ok := notePerms[each.NoteId]; !ok {
|
||||
notePerms[each.NoteId] = each.Perm
|
||||
}
|
||||
}
|
||||
Log("笔记权限")
|
||||
LogJ(notePerms);
|
||||
|
||||
// 3.2 组合
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
||||
@@ -162,17 +213,21 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
||||
}
|
||||
|
||||
// 得到note的perm信息
|
||||
func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||
shareNotes := []info.ShareNote{}
|
||||
db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||
|
||||
notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||
for _, each := range shareNotes {
|
||||
notesPerm[each.NoteId] = each.Perm
|
||||
}
|
||||
|
||||
return notesPerm
|
||||
}
|
||||
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||
// shareNotes := []info.ShareNote{}
|
||||
// db.ListByQ(db.ShareNotes,
|
||||
// bson.M{
|
||||
// "NoteId": bson.M{"$in": noteIds},
|
||||
// "UserId": bson.ObjectIdHex(sharedUserId),
|
||||
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||
//
|
||||
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||
// for _, each := range shareNotes {
|
||||
// notesPerm[each.NoteId] = each.Perm
|
||||
// }
|
||||
//
|
||||
// return notesPerm
|
||||
//}
|
||||
|
||||
// 得到默认的单个的notes 共享集
|
||||
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
||||
@@ -184,9 +239,12 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
||||
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
shareNotes := []info.ShareNote{}
|
||||
|
||||
q := this.getOrQ(myUserId)
|
||||
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||
|
||||
db.ShareNotes.
|
||||
Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
|
||||
// Sort(sortFieldR).
|
||||
Find(q).
|
||||
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(&shareNotes)
|
||||
@@ -200,15 +258,20 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
notes := noteService.ListNotesByNoteIds(noteIds)
|
||||
notesMap := make(map[bson.ObjectId]info.Note, len(notes))
|
||||
notesMap := map[bson.ObjectId]info.Note{}
|
||||
for _, each := range notes {
|
||||
notesMap[each.NoteId] = each
|
||||
}
|
||||
|
||||
// 将shareNotes与notes结合起来
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
|
||||
for i, each := range shareNotes {
|
||||
notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
|
||||
notesWithPerm := []info.ShareNoteWithPerm{}
|
||||
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的
|
||||
for _, each := range shareNotes {
|
||||
if !hasAdded[each.NoteId] {
|
||||
// 待优化
|
||||
notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm})
|
||||
hasAdded[each.NoteId] = true
|
||||
}
|
||||
}
|
||||
return notesWithPerm
|
||||
}
|
||||
@@ -277,28 +340,36 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||
});
|
||||
|
||||
|
||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
ToUserId: bson.ObjectIdHex(toUserId),
|
||||
Perm: perm,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
|
||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||
}
|
||||
|
||||
|
||||
// updatedUserId是否有查看userId noteId的权限?
|
||||
// userId是所有者
|
||||
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
||||
if !db.Has(db.ShareNotes,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||
if !db.Has(db.ShareNotes, q) {
|
||||
// noteId的notebookId是否被共享了?
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId.Hex() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
delete(q, "NoteId")
|
||||
q["NotebookId"] = notebookId
|
||||
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
|
||||
if !db.Has(db.ShareNotebooks, q) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
@@ -310,43 +381,44 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool
|
||||
|
||||
// updatedUserId是否有修改userId noteId的权限?
|
||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||
// 1. noteId是否被共享了?
|
||||
// 得到该note share的信息
|
||||
/*
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
*/
|
||||
if !db.Has(db.ShareNotes,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) {
|
||||
// noteId的notebookId是否被共享了?
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId.Hex() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||
|
||||
// note的权限
|
||||
shares := []info.ShareNote{}
|
||||
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织
|
||||
for _, share := range shares {
|
||||
return share.Perm == 1 // 第1个权限最大
|
||||
}
|
||||
|
||||
// notebook的权限
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId.Hex() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
delete(q, "NoteId")
|
||||
q["NotebookId"] = notebookId
|
||||
shares2 := []info.ShareNotebook{}
|
||||
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||
for _, share := range shares2 {
|
||||
return share.Perm == 1 // 第1个权限最大
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// updatedUserId是否有修改userId notebookId的权限?
|
||||
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||
shares2 := []info.ShareNotebook{}
|
||||
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||
for _, share := range shares2 {
|
||||
return share.Perm == 1 // 第1个权限最大
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 共享note, notebook时使用
|
||||
@@ -372,12 +444,16 @@ func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId strin
|
||||
}
|
||||
|
||||
// 得到共享的笔记内容
|
||||
// 首先要判断这个note是否我被共享了
|
||||
// 并返回笔记的权限!!!
|
||||
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
||||
noteContent = info.NoteContent{}
|
||||
// 是否单独共享了该notebook
|
||||
// 或者, 其notebook共享了我
|
||||
if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
|
||||
// Log(this.HasSharedNote(noteId, myUserId))
|
||||
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
|
||||
Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
|
||||
if this.HasReadPerm(sharedUserId, myUserId, noteId) {
|
||||
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
|
||||
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||
} else {
|
||||
}
|
||||
@@ -391,7 +467,15 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
||||
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
||||
// 得到shareNote信息, 得到所有的ToUserId
|
||||
shareNotes := []info.ShareNote{}
|
||||
db.ListByQLimit(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}, &shareNotes, 100)
|
||||
db.ListByQLimit(db.ShareNotes,
|
||||
bson.M{
|
||||
"NoteId": bson.ObjectIdHex(noteId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToGroupId": bson.M{"$exists": false},
|
||||
}, &shareNotes, 100)
|
||||
|
||||
// Log("<<>>>>")
|
||||
// Log(len(shareNotes))
|
||||
|
||||
if len(shareNotes) == 0 {
|
||||
return nil
|
||||
@@ -450,7 +534,11 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
|
||||
db.ListByQLimit(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)},
|
||||
bson.M{
|
||||
"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToGroupId": bson.M{"$exists": false},
|
||||
},
|
||||
&shareNotebooks, 100)
|
||||
|
||||
if len(shareNotebooks) == 0 {
|
||||
@@ -555,7 +643,7 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// 用户userId是否有修改noteId的权限
|
||||
// 用户userId是否有查看noteId的权限
|
||||
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
||||
if noteId == "" || userId == "" {
|
||||
return false;
|
||||
@@ -576,4 +664,177 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------
|
||||
// 用户分组
|
||||
|
||||
// 得到笔记分享给的groups
|
||||
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
||||
// 得到分组s
|
||||
groups := groupService.GetGroups(userId)
|
||||
|
||||
// 得到有分享的分组
|
||||
shares := []info.ShareNote{}
|
||||
db.ListByQ(db.ShareNotes,
|
||||
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
|
||||
mapShares := map[bson.ObjectId]info.ShareNote{}
|
||||
for _, share := range shares {
|
||||
mapShares[share.ToGroupId] = share
|
||||
}
|
||||
|
||||
// 所有的groups都有share, 但没有share的group没有shareId
|
||||
shares2 := make([]info.ShareNote, len(groups))
|
||||
for i, group := range groups {
|
||||
share, ok := mapShares[group.GroupId]
|
||||
if !ok {
|
||||
share = info.ShareNote{}
|
||||
}
|
||||
share.ToGroup = group;
|
||||
shares2[i] = share
|
||||
}
|
||||
|
||||
return shares2
|
||||
}
|
||||
|
||||
// 共享笔记给分组
|
||||
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
||||
// 得到group, 是否是我的group
|
||||
group := groupService.GetGroup(userId, groupId)
|
||||
if group.GroupId == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 先删除之
|
||||
this.DeleteShareNoteGroup(userId, noteId, groupId)
|
||||
|
||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId), // 冗余字段
|
||||
ToGroupId: bson.ObjectIdHex(groupId),
|
||||
Perm: perm,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.ShareNotes, shareNote)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) bool {
|
||||
return db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
||||
});
|
||||
}
|
||||
|
||||
//-------
|
||||
|
||||
// 得到笔记本分享给的groups
|
||||
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
||||
// 得到分组s
|
||||
groups := groupService.GetGroups(userId)
|
||||
|
||||
// 得到有分享的分组
|
||||
shares := []info.ShareNotebook{}
|
||||
db.ListByQ(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
|
||||
mapShares := map[bson.ObjectId]info.ShareNotebook{}
|
||||
for _, share := range shares {
|
||||
mapShares[share.ToGroupId] = share
|
||||
}
|
||||
LogJ(shares)
|
||||
|
||||
// 所有的groups都有share, 但没有share的group没有shareId
|
||||
shares2 := make([]info.ShareNotebook, len(groups))
|
||||
for i, group := range groups {
|
||||
share, ok := mapShares[group.GroupId]
|
||||
if !ok {
|
||||
share = info.ShareNotebook{}
|
||||
}
|
||||
share.ToGroup = group;
|
||||
shares2[i] = share
|
||||
}
|
||||
|
||||
return shares2
|
||||
}
|
||||
// 共享笔记给分组
|
||||
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
||||
// 得到group, 是否是我的group
|
||||
group := groupService.GetGroup(userId, groupId)
|
||||
if group.GroupId == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 先删除之
|
||||
this.DeleteShareNotebookGroup(userId, notebookId, groupId)
|
||||
|
||||
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||
UserId: bson.ObjectIdHex(userId), // 冗余字段
|
||||
ToGroupId: bson.ObjectIdHex(groupId),
|
||||
Perm: perm,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.ShareNotebooks, shareNotebook)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId string) bool {
|
||||
return db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToGroupId": bson.ObjectIdHex(groupId),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
func (this *ShareService) GenSharePass(noteId string) (int, bool) {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
pass := 1000 + r.Intn(9000)
|
||||
|
||||
ok := db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$set": bson.M{"SharePass": pass}})
|
||||
return pass, ok
|
||||
}
|
||||
|
||||
func (this *ShareService) QuerySharePass(noteId string) int {
|
||||
note := &info.Note{}
|
||||
db.Get(db.Notes, noteId, note)
|
||||
|
||||
return note.SharePass
|
||||
}
|
||||
|
||||
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
|
||||
note = info.Note{}
|
||||
db.Get(db.Notes, noteId, ¬e)
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
634
app/service/ThemeService.go
Normal file
634
app/service/ThemeService.go
Normal file
@@ -0,0 +1,634 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/lea/archive"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"strings"
|
||||
"os"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// 主题
|
||||
type ThemeService struct {
|
||||
}
|
||||
|
||||
var defaultStyle = "blog_default"
|
||||
var elegantStyle = "blog_daqi"
|
||||
var fixedStyle = "blog_left_fixed"
|
||||
|
||||
// admin用户的主题基路径
|
||||
func (this *ThemeService) getDefaultThemeBasePath() string {
|
||||
return revel.BasePath + "/public/blog/themes"
|
||||
}
|
||||
// 默认主题路径
|
||||
func (this *ThemeService) getDefaultThemePath(style string) string {
|
||||
if style == elegantStyle {
|
||||
return this.getDefaultThemeBasePath() + "/elegant"
|
||||
} else if style == fixedStyle {
|
||||
return this.getDefaultThemeBasePath() + "/nav_fixed"
|
||||
} else {
|
||||
return this.getDefaultThemeBasePath() + "/default"
|
||||
}
|
||||
}
|
||||
// blogService用
|
||||
func (this *ThemeService) GetDefaultThemePath(style string) string {
|
||||
if style == elegantStyle {
|
||||
return "public/blog/themes/elegant"
|
||||
} else if style == fixedStyle {
|
||||
return "public/blog/themes/nav_fixed"
|
||||
} else {
|
||||
return "public/blog/themes/default"
|
||||
}
|
||||
}
|
||||
|
||||
// 得到默认主题
|
||||
// style是之前的值, 有3个值 blog_default, blog_daqi, blog_left_fixed
|
||||
func (this *ThemeService) getDefaultTheme(style string) info.Theme {
|
||||
if style == elegantStyle {
|
||||
return info.Theme{
|
||||
IsDefault: true,
|
||||
Path: "public/blog/themes/elegant",
|
||||
Name: "leanote elegant",
|
||||
Author: "leanote",
|
||||
AuthorUrl: "http://leanote.com",
|
||||
Version: "1.0",
|
||||
}
|
||||
} else if style == fixedStyle {
|
||||
return info.Theme{
|
||||
IsDefault: true,
|
||||
Path: "public/blog/themes/nav_fixed",
|
||||
Name: "leanote nav fixed",
|
||||
Author: "leanote",
|
||||
AuthorUrl: "http://leanote.com",
|
||||
Version: "1.0",
|
||||
}
|
||||
} else { // blog default
|
||||
return info.Theme{
|
||||
IsDefault: true,
|
||||
Path: "public/blog/themes/default",
|
||||
Name: "leanote default",
|
||||
Author: "leanote",
|
||||
AuthorUrl: "http://leanote.com",
|
||||
Version: "1.0",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户的主题路径设置
|
||||
func (this *ThemeService) getUserThemeBasePath(userId string) string {
|
||||
return revel.BasePath + "/public/upload/" + userId + "/themes"
|
||||
}
|
||||
func (this *ThemeService) getUserThemePath(userId, themeId string) string {
|
||||
return this.getUserThemeBasePath(userId) + "/" + themeId
|
||||
}
|
||||
func (this *ThemeService) getUserThemePath2(userId, themeId string) string {
|
||||
return "public/upload/" + userId + "/themes/" + themeId
|
||||
}
|
||||
|
||||
// 新建主题
|
||||
// 复制默认主题到文件夹下
|
||||
func (this *ThemeService) CopyDefaultTheme(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||
newThemeId := bson.NewObjectId()
|
||||
themeId = newThemeId.Hex()
|
||||
userId := userBlog.UserId.Hex()
|
||||
themePath := this.getUserThemePath(userId, themeId)
|
||||
err := os.MkdirAll(themePath, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 复制默认主题
|
||||
defaultThemePath := this.getDefaultThemePath(userBlog.Style)
|
||||
err = CopyDir(defaultThemePath, themePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 保存到数据库中
|
||||
theme, _ := this.getThemeConfig(themePath)
|
||||
theme.ThemeId = newThemeId
|
||||
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||
theme.CreatedTime = time.Now()
|
||||
theme.UpdatedTime = theme.CreatedTime
|
||||
theme.UserId = bson.ObjectIdHex(userId)
|
||||
|
||||
ok = db.Insert(db.Themes, theme)
|
||||
return ok, themeId
|
||||
}
|
||||
|
||||
// 第一次新建主题
|
||||
// 设为active true
|
||||
func (this *ThemeService) NewThemeForFirst(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||
this.ActiveTheme(userBlog.UserId.Hex(), themeId)
|
||||
// db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||
return
|
||||
}
|
||||
|
||||
// 新建主题, 判断是否有主题了
|
||||
func (this *ThemeService) NewTheme(userId string) (ok bool, themeId string) {
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
// 如果还没有主题, 那先复制旧的主题
|
||||
if userBlog.ThemeId == "" {
|
||||
themeService.NewThemeForFirst(userBlog)
|
||||
}
|
||||
// 再copy一个默认主题
|
||||
userBlog.Style = "defaultStyle";
|
||||
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||
return
|
||||
}
|
||||
|
||||
// 将字符串转成Theme配置
|
||||
func (this *ThemeService) parseConfig(configStr string) (theme info.Theme, err error) {
|
||||
theme = info.Theme{}
|
||||
// 除去/**/注释
|
||||
reg, _ := regexp.Compile("/\\*[\\s\\S]*?\\*/")
|
||||
configStr = reg.ReplaceAllString(configStr, "")
|
||||
// 转成map
|
||||
config := map[string]interface{}{}
|
||||
err = json.Unmarshal([]byte(configStr), &config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 没有错, 则将Name, Version, Author, AuthorUrl
|
||||
Name := config["Name"]
|
||||
if Name != nil {
|
||||
theme.Name = Name.(string)
|
||||
}
|
||||
Version := config["Version"]
|
||||
if Version != nil {
|
||||
theme.Version = Version.(string)
|
||||
}
|
||||
Author := config["Author"]
|
||||
if Author != nil {
|
||||
theme.Author = Author.(string)
|
||||
}
|
||||
AuthorUrl := config["AuthorUrl"]
|
||||
if AuthorUrl != nil {
|
||||
theme.AuthorUrl = AuthorUrl.(string)
|
||||
}
|
||||
theme.Info = config
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 读取theme.json得到值
|
||||
func (this *ThemeService) getThemeConfig(themePath string) (theme info.Theme, err error) {
|
||||
theme = info.Theme{}
|
||||
configStr := GetFileStrContent(themePath + "/theme.json")
|
||||
theme, err = this.parseConfig(configStr)
|
||||
return
|
||||
}
|
||||
|
||||
func (this *ThemeService) GetTheme(userId, themeId string) info.Theme {
|
||||
theme := info.Theme{}
|
||||
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, &theme)
|
||||
return theme
|
||||
}
|
||||
func (this *ThemeService) GetThemeById(themeId string) info.Theme {
|
||||
theme := info.Theme{}
|
||||
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, &theme)
|
||||
return theme
|
||||
}
|
||||
|
||||
// 得到主题信息, 为了给博客用
|
||||
func (this *ThemeService) GetThemeInfo(themeId, style string) map[string]interface{} {
|
||||
q := bson.M{}
|
||||
if themeId == "" {
|
||||
if style == "" {
|
||||
style = defaultStyle
|
||||
}
|
||||
q["Style"] = style
|
||||
q["IsDefault"] = true
|
||||
} else {
|
||||
q["_id"] = bson.ObjectIdHex(themeId)
|
||||
}
|
||||
theme := info.Theme{}
|
||||
db.GetByQ(db.Themes, q, &theme)
|
||||
return theme.Info
|
||||
}
|
||||
|
||||
// 得到用户的主题
|
||||
// 若用户没有主题, 则至少有一个默认主题
|
||||
// 第一个返回值是当前active
|
||||
func (this *ThemeService) GetUserThemes(userId string) (theme info.Theme, themes []info.Theme) {
|
||||
theme = info.Theme{}
|
||||
themes = []info.Theme{}
|
||||
|
||||
// db.ListByQ(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId)}, &themes)
|
||||
|
||||
// 创建时间逆序
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
||||
q := db.Themes.Find(query);
|
||||
q.Sort("-CreatedTime").All(&themes)
|
||||
if len(themes) == 0 {
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
theme = this.getDefaultTheme(userBlog.Style)
|
||||
} else {
|
||||
var has = false
|
||||
// 第一个是active的主题
|
||||
themes2 := make([]info.Theme, len(themes))
|
||||
i := 0
|
||||
for _, t := range themes {
|
||||
if t.IsActive {
|
||||
theme = t
|
||||
} else {
|
||||
has = true
|
||||
themes2[i] = t
|
||||
i++
|
||||
}
|
||||
}
|
||||
if has {
|
||||
themes = themes2
|
||||
} else {
|
||||
themes = nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 得到默认主题供选择
|
||||
func (this *ThemeService) GetDefaultThemes() (themes []info.Theme) {
|
||||
themes = []info.Theme{}
|
||||
db.ListByQ(db.Themes, bson.M{"IsDefault": true}, &themes)
|
||||
return
|
||||
}
|
||||
|
||||
// 得到模板内容
|
||||
func (this *ThemeService) GetTplContent(userId, themeId, filename string) string {
|
||||
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||
return GetFileStrContent(path)
|
||||
}
|
||||
|
||||
// 得到主题的绝对路径
|
||||
func (this *ThemeService) GetThemeAbsolutePath(userId, themeId string) string {
|
||||
theme := info.Theme{}
|
||||
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||
if theme.Path != "" {
|
||||
return revel.BasePath + "/" + theme.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (this *ThemeService) GetThemePath(userId, themeId string) string {
|
||||
theme := info.Theme{}
|
||||
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||
if theme.Path != "" {
|
||||
return theme.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
// 更新模板内容
|
||||
func (this *ThemeService) UpdateTplContent(userId, themeId, filename, content string) (ok bool, msg string) {
|
||||
basePath := this.GetThemeAbsolutePath(userId, themeId)
|
||||
path := basePath + "/" + filename
|
||||
if strings.Contains(filename, ".html") {
|
||||
Log(">>")
|
||||
if ok, msg = this.ValidateTheme(basePath, filename, content); ok {
|
||||
// 模板
|
||||
if ok, msg = this.mustTpl(filename, content); ok {
|
||||
ok = PutFileStrContent(path, content)
|
||||
}
|
||||
}
|
||||
return
|
||||
} else if filename == "theme.json" {
|
||||
// 主题配置, 判断是否是正确的json
|
||||
theme, err := this.parseConfig(content)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("%v", err)
|
||||
}
|
||||
// 正确, 更新theme信息
|
||||
ok = db.UpdateByQMap(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)},
|
||||
bson.M{
|
||||
"Name": theme.Name,
|
||||
"Version": theme.Version,
|
||||
"Author": theme.Author,
|
||||
"AuthorUrl": theme.AuthorUrl,
|
||||
"Info": theme.Info,
|
||||
})
|
||||
if ok {
|
||||
ok = PutFileStrContent(path, content)
|
||||
}
|
||||
return
|
||||
}
|
||||
ok = PutFileStrContent(path, content)
|
||||
return
|
||||
}
|
||||
|
||||
func (this *ThemeService) DeleteTpl(userId, themeId, filename string) (ok bool) {
|
||||
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||
ok = DeleteFile(path)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断是否有语法错误
|
||||
func (this *ThemeService) mustTpl(filename, content string) (ok bool, msg string) {
|
||||
ok = true
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
Log(err)
|
||||
msg = fmt.Sprintf("%v", err)
|
||||
}
|
||||
}()
|
||||
template.Must(template.New(filename).Funcs(revel.TemplateFuncs).Parse(content))
|
||||
return
|
||||
}
|
||||
|
||||
/////////
|
||||
|
||||
// 使用主题
|
||||
func (this *ThemeService) ActiveTheme(userId, themeId string) (ok bool) {
|
||||
if db.Has(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||
// 之前的设为false
|
||||
db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "IsActive": true}, "IsActive", false)
|
||||
// 现在的设为true
|
||||
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||
|
||||
// UserBlog ThemeId
|
||||
db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "ThemeId", bson.ObjectIdHex(themeId))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除主题
|
||||
func (this *ThemeService) DeleteTheme(userId, themeId string) (ok bool) {
|
||||
return db.Delete(db.Themes,bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId), "IsActive": false})
|
||||
}
|
||||
|
||||
// 公开主题, 只有管理员才有权限, 之前没公开的变成公开
|
||||
func (this *ThemeService) PublicTheme(userId, themeId string) (ok bool) {
|
||||
// 是否是管理员?
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
if userInfo.Username == configService.GetAdminUsername() {
|
||||
theme := this.GetThemeById(themeId)
|
||||
return db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(themeId)}, "IsDefault", !theme.IsDefault)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// 导出主题
|
||||
func (this *ThemeService) ExportTheme(userId, themeId string) (ok bool, path string) {
|
||||
theme := this.GetThemeById(themeId)
|
||||
// 打包
|
||||
// 验证路径, 别把整个项目打包了
|
||||
Log(theme.Path)
|
||||
if theme.Path == "" ||
|
||||
(!strings.HasPrefix(theme.Path, "public/upload") &&
|
||||
!strings.HasPrefix(theme.Path, "public/blog/themes")) ||
|
||||
strings.Contains(theme.Path, "..") {
|
||||
return
|
||||
}
|
||||
|
||||
sourcePath := revel.BasePath + "/" + theme.Path
|
||||
targetPath := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||
err := os.MkdirAll(targetPath, 0755)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return
|
||||
}
|
||||
targetName := targetPath + "/" + theme.Name + ".zip"
|
||||
Log(sourcePath)
|
||||
Log(targetName)
|
||||
ok = archive.Zip(sourcePath, targetName)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
return true, targetName
|
||||
}
|
||||
// 导入主题
|
||||
// path == /llllllll/..../public/upload/.../aa.zip, 绝对路径
|
||||
func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string) {
|
||||
themeIdO := bson.NewObjectId()
|
||||
themeId := themeIdO.Hex()
|
||||
targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId
|
||||
if ok, msg = archive.Unzip(path, targetPath); !ok {
|
||||
DeleteFile(targetPath)
|
||||
return
|
||||
}
|
||||
// 主题验证
|
||||
if ok, msg = this.ValidateTheme(targetPath, "", ""); !ok {
|
||||
DeleteFile(targetPath)
|
||||
return
|
||||
}
|
||||
// 解压成功, 那么新建之
|
||||
// 保存到数据库中
|
||||
theme, _ := this.getThemeConfig(targetPath)
|
||||
if theme.Name == "" {
|
||||
ok = false
|
||||
DeleteFile(targetPath)
|
||||
msg = "解析错误"
|
||||
return
|
||||
}
|
||||
theme.ThemeId = themeIdO
|
||||
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||
theme.CreatedTime = time.Now()
|
||||
theme.UpdatedTime = theme.CreatedTime
|
||||
theme.UserId = bson.ObjectIdHex(userId)
|
||||
|
||||
ok = db.Insert(db.Themes, theme)
|
||||
if !ok {
|
||||
DeleteFile(targetPath)
|
||||
}
|
||||
DeleteFile(path)
|
||||
return
|
||||
}
|
||||
|
||||
// 升级用
|
||||
// public/
|
||||
|
||||
func (this *ThemeService) UpgradeThemeBeta2() (ok bool) {
|
||||
adminUserId := configService.GetAdminUserId()
|
||||
this.upgradeThemeBeta2(adminUserId, defaultStyle, true)
|
||||
this.upgradeThemeBeta2(adminUserId, elegantStyle, false)
|
||||
this.upgradeThemeBeta2(adminUserId, fixedStyle, false)
|
||||
return true
|
||||
}
|
||||
func (this *ThemeService) upgradeThemeBeta2(userId, style string, isActive bool) (ok bool) {
|
||||
// 解压成功, 那么新建之
|
||||
// 保存到数据库中
|
||||
targetPath := this.GetDefaultThemePath(style)
|
||||
theme, _ := this.getThemeConfig(revel.BasePath + "/" + targetPath)
|
||||
if theme.Name == "" {
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
themeIdO := bson.NewObjectId()
|
||||
theme.ThemeId = themeIdO
|
||||
theme.Path = targetPath // public
|
||||
theme.CreatedTime = time.Now()
|
||||
theme.UpdatedTime = theme.CreatedTime
|
||||
theme.UserId = bson.ObjectIdHex(userId)
|
||||
theme.IsActive = isActive
|
||||
theme.IsDefault = true
|
||||
theme.Style = style
|
||||
ok = db.Insert(db.Themes, theme)
|
||||
return ok
|
||||
}
|
||||
|
||||
// 安装主题
|
||||
// 得到该主题路径
|
||||
func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) {
|
||||
theme := this.GetThemeById(themeId)
|
||||
// 不是默认主题, 即不是admin用户的主题, 不能乱安装
|
||||
if !theme.IsDefault {
|
||||
return false
|
||||
}
|
||||
|
||||
// 用户之前是否有主题?
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
if userBlog.ThemeId == "" {
|
||||
this.NewThemeForFirst(userBlog)
|
||||
}
|
||||
|
||||
// 生成新主题
|
||||
newThemeId := bson.NewObjectId()
|
||||
themeId = newThemeId.Hex()
|
||||
themePath := this.getUserThemePath(userId, themeId)
|
||||
err := os.MkdirAll(themePath, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 复制默认主题
|
||||
sourceThemePath := revel.BasePath + "/" + theme.Path
|
||||
err = CopyDir(sourceThemePath, themePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 保存到数据库中
|
||||
theme, _ = this.getThemeConfig(themePath)
|
||||
theme.ThemeId = newThemeId
|
||||
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||
theme.CreatedTime = time.Now()
|
||||
theme.UpdatedTime = theme.CreatedTime
|
||||
theme.UserId = bson.ObjectIdHex(userId)
|
||||
|
||||
ok = db.Insert(db.Themes, theme)
|
||||
|
||||
// 激活之
|
||||
this.ActiveTheme(userId, themeId);
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// 验证主题是否全法, 存在循环引用?
|
||||
// filename, newContent 表示在修改模板时要判断模板修改时是否有错误
|
||||
func (this *ThemeService) ValidateTheme(path string, filename, newContent string) (ok bool, msg string) {
|
||||
Log("theme Path")
|
||||
Log(path)
|
||||
// 建立一个有向图
|
||||
// 将该path下的所有文件提出, 得到文件的引用情况
|
||||
files := ListDir(path)
|
||||
LogJ(files);
|
||||
size := len(files)
|
||||
if(size > 100) {
|
||||
ok = false;
|
||||
msg = "tooManyFiles"
|
||||
return
|
||||
}
|
||||
/*
|
||||
111111111
|
||||
111000000
|
||||
*/
|
||||
vector := make([][]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
vector[i] = make([]int, size)
|
||||
}
|
||||
fileIndexMap := map[string]int{} // fileName => index
|
||||
fileContent := map[string]string{} // fileName => content
|
||||
index := 0
|
||||
// 得到文件内容, 和建立索引, 每个文件都有一个index, 对应数组位置
|
||||
for _, t := range files {
|
||||
if !strings.Contains(t, ".html") {
|
||||
continue;
|
||||
}
|
||||
if t != filename {
|
||||
fileBytes, err := ioutil.ReadFile(path + "/" + t)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fileIndexMap[t] = index;
|
||||
// html内容
|
||||
fileStr := string(fileBytes)
|
||||
fileContent[t] = fileStr
|
||||
} else {
|
||||
fileIndexMap[t] = index
|
||||
fileContent[t] = newContent
|
||||
}
|
||||
index++
|
||||
}
|
||||
// 分析文件内容, 建立有向图
|
||||
reg, _ := regexp.Compile("{{ *template \"(.+?\\.html)\".*}}")
|
||||
for filename, content := range fileContent {
|
||||
thisIndex := fileIndexMap[filename]
|
||||
finds := reg.FindAllStringSubmatch(content, -1) // 子匹配
|
||||
LogJ(finds)
|
||||
// Log(content)
|
||||
if finds != nil && len(finds) > 0 {
|
||||
for _, includes := range finds {
|
||||
include := includes[1]
|
||||
includeIndex, has := fileIndexMap[include]
|
||||
Log(includeIndex)
|
||||
Log("??")
|
||||
Log(has)
|
||||
if has {
|
||||
vector[thisIndex][includeIndex] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogJ(vector)
|
||||
LogJ(fileIndexMap)
|
||||
// 建立图后, 判断是否有环
|
||||
if this.hasRound(vector, index) {
|
||||
ok = false
|
||||
msg = "themeValidHasRoundInclude"
|
||||
} else {
|
||||
ok = true
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 检测有向图是否有环, DFS
|
||||
func (this *ThemeService) hasRound(vector [][]int, size int) (ok bool) {
|
||||
for i := 0; i < size; i++ {
|
||||
visited := make([]int, size)
|
||||
if this.hasRoundEach(vector, i, size, visited) {
|
||||
Log(">>")
|
||||
Log(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 从每个节点出发, 判断是否有环
|
||||
func (this *ThemeService) hasRoundEach(vector [][]int, index int, size int, visited []int) (ok bool) {
|
||||
if visited[index] > 0 {
|
||||
Log("<")
|
||||
Log(index)
|
||||
return true
|
||||
}
|
||||
visited[index] = 1;
|
||||
// 遍历它的孩子
|
||||
for i := 0; i < size; i++ {
|
||||
if vector[index][i] > 0 {
|
||||
return this.hasRoundEach(vector, i, size, visited);
|
||||
}
|
||||
}
|
||||
visited[index] = 0;
|
||||
return false;
|
||||
}
|
||||
@@ -19,9 +19,86 @@ func (this *UpgradeService) UpgradeBlog() bool {
|
||||
|
||||
// PublicTime, RecommendTime = UpdatedTime
|
||||
for _, note := range notes {
|
||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||
Log(note.NoteId.Hex())
|
||||
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||
Log(note.NoteId.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 11-5自定义博客升级, 将aboutMe移至pages
|
||||
/*
|
||||
<li>Migrate "About me" to single(a single post)</li>
|
||||
<li>Add some default themes to administrator</li>
|
||||
<li>Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post</li>
|
||||
<li>Generate "UrlTitle" for all notebooks</li>
|
||||
<li>Generate "UrlTitle" for all singles</li>
|
||||
*/
|
||||
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
||||
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
||||
return false, "已升级"
|
||||
}
|
||||
|
||||
// 1. aboutMe -> page
|
||||
userBlogs := []info.UserBlog{}
|
||||
db.ListByQ(db.UserBlogs, bson.M{}, &userBlogs)
|
||||
|
||||
for _, userBlog := range userBlogs {
|
||||
blogService.AddOrUpdateSingle(userBlog.UserId.Hex(), "", "About Me", userBlog.AboutMe)
|
||||
}
|
||||
|
||||
// 2. 默认主题, 给admin用户
|
||||
themeService.UpgradeThemeBeta2()
|
||||
|
||||
// 3. UrlTitles
|
||||
|
||||
// 3.1 note
|
||||
notes := []info.Note{}
|
||||
db.ListByQ(db.Notes, bson.M{}, ¬es)
|
||||
for _, note := range notes {
|
||||
data := bson.M{}
|
||||
noteId := note.NoteId.Hex()
|
||||
// PublicTime, RecommendTime = UpdatedTime
|
||||
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||
data["PublicTime"] = note.UpdatedTime
|
||||
data["RecommendTime"] = note.UpdatedTime
|
||||
Log("Time " + noteId)
|
||||
}
|
||||
data["UrlTitle"] = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, data)
|
||||
Log(noteId)
|
||||
}
|
||||
|
||||
// 3.2
|
||||
Log("notebook")
|
||||
notebooks := []info.Notebook{}
|
||||
db.ListByQ(db.Notebooks, bson.M{}, ¬ebooks)
|
||||
for _, notebook := range notebooks {
|
||||
notebookId := notebook.NotebookId.Hex()
|
||||
data := bson.M{}
|
||||
data["UrlTitle"] = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||
db.UpdateByIdAndUserIdMap2(db.Notebooks, notebook.NotebookId, notebook.UserId, data)
|
||||
Log(notebookId)
|
||||
}
|
||||
|
||||
// 3.3 single
|
||||
/*
|
||||
singles := []info.BlogSingle{}
|
||||
db.ListByQ(db.BlogSingles, bson.M{}, &singles)
|
||||
for _, single := range singles {
|
||||
singleId := single.SingleId.Hex()
|
||||
blogService.UpdateSingleUrlTitle(single.UserId.Hex(), singleId, single.Title)
|
||||
Log(singleId)
|
||||
}
|
||||
*/
|
||||
|
||||
// 删除索引
|
||||
db.ShareNotes.DropIndex("UserId", "ToUserId", "NoteId")
|
||||
ok = true
|
||||
msg = "success"
|
||||
configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToBeta2", "1")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func (this *UserService) AddUser(user info.User) bool {
|
||||
go func() {
|
||||
emailService.RegisterSendActiveEmail(user, user.Email)
|
||||
// 发送给我 life@leanote.com
|
||||
// emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
||||
emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
||||
}();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,20 @@ func (this *UserService) GetUserId(email string) string {
|
||||
return user.UserId.Hex()
|
||||
}
|
||||
|
||||
// 得到用户名
|
||||
func (this *UserService) GetUsername(userId string) string {
|
||||
user := info.User{}
|
||||
db.GetByQWithFields(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, []string{"Username"}, &user)
|
||||
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
|
||||
func (this *UserService) IsExistsUser(email string) bool {
|
||||
if this.GetUserId(email) == "" {
|
||||
@@ -75,7 +89,7 @@ func (this *UserService) setUserLogo(user *info.User) {
|
||||
}
|
||||
if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") {
|
||||
user.Logo = strings.Trim(user.Logo, "/")
|
||||
user.Logo = siteUrl + "/" + user.Logo
|
||||
user.Logo = configService.GetSiteUrl() + "/" + user.Logo
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +147,58 @@ func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectI
|
||||
return this.MapUserInfoByUserIds(userIds)
|
||||
}
|
||||
|
||||
// 返回info.UserAndBlog
|
||||
func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[string]info.UserAndBlog {
|
||||
users := []info.User{}
|
||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||
|
||||
userBlogs := []info.UserBlog{}
|
||||
db.ListByQ(db.UserBlogs, bson.M{"_id": bson.M{"$in": userIds}}, &userBlogs)
|
||||
|
||||
userBlogMap := make(map[bson.ObjectId]info.UserBlog, len(userBlogs))
|
||||
for _, user := range userBlogs {
|
||||
userBlogMap[user.UserId] = user
|
||||
}
|
||||
|
||||
userAndBlogMap := make(map[string]info.UserAndBlog, len(users))
|
||||
|
||||
for _, user := range users {
|
||||
this.setUserLogo(&user)
|
||||
|
||||
userBlog, ok := userBlogMap[user.UserId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
userAndBlogMap[user.UserId.Hex()] = info.UserAndBlog{
|
||||
UserId: user.UserId,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Logo: user.Logo,
|
||||
BlogTitle: userBlog.Title,
|
||||
BlogLogo: userBlog.Logo,
|
||||
BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username),
|
||||
}
|
||||
}
|
||||
return userAndBlogMap
|
||||
}
|
||||
|
||||
// 得到userAndBlog公开信息
|
||||
func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog {
|
||||
user := this.GetUserInfo(userId)
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
return info.UserAndBlog{
|
||||
UserId: user.UserId,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Logo: user.Logo,
|
||||
BlogTitle: userBlog.Title,
|
||||
BlogLogo: userBlog.Logo,
|
||||
BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username),
|
||||
BlogUrls: blogService.GetBlogUrls(&userBlog, &user),
|
||||
}
|
||||
}
|
||||
|
||||
// 通过ids得到users, 按id的顺序组织users
|
||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||
users := []info.User{}
|
||||
@@ -143,9 +209,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
||||
usersMap[user.UserId] = user
|
||||
}
|
||||
|
||||
hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的
|
||||
users2 := []info.User{};
|
||||
for _, userId := range userIds {
|
||||
if user, ok := usersMap[userId]; ok {
|
||||
if user, ok := usersMap[userId]; ok && !hasAppend[userId] {
|
||||
hasAppend[userId] = true
|
||||
users2 = append(users2, user)
|
||||
}
|
||||
}
|
||||
@@ -169,7 +237,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
||||
// 更新username
|
||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||
return false, "用户已存在"
|
||||
return false, "usernameIsExisted"
|
||||
}
|
||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||
username = strings.ToLower(username)
|
||||
@@ -177,7 +245,7 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
||||
// 先判断是否存在
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
||||
return false, "用户已存在"
|
||||
return false, "usernameIsExisted"
|
||||
}
|
||||
|
||||
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
||||
@@ -195,18 +263,42 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||
userInfo := this.GetUserInfo(userId)
|
||||
if userInfo.Pwd != Md5(oldPwd) {
|
||||
return false, "旧密码错误"
|
||||
return false, "oldPasswordError"
|
||||
}
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
// 管理员重置密码
|
||||
func (this *UserService) ResetPwd(adminUserId, userId, pwd string) (ok bool, msg string) {
|
||||
if configService.GetAdminUserId() != adminUserId {
|
||||
return
|
||||
}
|
||||
ok = db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||
return
|
||||
}
|
||||
|
||||
// 修改主题
|
||||
func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
||||
return ok
|
||||
}
|
||||
|
||||
// 帐户类型设置
|
||||
func (this *UserService) UpdateAccount(userId, accountType string, accountStartTime, accountEndTime time.Time,
|
||||
maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) bool {
|
||||
return db.UpdateByQI(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, info.UserAccount{
|
||||
AccountType: accountType,
|
||||
AccountStartTime: accountStartTime,
|
||||
AccountEndTime: accountEndTime,
|
||||
MaxImageNum: maxImageNum,
|
||||
MaxImageSize: maxImageSize,
|
||||
MaxAttachNum: maxAttachNum,
|
||||
MaxAttachSize: maxAttachSize,
|
||||
MaxPerAttachSize: maxPerAttachSize,
|
||||
})
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 修改email
|
||||
|
||||
@@ -261,6 +353,13 @@ func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string)
|
||||
//---------
|
||||
// 第三方添加账号
|
||||
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
||||
// 判断该用户是否已有了帐户
|
||||
userInfo := this.GetUserInfo(userId)
|
||||
if userInfo.Email != "" {
|
||||
msg = "你已有帐户"
|
||||
return
|
||||
}
|
||||
|
||||
// 判断email是否存在
|
||||
if this.IsExistsUser(email) {
|
||||
msg = "该用户已存在"
|
||||
@@ -277,7 +376,7 @@ func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg s
|
||||
// 宽度
|
||||
func (this *UserService)UpdateColumnWidth(userId string, notebookWidth, noteListWidth, mdEditorWidth int) bool {
|
||||
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||
bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth, "mdEditorWidth": mdEditorWidth})
|
||||
bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth, "MdEditorWidth": mdEditorWidth})
|
||||
}
|
||||
// 左侧是否隐藏
|
||||
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
|
||||
@@ -291,7 +390,11 @@ func (this *UserService) ListUsers(pageNumber, pageSize int, sortField string, i
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
query := bson.M{}
|
||||
if email != "" {
|
||||
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
|
||||
orQ := []bson.M{
|
||||
bson.M{"Email": bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}},
|
||||
bson.M{"Username": bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}},
|
||||
}
|
||||
query["$or"] = orQ
|
||||
}
|
||||
q := db.Users.Find(query);
|
||||
// 总记录数
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"regexp"
|
||||
"strings"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"gopkg.in/mgo.v2"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
// init service, for share service bettween services
|
||||
@@ -14,6 +20,7 @@ var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService
|
||||
var trashService, TrashS *TrashService
|
||||
var shareService, ShareS *ShareService
|
||||
var userService, UserS *UserService
|
||||
var groupService, GroupS *GroupService
|
||||
var tagService, TagS *TagService
|
||||
var blogService, BlogS *BlogService
|
||||
var tokenService, TokenS *TokenService
|
||||
@@ -28,8 +35,7 @@ var emailService, EmailS *EmailService
|
||||
var AuthS *AuthService
|
||||
var UpgradeS *UpgradeService
|
||||
var SessionS, sessionService *SessionService
|
||||
|
||||
var siteUrl string
|
||||
var ThemeS, themeService *ThemeService
|
||||
|
||||
// onAppStart调用
|
||||
func InitService() {
|
||||
@@ -39,6 +45,7 @@ func InitService() {
|
||||
TrashS = &TrashService{}
|
||||
ShareS = &ShareService{}
|
||||
UserS = &UserService{}
|
||||
GroupS = &GroupService{}
|
||||
TagS = &TagService{}
|
||||
BlogS = &BlogService{}
|
||||
TokenS = &TokenService{}
|
||||
@@ -53,6 +60,7 @@ func InitService() {
|
||||
EmailS = NewEmailService()
|
||||
UpgradeS = &UpgradeService{}
|
||||
SessionS = &SessionService{}
|
||||
ThemeS = &ThemeService{}
|
||||
|
||||
notebookService = NotebookS
|
||||
noteService = NoteS
|
||||
@@ -60,6 +68,7 @@ func InitService() {
|
||||
trashService = TrashS
|
||||
shareService = ShareS
|
||||
userService = UserS
|
||||
groupService = GroupS
|
||||
tagService = TagS
|
||||
blogService = BlogS
|
||||
tokenService = TokenS
|
||||
@@ -70,7 +79,72 @@ func InitService() {
|
||||
configService = ConfigS
|
||||
emailService = EmailS
|
||||
sessionService = SessionS
|
||||
themeService = ThemeS
|
||||
}
|
||||
|
||||
//----------------
|
||||
// service 公用方法
|
||||
|
||||
// 将name=val的val进行encoding
|
||||
func decodeValue(val string) string {
|
||||
v, _ := url.ParseQuery("a=" + val)
|
||||
return v.Get("a")
|
||||
}
|
||||
|
||||
func encodeValue(val string) string {
|
||||
if val == "" {
|
||||
return val
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("", val)
|
||||
return v.Encode()[1:]
|
||||
}
|
||||
// 添加笔记时通过title得到urlTitle
|
||||
func fixUrlTitle(urlTitle string) string {
|
||||
if urlTitle != "" {
|
||||
// 把特殊字段给替换掉
|
||||
// str := `life "%&()+,/:;<>=?@\|`
|
||||
reg, _ := regexp.Compile("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
|
||||
urlTitle = reg.ReplaceAllString(urlTitle, "-")
|
||||
urlTitle = strings.Trim(urlTitle, "-") // 左右单独的-去掉
|
||||
// 把空格替换成-
|
||||
// urlTitle = strings.Replace(urlTitle, " ", "-", -1)
|
||||
for strings.Index(urlTitle, "--") >= 0 { // 防止出现连续的--
|
||||
urlTitle = strings.Replace(urlTitle, "--", "-", -1)
|
||||
}
|
||||
return encodeValue(urlTitle)
|
||||
}
|
||||
return urlTitle
|
||||
}
|
||||
|
||||
func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int) string {
|
||||
urlTitle2 := urlTitle
|
||||
if padding > 1 {
|
||||
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
||||
}
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
|
||||
//
|
||||
siteUrl, _ = revel.Config.String("site.url")
|
||||
}
|
||||
var collection *mgo.Collection
|
||||
if types == "note" {
|
||||
collection = db.Notes
|
||||
} else if types == "notebook" {
|
||||
collection = db.Notebooks
|
||||
} else if types == "single" {
|
||||
collection = db.BlogSingles
|
||||
}
|
||||
for db.Has(collection, bson.M{"UserId": userIdO, "UrlTitle": urlTitle2}) { // 用户下唯一
|
||||
padding++
|
||||
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
||||
}
|
||||
|
||||
return urlTitle2
|
||||
}
|
||||
// types == note,notebook,single
|
||||
func GetUrTitle(userId string, title string, types string) string {
|
||||
urlTitle := strings.Trim(title, " ")
|
||||
if urlTitle == "" {
|
||||
urlTitle = "Untitled-" + userId
|
||||
}
|
||||
urlTitle = fixUrlTitle(urlTitle)
|
||||
return getUniqueUrlTitle(userId, urlTitle, types, 1)
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link href="/public/mobile2/topcoat/css/topcoat-mobile-light.min.css" rel="stylesheet">
|
||||
<link href="/public/mobile2/css/styles.css" rel="stylesheet">
|
||||
<link href="/public/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body ng-controller="MainCtrl">
|
||||
|
||||
<div id="sidebar" class="page-sidebar">
|
||||
<h1>leanote</h1>
|
||||
<ul id="nav">
|
||||
<li ng-click="go('/notes/all')"><a>[[msg.all]]</a></li>
|
||||
<li ng-click="go('/notebooks')"><a>[[msg.notebook]]</a></li>
|
||||
<li><a href="#">[[msg.tag]]</a></li>
|
||||
</ul>
|
||||
<footer>
|
||||
<a href="/mobile/logout">[[msg.logout]]</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div id="content" class="page-content">
|
||||
<div ng-view ng-class="slide" >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/i18n/msg.{{.locale}}.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
|
||||
<script src="/public/js/angular/angular.min.js"></script>
|
||||
<script src="/public/js/angular/angular-touch.min.js"></script>
|
||||
<script src="/public/js/angular/angular-resource.min.js"></script>
|
||||
<script src="/public/js/angular/angular-animate.min.js"></script>
|
||||
<script src="/public/js/angular/angular-route.min.js"></script>
|
||||
<script src="/public/mobile2/js/app.js"></script>
|
||||
<script src="/public/mobile2/js/controllers.js"></script>
|
||||
<script src="/public/mobile2/js/services.js"></script>
|
||||
<script src="/public/mobile2/js/snap.js"></script>
|
||||
<script>
|
||||
angular.element(document).ready(function() {
|
||||
angular.bootstrap(document, ['myApp']);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,178 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<title>leanote</title>
|
||||
<link href="/public/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/mobile/css/base.css" rel="stylesheet" type="text/css">
|
||||
<link href="/public/css/bootstrap.css" rel="stylesheet" />
|
||||
<link href="/public/mobile/css/leanote.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
// console.log(o);
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="preloader">
|
||||
<div id="status">
|
||||
<p class="center-text">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="all-elements" style="height: 100%">
|
||||
<div id="sidebar" class="page-sidebar sidebar-content-background">
|
||||
<div class="page-sidebar-scroll">
|
||||
<div>
|
||||
<div class="sidebar-section">
|
||||
<a href="#" class="sidebar-close"></a>
|
||||
<em>leanote</em>
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
<div id="userInfo">
|
||||
{{.userInfo.Username}}
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
|
||||
<div class="sidebar-navigation">
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-newest">最新笔记</a>
|
||||
</div>
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-myNotebooks">我的笔记本</a>
|
||||
</div>
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-myTags">我的标签</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
<div class="sidebar-navigation">
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-logout">退出</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="page-content" style="position: absolute; background-color: #fff;width: 100%;">
|
||||
<!-- notebooks -->
|
||||
<div id="notebooks">
|
||||
<!-- 头部 -->
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
我的笔记本
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom: 0">
|
||||
<ul id="notebookList">
|
||||
</ul>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
添加笔记本
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- note -->
|
||||
<div id="notes">
|
||||
<!-- 头部 -->
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
XX的笔记
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom:0">
|
||||
<div id="noteItemList">
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
添加笔记
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- view -->
|
||||
<div id="view">
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
笔记标题
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
<i class="fa fa-pencil" id="editBtn"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom:0">
|
||||
<img id="loading" style="width: 30px; margin: auto; margin-top: 100px; height: 30px; display: none" src="/public/mobile/images/status.gif" />
|
||||
<div id="noteContent"></div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/public/mobile/js/snap.js"></script>
|
||||
<script src="/public/js/i18n/msg.{{.locale}}.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-common.js"></script>
|
||||
<script>
|
||||
var UserInfo = json({{.userInfoJson}});
|
||||
var notebooks = json({{.notebooks}});
|
||||
</script>
|
||||
<!--
|
||||
// var shareNotebooks = json({{.shareNotebooks}});
|
||||
// var sharedUserInfos = json({{.sharedUserInfos}});
|
||||
// var tagsJson = json({{.tagsJson}});
|
||||
-->
|
||||
<script src="/public/mobile/js/app/mobile-notebook.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-tag.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-note.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-page.js"></script>
|
||||
<script>
|
||||
Notebook.RenderNotebooks(notebooks);
|
||||
// Share.RenderShareNotebooks(sharedUserInfos, shareNotebooks);
|
||||
// Tag.renderTagNav(tagsJson);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,96 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<title>leanote sign in</title>
|
||||
|
||||
<link href="/public/css/font-awesome-4.0.3/css/font-awesome.css" rel="mobile/csssheet">
|
||||
<link href="/public/css/bootstrap.css" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
.alert {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.form-control {
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-transition: nonoe;
|
||||
transition: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="text-align: center">
|
||||
<img src="/public/mobile/images/blog01.jpg" style="width: 100%"/>
|
||||
<form id="loginForm" style="width: 90%; margin: auto;">
|
||||
<div class="form-group">
|
||||
<h2 style="margin-top:10px">leanote {{msg . "login"}}</h2>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="loginMsg" style="display: none"></div>
|
||||
<div class="form-group">
|
||||
<input class="form-control" id="email" name="email" placeholder="{{msg . "usernameOrEmail"}}" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="pwd" name="pwd" placeholder="{{msg . "password"}}">
|
||||
</div>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "login"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/public/js/jquery-1.9.0.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$("#status").fadeOut(); // will first fade out the loading animation
|
||||
$("#preloader").delay(350).fadeOut("slow"); // will fade out the white DIV that covers the website.
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#loginBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
var email = $("#email").val();
|
||||
var pwd = $("#pwd").val();
|
||||
if(!email) {
|
||||
showMsg("{{msg . "inputUsername"}}", "email");
|
||||
return;
|
||||
}
|
||||
if(!pwd) {
|
||||
showMsg("{{msg . "inputPassword"}}", "pwd");
|
||||
return;
|
||||
} else {
|
||||
if(pwd.length < 6) {
|
||||
showMsg("{{msg . "wrongPassword"}}", "pwd");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#loginBtn").html("{{msg . "logining"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/doLogin", {email: email, pwd: pwd}, function(e) {
|
||||
$("#loginBtn").html("{{msg . "login"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
$("#loginBtn").html("{{msg . "loginSuccess"}}...");
|
||||
location.href = '/mobile/index';
|
||||
} else {
|
||||
showMsg(e.Msg, "pwd");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,71 +0,0 @@
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">{{msg . "share"}} <b>{{.title}}</b></h4>
|
||||
</div>
|
||||
{{$noteOrNotebookId := .noteOrNotebookId}}
|
||||
|
||||
<div class="modal-body">
|
||||
<button class="btn btn-default" id="addShareNotebookBtn">{{msg . "addShare"}}</button>
|
||||
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
||||
<table class="table table-hover" id="shareNotebookTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>{{msg . "friendEmail"}}</th>
|
||||
<th>{{msg . "permission"}}</th>
|
||||
<th width="150px">{{msg . "delete"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="tr1">
|
||||
<td>#</td>
|
||||
<td>
|
||||
<input id="friendsEmail" type="text" class="form-control" placeholder="{{msg . "friendEmail"}}">
|
||||
</td>
|
||||
<td>
|
||||
<label for="readPerm1"><input type="radio" name="perm1" checked="checked" value="0" id="readPerm1"> {{msg . "readOnly"}}</label>
|
||||
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> {{msg . "writable"}}</label>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-success" onclick="addShareNoteOrNotebook(1)">{{msg . "share"}}</button>
|
||||
<button class="btn btn-warning" onclick="deleteShareNoteOrNotebook(1)">{{msg . "delete"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{range $i, $v := .noteOrNotebookShareUserInfos}}
|
||||
{{$toUserId := $v.ToUserId.Hex}}
|
||||
<tr>
|
||||
<td>{{add $i}}</td>
|
||||
<td>{{$v.Email}}</td>
|
||||
<td>
|
||||
{{if eq $v.Perm 0}}
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "readOnly"}}</a>
|
||||
{{else}}
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "writable"}}</a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">{{msg . "delete"}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
Share.dialogIsNote = {{.isNote}};
|
||||
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
||||
$(function() {
|
||||
setTimeout(function() {
|
||||
$("#tr1 #friendsEmail").focus();
|
||||
}, 500);
|
||||
});
|
||||
</script>
|
||||
@@ -1,84 +0,0 @@
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">{{.note.Title}} 的分享状态</h4>
|
||||
</div>
|
||||
{{$noteId := .note.NoteId.Hex}}
|
||||
|
||||
<div class="modal-body">
|
||||
{{if .noteShareUserInfos }}
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Email</th>
|
||||
<th>权限</th>
|
||||
<th>删除分享</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i, $v := .noteShareUserInfos}}
|
||||
{{$toUserId := $v.ToUserId.Hex}}
|
||||
<tr>
|
||||
<td>{{add $i}}</td>
|
||||
<td>{{$v.Email}}</td>
|
||||
<td>
|
||||
{{if eq $v.Perm 0}}
|
||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">只读</a>
|
||||
{{else}}
|
||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">可编辑</a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" noteId="{{$noteId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
无分享信息
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
$(function() {
|
||||
$(".change-perm").click(function() {
|
||||
var self = this;
|
||||
var perm = $(this).attr("perm");
|
||||
var noteId = $(this).attr("noteId");
|
||||
var toUserId = $(this).attr("toUserId");
|
||||
var toHtml = "可编辑";
|
||||
var toPerm = "1";
|
||||
if(perm == "1") {
|
||||
toHtml = "只读";
|
||||
toPerm = "0";
|
||||
}
|
||||
ajaxGet("/share/UpdateShareNotePerm", {noteId: noteId, perm: toPerm, toUserId: toUserId}, function(ret) {
|
||||
if(ret) {
|
||||
$(self).html(toHtml);
|
||||
$(self).attr("perm", toPerm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(".delete-share").click(function() {
|
||||
var self = this;
|
||||
var noteId = $(this).attr("noteId");
|
||||
var toUserId = $(this).attr("toUserId");
|
||||
ajaxGet("/share/DeleteShareNote", {noteId: noteId, toUserId: toUserId}, function(ret) {
|
||||
if(ret) {
|
||||
$(self).parent().parent().remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -97,9 +97,6 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-4 text-center">
|
||||
<small class="text-muted inline m-t-sm m-b-sm">
|
||||
showing 20-30 of 50 items
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-sm-4 text-right text-center-xs">
|
||||
{{set . "url" (urlConcat "/adminBlog/index" "sorter" .sorter "keywords" .keywords)}}
|
||||
@@ -10,7 +10,7 @@
|
||||
<title>{{.title}}</title>
|
||||
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/admin.css" rel="stylesheet">
|
||||
<style>
|
||||
</style>
|
||||
@@ -128,10 +128,18 @@
|
||||
</i>
|
||||
</span>
|
||||
<span>
|
||||
Setting
|
||||
Configuration
|
||||
</span>
|
||||
</a>
|
||||
<ul class="nav lt">
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/home_page">
|
||||
<span>
|
||||
Home Page
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/demo">
|
||||
<span>
|
||||
@@ -141,7 +149,7 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/openRegister">
|
||||
<a href="/admin/t?t=setting/open_register">
|
||||
<span>
|
||||
Open Register
|
||||
</span>
|
||||
@@ -155,6 +163,14 @@
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/upload">
|
||||
<span>
|
||||
Upload File Size Limit
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -192,5 +208,32 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<i class="fa fa-space-shuttle icon">
|
||||
<b class="bg-danger">
|
||||
</b>
|
||||
</i>
|
||||
<span class="pull-right">
|
||||
<i class="fa fa-angle-down text">
|
||||
</i>
|
||||
<i class="fa fa-angle-up text-active">
|
||||
</i>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
Upgrade
|
||||
</span>
|
||||
</a>
|
||||
<ul class="nav lt">
|
||||
<li>
|
||||
<a href="/admin/t?t=upgrade/beta2">
|
||||
<span>
|
||||
v1.0-beta to v1.0-beta2
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
49
app/views/admin/setting/home_page.html
Normal file
49
app/views/admin/setting/home_page.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<div class="m-b-md"> <h3 class="m-b-none">Home Page</h3></div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-6">
|
||||
<form id="form_data">
|
||||
<section class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label><a href="/blog" target="_blank">Admin's Blog Page</a></label>
|
||||
<input type="radio" class="form-control" name="homePage" {{if not .str.homePage}}checked="checked"{{end}} value="0">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label><a href="/index" target="_blank">Index Page</a></label>
|
||||
<input type="radio" class="form-control" name="homePage" {{if .str.homePage}}checked="checked"{{end}} value="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="panel-footer text-right bg-light lter">
|
||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||
</footer>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "admin/footer.html" .}}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#submit").click(function(e){
|
||||
e.preventDefault();
|
||||
var t = this;
|
||||
$(t).button('loading');
|
||||
ajaxPost("/adminSetting/homePage", getFormJsonData("form_data"), function(ret){
|
||||
$(t).button('reset');
|
||||
if(!ret.Ok) {
|
||||
art.alert(ret.Msg);
|
||||
} else {
|
||||
art.tips("Success");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{{template "admin/end.html" .}}
|
||||
65
app/views/admin/setting/upload.html
Normal file
65
app/views/admin/setting/upload.html
Normal file
@@ -0,0 +1,65 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<div class="m-b-md"> <h3 class="m-b-none">Upload File Size Limit</h3></div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-6">
|
||||
<form id="add_user_form">
|
||||
<section class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label>Image</label>
|
||||
<input type="text" class="form-control" name="uploadImageSize" value="{{.str.uploadImageSize}}">
|
||||
MB. Default is unlimit;
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Avatar</label>
|
||||
<input type="text" class="form-control" name="uploadAvatarSize" value="{{.str.uploadAvatarSize}}">
|
||||
MB. Default is unlimit;
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Blog Logo</label>
|
||||
<input type="text" class="form-control" name="uploadBlogLogoSize" value="{{.str.uploadBlogLogoSize}}">
|
||||
MB. Default is unlimit;
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Attachment</label>
|
||||
<input type="text" class="form-control" name="uploadAttachSize" value="{{.str.uploadAttachSize}}">
|
||||
MB. Default is unlimit;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="panel-footer text-right bg-light lter">
|
||||
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||
</footer>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "admin/footer.html" .}}
|
||||
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
init_validator("#add_user_form");
|
||||
|
||||
$("#submit").click(function(e){
|
||||
e.preventDefault();
|
||||
var t = this;
|
||||
if($("#add_user_form").valid()) {
|
||||
$(t).button('loading');
|
||||
ajaxPost("/adminSetting/uploadSize", getFormJsonData("add_user_form"), function(ret){
|
||||
$(t).button('reset')
|
||||
if(!ret.Ok) {
|
||||
art.alert(ret.Msg)
|
||||
} else {
|
||||
art.tips("Success");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{{template "admin/end.html" .}}
|
||||
@@ -7,7 +7,7 @@
|
||||
</title>
|
||||
<meta name="description" content="leanote admin"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/bootstrap.3.2.0.min.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/admin.css" rel="stylesheet">
|
||||
<!--[if lt IE 9]>
|
||||
@@ -84,7 +84,7 @@
|
||||
</section>
|
||||
<footer class="footer lt hidden-xs b-t b-light" style="min-height: initial;
|
||||
padding: 10px 15px;text-align:center;">
|
||||
<a href="http://leanote.com" target="_blank">leanote</a> © 2014
|
||||
<a href="http://leanote.com" target="_blank">leanote</a> © 2015
|
||||
<!--
|
||||
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
|
||||
<i class="fa fa-angle-left text">
|
||||
47
app/views/admin/upgrade/beta2.html
Normal file
47
app/views/admin/upgrade/beta2.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<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="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>Migrate "About me" to single(a single post)</li>
|
||||
<li>Add some default themes to administrator</li>
|
||||
<li>Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post</li>
|
||||
<li>Generate "UrlTitle" for all notebooks</li>
|
||||
<li>Generate "UrlTitle" for all singles</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</button>
|
||||
</footer>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "admin/footer.html" .}}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#submit").click(function(e){
|
||||
e.preventDefault();
|
||||
var t = this;
|
||||
$(t).button('loading');
|
||||
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
||||
$(t).button('reset')
|
||||
if(!ret.Ok) {
|
||||
art.alert(ret.Msg)
|
||||
} else {
|
||||
art.tips("Success");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{{template "admin/end.html" .}}
|
||||
@@ -42,7 +42,7 @@ $(function() {
|
||||
var t = this;
|
||||
if($("#add_user_form").valid()) {
|
||||
$(t).button('loading');
|
||||
ajaxPost("/auth/doRegister", getFormJsonData("add_user_form"), function(ret){
|
||||
ajaxPost("/adminUser/register", getFormJsonData("add_user_form"), function(ret){
|
||||
$(t).button('reset')
|
||||
if(!ret.Ok) {
|
||||
art.alert(ret.Msg);
|
||||
@@ -4,16 +4,8 @@
|
||||
<section class="panel panel-default">
|
||||
<div class="row wrapper">
|
||||
<div class="col-sm-5 m-b-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Send Email
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default bulk-btn">
|
||||
Apply
|
||||
<button class="btn btn-sm btn-default bulk-email">
|
||||
Send Email
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-4 m-b-xs">
|
||||
@@ -21,7 +13,7 @@
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="input-group search-group">
|
||||
<input type="text" class="input-sm form-control" placeholder="Email" id="keywords" value="{{.keywords}}" />
|
||||
<input type="text" class="input-sm form-control" placeholder="Username or Email" id="keywords" value="{{.keywords}}" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-sm btn-default" type="button" data-url="/adminUser/index">Search</button>
|
||||
</span>
|
||||
@@ -99,7 +91,8 @@
|
||||
{{.CreatedTime|datetime}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-default send-email" data-email="{{.Email}}">Send Email</a>
|
||||
<a href="#" class="btn btn-sm btn-default reset-pwd" data-id="{{.UserId.Hex}}">Reset Password</a>
|
||||
<a href="#" class="btn btn-sm btn-default send-email" data-email="{{.Email}}">Send Email</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
@@ -109,16 +102,8 @@
|
||||
<footer class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 hidden-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Send Email
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default bulk-btn">
|
||||
Apply
|
||||
<button class="btn btn-sm btn-default bulk-email">
|
||||
Send Email
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -137,19 +122,22 @@ $(function() {
|
||||
$(".send-email").click(function() {
|
||||
openSendEmailDialog($(this).data("email"));
|
||||
});
|
||||
$(".bulk-btn").click(function() {
|
||||
// email
|
||||
if($(this).prev().val() == "1") {
|
||||
var emails = [];
|
||||
$(".ck:checked").each(function() {
|
||||
emails.push($(this).data("email"));
|
||||
});
|
||||
if(emails.length == 0) {
|
||||
art.alert("No user");
|
||||
return;
|
||||
}
|
||||
openSendEmailDialog(emails.join(","));
|
||||
$(".bulk-email").click(function() {
|
||||
var emails = [];
|
||||
$(".ck:checked").each(function() {
|
||||
emails.push($(this).data("email"));
|
||||
});
|
||||
if(emails.length == 0) {
|
||||
art.alert("No user");
|
||||
return;
|
||||
}
|
||||
openSendEmailDialog(emails.join(","));
|
||||
});
|
||||
|
||||
// reset password
|
||||
$(".reset-pwd").click(function() {
|
||||
var id = $(this).data("id");
|
||||
openDialog({width: 500, url: "/adminUser/resetPwd?userId=" + id, title: "Reset Password"});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user