Compare commits
225
Commits
0.3
...
dev-binnchx
| 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 | ||
|
|
fe910fd91d | ||
|
|
1c6c645c9f | ||
|
|
04838cc996 | ||
|
|
86ecc55f41 | ||
|
|
e4323d0cb2 | ||
|
|
28fbdb9ee2 | ||
|
|
b0b304d5dd | ||
|
|
536c5de56a | ||
|
|
1f51f6cc9b | ||
|
|
0ea4843cac | ||
|
|
ebcce0a247 | ||
|
|
b43c68ec2d | ||
|
|
762f6b554d | ||
|
|
593d2c2965 | ||
|
|
8ae438272b | ||
|
|
f99cca40c2 | ||
|
|
3f1930723a | ||
|
|
9fbbde9849 | ||
|
|
3bade30e1a | ||
|
|
44c8f2a7e2 | ||
|
|
8d820b069c | ||
|
|
f16ba28a3b | ||
|
|
9db1164fe0 | ||
|
|
37563d1869 | ||
|
|
87269cc939 | ||
|
|
99956cfd72 | ||
|
|
cff6efde91 | ||
|
|
2221f146de | ||
|
|
1fea36a7c1 | ||
|
|
95af247cdc | ||
|
|
5a2274328b | ||
|
|
0e6f777402 | ||
|
|
84f5e9c969 | ||
|
|
c216e3a1ea | ||
|
|
b4f0a08b9f | ||
|
|
02536f6de4 | ||
|
|
50b6af0446 | ||
|
|
416dd77717 | ||
|
|
b89721a0f4 | ||
|
|
b8ced2e1c3 | ||
|
|
e240dfbafe | ||
|
|
b411302087 | ||
|
|
e86bbb9b02 | ||
|
|
7bd5d66c55 | ||
|
|
6b194a63c6 | ||
|
|
5439c1b5fb | ||
|
|
ca9be9cd81 | ||
|
|
320c79e7a3 | ||
|
|
2ddbeb5b11 | ||
|
|
c556ab59b5 | ||
|
|
ab242b10f2 | ||
|
|
81c2254cfb | ||
|
|
9f89a3c717 | ||
|
|
6f4ba8313c | ||
|
|
c142568a56 | ||
|
|
65e84d30db | ||
|
|
76a111c6b0 | ||
|
|
4d48ecad49 | ||
|
|
9bf3b4c2bc | ||
|
|
9bdce1a46c | ||
|
|
b41101e073 | ||
|
|
cc9cb271c4 | ||
|
|
b5661edd85 | ||
|
|
a60e49364b | ||
|
|
cdd6aa035b | ||
|
|
522bbd9ed4 | ||
|
|
138dfa904c | ||
|
|
94e3f543ab | ||
|
|
634ad35813 | ||
|
|
20a39d5128 | ||
|
|
27dbd6552c | ||
|
|
d1f18b9476 | ||
|
|
8dd5239a8a | ||
|
|
e6fb6e3f09 | ||
|
|
52010e4fc1 | ||
|
|
adf59976ec | ||
|
|
f30430bc63 | ||
|
|
a113b9b5e5 | ||
|
|
85fd63baa5 | ||
|
|
4b723eb331 | ||
|
|
9b96f0fbd1 | ||
|
|
ca4eb3aef5 | ||
|
|
883ea1da62 | ||
|
|
dc2435a83d | ||
|
|
2bed5b31fa | ||
|
|
bfcf8ec547 | ||
|
|
c30cb745f9 | ||
|
|
db2e78c5a5 | ||
|
|
e4b003d063 | ||
|
|
f3993519ea | ||
|
|
02d0411d53 | ||
|
|
77f4b0f383 | ||
|
|
af9b5652ed | ||
|
|
fbad32e273 | ||
|
|
3ffb10b923 | ||
|
|
ba9b35c46e | ||
|
|
acc67754c3 | ||
|
|
1ed9f0c96d | ||
|
|
2db2a55e81 | ||
|
|
634b17c6f7 | ||
|
|
468ad4dec7 | ||
|
|
7cbd38e8bf | ||
|
|
1d8be4c012 | ||
|
|
7b6a5c0929 | ||
|
|
fe10dbbd77 | ||
|
|
7db9d95108 | ||
|
|
91eb893814 | ||
|
|
fcc86de37c | ||
|
|
61a0b9caa0 | ||
|
|
95fe0c5289 | ||
|
|
bb0350fdac | ||
|
|
1494b25129 | ||
|
|
06eb27faab | ||
|
|
121eab5d38 | ||
|
|
37da418bdd | ||
|
|
eea6ad07f8 | ||
|
|
b0402f29dd | ||
|
|
8e05e433de | ||
|
|
a0acd31fcf | ||
|
|
a5b525affd | ||
|
|
414639dc3d | ||
|
|
cf4accc110 | ||
|
|
8d4a757ee9 | ||
|
|
68bacdc3bf | ||
|
|
3df6fa2bb7 | ||
|
|
e8c0001721 | ||
|
|
4210d56a0d | ||
|
|
63b65920db | ||
|
|
c55f364153 | ||
|
|
8af64c7b74 | ||
|
|
7bb05bd9e7 | ||
|
|
abf3297639 | ||
|
|
ad00f36fd9 | ||
|
|
c549957cdc | ||
|
|
7f9356c5a7 |
No files matched your search
+4
-2
@@ -8,10 +8,12 @@ bin/release
|
|||||||
bin/tmp
|
bin/tmp
|
||||||
bin/test
|
bin/test
|
||||||
bin/src
|
bin/src
|
||||||
conf/app.conf
|
|
||||||
conf/routes
|
|
||||||
public/upload
|
public/upload
|
||||||
app/routes/routes.go
|
app/routes/routes.go
|
||||||
app/tmp/main.go
|
app/tmp/main.go
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.settings
|
.settings
|
||||||
|
.project
|
||||||
|
public/config.codekit
|
||||||
|
files
|
||||||
|
conf/app.conf
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>leanote-public</name>
|
|
||||||
<comment>leanote, your own cloud note!</comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>com.googlecode.goclipse.goBuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>goclipse.goNature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
||||||
@@ -1,5 +1,25 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
leanote - you own cloud note!
|
||||||
Version 2, June 1991
|
|
||||||
|
Copyright 2014 by the contributors
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
leanote is licensed under the GPL v2.
|
||||||
|
|
||||||
|
life(life@leanote.com, lifephp@gmail.com)
|
||||||
|
|
||||||
|
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
|
||||||
|
# Leanote
|
||||||
|
|
||||||
## 1. Introduction
|
## 1. Introduction
|
||||||
|
|
||||||
Leanote, your own cloud note.
|
Leanote, not just a notebook!
|
||||||
|

|
||||||
|
|
||||||
**Some Features**
|
**Some Features**
|
||||||
|
|
||||||
@@ -18,12 +22,18 @@ To be honest, our inspiration comes from Evernote. We use Evernote to manage our
|
|||||||
|
|
||||||
## 3. How to install leanote
|
## 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
|
### 3.1. Download leanote
|
||||||
|
|
||||||
Leanote v0.1 has been released. Binaries:
|
Leanote V1.0.2-beta has been released. Binaries:
|
||||||
|
|
||||||
* Linux: [leanote-linux-v0.1.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.1/leanote-linux-v0.1.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-v0.1.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.1/leanote-mac-v0.1.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
|
### 3.2. Install MongoDB
|
||||||
|
|
||||||
@@ -42,8 +52,8 @@ $> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb
|
|||||||
The initial database contains two users:
|
The initial database contains two users:
|
||||||
|
|
||||||
```
|
```
|
||||||
user1 username: leanote, password: abc123
|
user2 username: admin, password: abc123 (administrator)
|
||||||
user2 username: admin, password: abc123
|
user3 username: demo, password: demo@leanote.com (this user is for demo)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4. Configuration
|
### 3.4. Configuration
|
||||||
@@ -60,21 +70,10 @@ db.username=
|
|||||||
db.password=
|
db.password=
|
||||||
```
|
```
|
||||||
|
|
||||||
``http.port``
|
``app.secret`` **required** **important**
|
||||||
|
The secret key used for cryptographic operations (revel.Sign).
|
||||||
|
|
||||||
Default is 80
|
FOR SECURITY, YOU MUST CHANGE IT!!
|
||||||
|
|
||||||
``site.url``
|
|
||||||
|
|
||||||
Default is `http://localhost`, you must edit this when hosting leanote anywhere else. This is used when uploading images.
|
|
||||||
|
|
||||||
``email``
|
|
||||||
|
|
||||||
For password recovery mails
|
|
||||||
|
|
||||||
``adminUsername``
|
|
||||||
|
|
||||||
Default is `admin`. The landing page is the admin user's blog.
|
|
||||||
|
|
||||||
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
|
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
|
||||||
|
|
||||||
@@ -87,40 +86,28 @@ $> sudo sh run.sh
|
|||||||
|
|
||||||
## 4. How to develop leanote
|
## 4. How to develop leanote
|
||||||
|
|
||||||
For more tips please see [our wiki](https://github.com/leanote/leanote/wiki/How-to-develop-leanote)
|
Please see [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
Leanote is a app based on [revel](https://revel.github.io/), so if you want to work on leanote, you should be familar with revel.
|
|
||||||
|
|
||||||
### 4.1 Install golang
|
## 5. Contributors
|
||||||
|
Thank you to all the [contributors](https://github.com/leanote/leanote/graphs/contributors) on
|
||||||
|
this project. Your help is much appreciated.
|
||||||
|
|
||||||
Install golang and set the `GOPATH` environment variable
|
## 6. Contributing
|
||||||
|
|
||||||
### 4.2 Install revel
|
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||||
```
|
|
||||||
$> go get github.com/revel/revel
|
|
||||||
$> go get github.com/revel/cmd/revel
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.3 Get leanote
|
## 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)
|
||||||
$> go get github.com/leanote/leanote/app
|
* [leanote blog theme api](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api_en)
|
||||||
```
|
|
||||||
|
|
||||||
### 4.4 Build/Run leanote via revel
|
|
||||||
|
|
||||||
```
|
|
||||||
$> cp conf/app.conf-default conf/app.conf
|
|
||||||
$> cp conf/routes-default conf/routes
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can modify the leanote source and build/run using `revel`
|
|
||||||
|
|
||||||
```
|
|
||||||
$> revel run github.com/leanote/leanote
|
|
||||||
```
|
|
||||||
|
|
||||||
You are welcome to join us and contribute code to leanote! Thanks.
|
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
[leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
* [leanote bbs](http://bbs.leanote.com)
|
||||||
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
|
* QQ Group: 158716820
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
[中文](README_zh.md)
|
||||||
|
|
||||||
|
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
|
||||||
|
# Leanote产品
|
||||||
|
|
||||||
|
## 1. 介绍
|
||||||
|
|
||||||
|
Leanote, 不只是笔记!
|
||||||
|

|
||||||
|
|
||||||
|
**特性**
|
||||||
|
|
||||||
|
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||||
|
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||||
|
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||||
|
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||||
|
|
||||||
|
## 2. 为什么我们要创建leanote?
|
||||||
|
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||||
|
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||||
|
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||||
|
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||||
|
* 还有...
|
||||||
|
|
||||||
|
## 3.安装leanote
|
||||||
|
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||||
|
|
||||||
|
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||||
|
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
|
||||||
|
### 3.1. 下载leanote
|
||||||
|
|
||||||
|
Leanote V1.0-beta.2 已发布, 二进制文件(暂时没有windows版的):
|
||||||
|
|
||||||
|
* Linux: [leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
* MacOS X: [leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.2.bin.tar.gz)
|
||||||
|
|
||||||
|
或者直接检出[Leanote bin repository](https://github.com/leanote/leanote-bin) (推荐, 因为为最新版本)
|
||||||
|
|
||||||
|
### 3.2. 安装 MongodbDB
|
||||||
|
|
||||||
|
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||||
|
|
||||||
|
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
|
### 3.3. 导入初始数据
|
||||||
|
|
||||||
|
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
|
初始数据包含两个用户:
|
||||||
|
|
||||||
|
```
|
||||||
|
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||||
|
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4. 配置
|
||||||
|
|
||||||
|
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||||
|
|
||||||
|
``mongodb`` **必须配置!**
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
db.host=localhost
|
||||||
|
db.port=27017
|
||||||
|
db.dbname=leanote
|
||||||
|
db.username=
|
||||||
|
db.password=
|
||||||
|
```
|
||||||
|
|
||||||
|
``app.secret`` **重要**
|
||||||
|
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
|
||||||
|
|
||||||
|
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
|
||||||
|
|
||||||
|
### 3.5. 运行leanote
|
||||||
|
|
||||||
|
```
|
||||||
|
$> cd PATH_TO_LEANOTE/bin
|
||||||
|
$> sudo sh run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 如何对leanote进行二次开发
|
||||||
|
|
||||||
|
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
|
## 5. 贡献者
|
||||||
|
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
||||||
|
|
||||||
|
## 6. 加入我们
|
||||||
|
|
||||||
|
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
||||||
|
|
||||||
|
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
||||||
|
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
||||||
|
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
||||||
|
|
||||||
|
|
||||||
|
## 讨论
|
||||||
|
* [leanote 社区](http://bbs.leanote.com)
|
||||||
|
* QQ群: 158716820
|
||||||
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
[English](README.md)
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
// "io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Album controller
|
||||||
|
type Album struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// all albums by userId
|
||||||
|
func (c Album) GetAlbums() revel.Result {
|
||||||
|
re := albumService.GetAlbums(c.GetUserId())
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
||||||
|
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
||||||
|
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
||||||
|
}
|
||||||
|
|
||||||
|
// add album
|
||||||
|
func (c Album) AddAlbum(name string) revel.Result {
|
||||||
|
album := info.Album{
|
||||||
|
AlbumId: bson.NewObjectId(),
|
||||||
|
Name: name,
|
||||||
|
Seq: -1,
|
||||||
|
UserId: c.GetObjectUserId()}
|
||||||
|
re := albumService.AddAlbum(album)
|
||||||
|
|
||||||
|
if(re) {
|
||||||
|
return c.RenderJson(album)
|
||||||
|
} else {
|
||||||
|
return c.RenderJson(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update alnum name
|
||||||
|
func (c Album) UpdateAlbum(albumId, name string) revel.Result {
|
||||||
|
return c.RenderJson(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"io"
|
||||||
|
"fmt"
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 附件
|
||||||
|
type Attach struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传附件
|
||||||
|
func (c Attach) UploadAttach(noteId string) revel.Result {
|
||||||
|
re := c.uploadAttach(noteId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||||
|
var fileId = ""
|
||||||
|
var resultMsg = "error" // 错误信息
|
||||||
|
var Ok = false
|
||||||
|
var fileInfo info.Attach
|
||||||
|
|
||||||
|
re = info.NewRe()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
re.Id = fileId // 只是id, 没有其它信息
|
||||||
|
re.Msg = resultMsg
|
||||||
|
re.Ok = Ok
|
||||||
|
re.Item = fileInfo
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 判断是否有权限为笔记添加附件
|
||||||
|
if !shareService.HasUpdateNotePerm(noteId, c.GetUserId()) {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
file, handel, err := c.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
// > 5M?
|
||||||
|
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成上传路径
|
||||||
|
filePath := "files/" + c.GetUserId() + "/attachs"
|
||||||
|
dir := revel.BasePath + "/" + filePath
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
// 生成新的文件名
|
||||||
|
filename := handel.Filename
|
||||||
|
_, ext := SplitFilename(filename) // .doc
|
||||||
|
filename = NewGuid() + ext
|
||||||
|
toPath := dir + "/" + filename;
|
||||||
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
// add File to db
|
||||||
|
fileType := ""
|
||||||
|
if ext != "" {
|
||||||
|
fileType = strings.ToLower(ext[1:])
|
||||||
|
}
|
||||||
|
filesize := GetFilesize(toPath)
|
||||||
|
fileInfo = info.Attach{Name: filename,
|
||||||
|
Title: handel.Filename,
|
||||||
|
NoteId: bson.ObjectIdHex(noteId),
|
||||||
|
UploadUserId: c.GetObjectUserId(),
|
||||||
|
Path: filePath + "/" + filename,
|
||||||
|
Type: fileType,
|
||||||
|
Size: filesize}
|
||||||
|
|
||||||
|
id := bson.NewObjectId();
|
||||||
|
fileInfo.AttachId = id
|
||||||
|
fileId = id.Hex()
|
||||||
|
Ok, resultMsg = attachService.AddAttach(fileInfo)
|
||||||
|
if resultMsg != "" {
|
||||||
|
resultMsg = c.Message(resultMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo.Path = ""; // 不要返回
|
||||||
|
if Ok {
|
||||||
|
resultMsg = "success"
|
||||||
|
}
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除附件
|
||||||
|
func (c Attach) DeleteAttach(attachId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all attachs by noteId
|
||||||
|
func (c Attach) GetAttachs(noteId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
re.List = attachService.ListAttachs(noteId, c.GetUserId())
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载附件
|
||||||
|
// 权限判断
|
||||||
|
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("")
|
||||||
|
}
|
||||||
|
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||||
|
file, _ := os.Open(fn)
|
||||||
|
return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
|
||||||
|
// return c.RenderFile(file, revel.Attachment) // revel.Attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Attach) DownloadAll(noteId string) revel.Result {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.NoteId == "" {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
// 得到文件列表
|
||||||
|
attachs := attachService.ListAttachs(noteId, c.GetUserId())
|
||||||
|
if attachs == nil || len(attachs) == 0 {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
dir := revel.BasePath + "/files/tmp"
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
filename := note.Title + ".tar.gz"
|
||||||
|
if note.Title == "" {
|
||||||
|
filename = "all.tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
// file write
|
||||||
|
fw, err := os.Create(revel.BasePath + "/files/" + filename)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
|
||||||
|
|
||||||
|
// gzip write
|
||||||
|
gw := gzip.NewWriter(fw)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
// tar write
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// 遍历文件列表
|
||||||
|
for _, attach := range attachs {
|
||||||
|
fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
|
||||||
|
fr, err := os.Open(fn)
|
||||||
|
fileInfo, _ := fr.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// 信息头
|
||||||
|
h := new(tar.Header)
|
||||||
|
h.Name = attach.Title
|
||||||
|
h.Size = fileInfo.Size()
|
||||||
|
h.Mode = int64(fileInfo.Mode())
|
||||||
|
h.ModTime = fileInfo.ModTime()
|
||||||
|
|
||||||
|
// 写信息头
|
||||||
|
err = tw.WriteHeader(h)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写文件
|
||||||
|
_, err = io.Copy(tw, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} // for
|
||||||
|
|
||||||
|
// tw.Close()
|
||||||
|
// gw.Close()
|
||||||
|
// fw.Close()
|
||||||
|
// file, _ := os.Open(dir + "/" + filename)
|
||||||
|
// fw.Seek(0, 0)
|
||||||
|
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "strconv"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
// 用户登录/注销/找回密码
|
||||||
@@ -14,11 +16,19 @@ type Auth struct {
|
|||||||
|
|
||||||
//--------
|
//--------
|
||||||
// 登录
|
// 登录
|
||||||
func (c Auth) Login(email string) revel.Result {
|
func (c Auth) Login(email, from string) revel.Result {
|
||||||
c.RenderArgs["title"] = c.Message("login")
|
c.RenderArgs["title"] = c.Message("login")
|
||||||
c.RenderArgs["subTitle"] = c.Message("login")
|
c.RenderArgs["subTitle"] = c.Message("login")
|
||||||
c.RenderArgs["email"] = email
|
c.RenderArgs["email"] = email
|
||||||
c.RenderArgs["openRegister"] = openRegister
|
c.RenderArgs["from"] = from
|
||||||
|
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
||||||
|
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
if sessionService.LoginTimesIsOver(sessionId) {
|
||||||
|
c.RenderArgs["needCaptcha"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
if c.Has("demo") {
|
if c.Has("demo") {
|
||||||
c.RenderArgs["demo"] = true
|
c.RenderArgs["demo"] = true
|
||||||
@@ -26,73 +36,97 @@ func (c Auth) Login(email string) revel.Result {
|
|||||||
}
|
}
|
||||||
return c.RenderTemplate("home/login.html")
|
return c.RenderTemplate("home/login.html")
|
||||||
}
|
}
|
||||||
func (c Auth) DoLogin(email, pwd string) revel.Result {
|
|
||||||
|
// 为了demo和register
|
||||||
|
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
var msg = ""
|
||||||
|
fmt.Println(sessionId)
|
||||||
userInfo := authService.Login(email, pwd)
|
userInfo := authService.Login(email, pwd)
|
||||||
if userInfo.Email != "" {
|
if userInfo.Email != "" {
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
// 必须要redirect, 不然用户刷新会重复提交登录信息
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
// return c.Redirect("/")
|
|
||||||
return c.RenderJson(info.Re{Ok: true})
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
}
|
}
|
||||||
// return c.RenderTemplate("login.html")
|
|
||||||
return c.RenderJson(info.Re{Ok: false, Msg: c.Message("wrongUsernameOrPassword")})
|
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
||||||
|
}
|
||||||
|
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
|
||||||
|
var msg = ""
|
||||||
|
// > 5次需要验证码, 直到登录成功
|
||||||
|
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||||
|
msg = "captchaError"
|
||||||
|
} else {
|
||||||
|
userInfo := authService.Login(email, pwd)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
c.SetSession(userInfo)
|
||||||
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
|
sessionService.IncrLoginTimes(sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
||||||
}
|
}
|
||||||
// 注销
|
// 注销
|
||||||
func (c Auth) Logout() revel.Result {
|
func (c Auth) Logout() revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
sessionService.Clear(sessionId)
|
||||||
c.ClearSession()
|
c.ClearSession()
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 体验一下
|
// 体验一下
|
||||||
func (c Auth) Demo() revel.Result {
|
func (c Auth) Demo() revel.Result {
|
||||||
c.DoLogin("demo@leanote.com", "demo@leanote.com")
|
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
|
||||||
return c.Redirect("/note")
|
return c.Redirect("/note")
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
// 注册
|
// 注册
|
||||||
func (c Auth) Register() revel.Result {
|
func (c Auth) Register(from, iu string) revel.Result {
|
||||||
if !openRegister {
|
if !configService.IsOpenRegister() {
|
||||||
return c.Redirect("/index")
|
return c.Redirect("/index")
|
||||||
}
|
}
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["from"] = from
|
||||||
|
c.RenderArgs["iu"] = iu
|
||||||
|
|
||||||
c.RenderArgs["title"] = c.Message("register")
|
c.RenderArgs["title"] = c.Message("register")
|
||||||
c.RenderArgs["subTitle"] = c.Message("register")
|
c.RenderArgs["subTitle"] = c.Message("register")
|
||||||
return c.RenderTemplate("home/register.html")
|
return c.RenderTemplate("home/register.html")
|
||||||
}
|
}
|
||||||
func (c Auth) DoRegister(email, pwd string) revel.Result {
|
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
||||||
if !openRegister {
|
if !configService.IsOpenRegister() {
|
||||||
return c.Redirect("/index")
|
return c.Redirect("/index")
|
||||||
}
|
}
|
||||||
|
|
||||||
re := info.NewRe();
|
re := info.NewRe();
|
||||||
|
|
||||||
if email == "" {
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
re.Msg = c.Message("inputEmail")
|
return c.RenderRe(re);
|
||||||
return c.RenderJson(re)
|
|
||||||
} else if !IsEmail(email) {
|
|
||||||
re.Msg = c.Message("wrongEmail")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
// 密码
|
return c.RenderRe(re);
|
||||||
if pwd == "" {
|
|
||||||
re.Msg = c.Message("inputPassword")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
} else if len(pwd) < 6 {
|
|
||||||
re.Msg = c.Message("wrongPassword")
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
re.Ok, re.Msg = authService.Register(email, pwd)
|
re.Ok, re.Msg = authService.Register(email, pwd, iu)
|
||||||
|
|
||||||
// 注册成功, 则立即登录之
|
// 注册成功, 则立即登录之
|
||||||
if re.Ok {
|
if re.Ok {
|
||||||
c.DoLogin(email, pwd)
|
c.doLogin(email, pwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderRe(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
@@ -130,12 +164,11 @@ func (c Auth) FindPassword2(token string) revel.Result {
|
|||||||
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
|
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
|
||||||
re := info.NewRe();
|
re := info.NewRe();
|
||||||
|
|
||||||
re.Ok, re.Msg = IsGoodPwd(pwd)
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
if !re.Ok {
|
return c.RenderRe(re);
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改之
|
// 修改之
|
||||||
re.Ok, re.Msg = pwdService.UpdatePwd(token, pwd)
|
re.Ok, re.Msg = pwdService.UpdatePwd(token, pwd)
|
||||||
return c.RenderJson(re)
|
return c.RenderRe(re)
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,16 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 公用Controller, 其它Controller继承它
|
// 公用Controller, 其它Controller继承它
|
||||||
@@ -54,15 +56,21 @@ func (c BaseController) GetUsername() string {
|
|||||||
// 得到用户信息
|
// 得到用户信息
|
||||||
func (c BaseController) GetUserInfo() info.User {
|
func (c BaseController) GetUserInfo() info.User {
|
||||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||||
|
return userService.GetUserInfo(userId);
|
||||||
|
/*
|
||||||
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
|
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
|
||||||
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
|
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
|
||||||
|
mdEditorWidth, _ := strconv.Atoi(c.Session["MdEditorWidth"])
|
||||||
|
LogJ(c.Session)
|
||||||
user := info.User{UserId: bson.ObjectIdHex(userId),
|
user := info.User{UserId: bson.ObjectIdHex(userId),
|
||||||
Email: c.Session["Email"],
|
Email: c.Session["Email"],
|
||||||
|
Logo: c.Session["Logo"],
|
||||||
Username: c.Session["Username"],
|
Username: c.Session["Username"],
|
||||||
UsernameRaw: c.Session["UsernameRaw"],
|
UsernameRaw: c.Session["UsernameRaw"],
|
||||||
Theme: c.Session["Theme"],
|
Theme: c.Session["Theme"],
|
||||||
NotebookWidth: notebookWidth,
|
NotebookWidth: notebookWidth,
|
||||||
NoteListWidth: noteListWidth,
|
NoteListWidth: noteListWidth,
|
||||||
|
MdEditorWidth: mdEditorWidth,
|
||||||
}
|
}
|
||||||
if c.Session["Verified"] == "1" {
|
if c.Session["Verified"] == "1" {
|
||||||
user.Verified = true
|
user.Verified = true
|
||||||
@@ -71,10 +79,19 @@ func (c BaseController) GetUserInfo() info.User {
|
|||||||
user.LeftIsMin = true
|
user.LeftIsMin = true
|
||||||
}
|
}
|
||||||
return user
|
return user
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return info.User{}
|
return info.User{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 这里的session都是cookie中的, 与数据库session无关
|
||||||
|
func (c BaseController) GetSession(key string) string {
|
||||||
|
v, ok := c.Session[key]
|
||||||
|
if !ok {
|
||||||
|
v = ""
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
func (c BaseController) SetSession(userInfo info.User) {
|
func (c BaseController) SetSession(userInfo info.User) {
|
||||||
if userInfo.UserId.Hex() != "" {
|
if userInfo.UserId.Hex() != "" {
|
||||||
c.Session["UserId"] = userInfo.UserId.Hex()
|
c.Session["UserId"] = userInfo.UserId.Hex()
|
||||||
@@ -82,6 +99,7 @@ func (c BaseController) SetSession(userInfo info.User) {
|
|||||||
c.Session["Username"] = userInfo.Username
|
c.Session["Username"] = userInfo.Username
|
||||||
c.Session["UsernameRaw"] = userInfo.UsernameRaw
|
c.Session["UsernameRaw"] = userInfo.UsernameRaw
|
||||||
c.Session["Theme"] = userInfo.Theme
|
c.Session["Theme"] = userInfo.Theme
|
||||||
|
c.Session["Logo"] = userInfo.Logo
|
||||||
|
|
||||||
c.Session["NotebookWidth"] = strconv.Itoa(userInfo.NotebookWidth)
|
c.Session["NotebookWidth"] = strconv.Itoa(userInfo.NotebookWidth)
|
||||||
c.Session["NoteListWidth"] = strconv.Itoa(userInfo.NoteListWidth)
|
c.Session["NoteListWidth"] = strconv.Itoa(userInfo.NoteListWidth)
|
||||||
@@ -154,7 +172,7 @@ func (c BaseController) E404() revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置本地
|
// 设置本地
|
||||||
func (c BaseController) SetLocale() {
|
func (c BaseController) SetLocale() string {
|
||||||
locale := string(c.Request.Locale) // zh-CN
|
locale := string(c.Request.Locale) // zh-CN
|
||||||
lang := locale
|
lang := locale
|
||||||
if strings.Contains(locale, "-") {
|
if strings.Contains(locale, "-") {
|
||||||
@@ -165,10 +183,68 @@ func (c BaseController) SetLocale() {
|
|||||||
lang = "en";
|
lang = "en";
|
||||||
}
|
}
|
||||||
c.RenderArgs["locale"] = lang;
|
c.RenderArgs["locale"] = lang;
|
||||||
|
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
|
||||||
|
|
||||||
|
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||||
|
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||||
|
c.RenderArgs["noteUrl"] = configService.GetNoteUrl()
|
||||||
|
|
||||||
|
return lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置userInfo
|
// 设置userInfo
|
||||||
func (c BaseController) SetUserInfo() {
|
func (c BaseController) SetUserInfo() info.User {
|
||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
if(userInfo.Username == configService.GetAdminUsername()) {
|
||||||
|
c.RenderArgs["isAdmin"] = true
|
||||||
|
}
|
||||||
|
return userInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// life
|
||||||
|
// 返回解析后的字符串, 只是为了解析模板得到字符串
|
||||||
|
func (c BaseController) RenderTemplateStr(templatePath string) string {
|
||||||
|
// Get the Template.
|
||||||
|
// 返回 GoTemplate{tmpl, loader}
|
||||||
|
template, err := revel.MainTemplateLoader.Template(templatePath)
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl := &revel.RenderTemplateResult{
|
||||||
|
Template: template,
|
||||||
|
RenderArgs: c.RenderArgs, // 把args给它
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
tpl.Template.Render(&buffer, c.RenderArgs)
|
||||||
|
return buffer.String();
|
||||||
|
}
|
||||||
|
|
||||||
|
// json, result
|
||||||
|
// 为了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, "-")
|
||||||
|
if len(msgAndValues) == 2 {
|
||||||
|
re.Msg = c.Message(msgAndValues[0], msgAndValues[1])
|
||||||
|
} else {
|
||||||
|
others := msgAndValues[0:]
|
||||||
|
a := make([]interface{}, len(others))
|
||||||
|
for i, v := range others {
|
||||||
|
a[i] = v
|
||||||
|
}
|
||||||
|
re.Msg = c.Message(msgAndValues[0], a...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
re.Msg = c.Message(re.Msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(re.Msg, "???") {
|
||||||
|
re.Msg = oldMsg
|
||||||
|
}
|
||||||
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
+810
-187
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,43 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/lea/captcha"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
// "strconv"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 验证码服务
|
||||||
|
type Captcha struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ca string
|
||||||
|
func (r Ca) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
resp.WriteHeader(http.StatusOK, "image/png")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Captcha) Get() revel.Result {
|
||||||
|
c.Response.ContentType = "image/png"
|
||||||
|
image, str := captcha.Fetch()
|
||||||
|
image.WriteTo(c.Response.Out)
|
||||||
|
|
||||||
|
sessionId := c.Session["_ID"]
|
||||||
|
// LogJ(c.Session)
|
||||||
|
// Log("------")
|
||||||
|
// Log(str)
|
||||||
|
// Log(sessionId)
|
||||||
|
Log("..")
|
||||||
|
sessionService.SetCaptcha(sessionId, str)
|
||||||
|
|
||||||
|
return c.Render()
|
||||||
|
}
|
||||||
@@ -3,10 +3,15 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/lea/netutil"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
// "strconv"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -14,44 +19,80 @@ type File struct {
|
|||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传图片 editor
|
// 上传的是博客logo
|
||||||
func (c File) UploadImage(renderHtml string) revel.Result {
|
// TODO logo不要设置权限, 另外的目录
|
||||||
if renderHtml == "" {
|
func (c File) UploadBlogLogo() revel.Result {
|
||||||
renderHtml = "file/image.html"
|
re := c.uploadImage("blogLogo", "");
|
||||||
}
|
|
||||||
|
|
||||||
re := c.uploadImage();
|
c.RenderArgs["fileUrlPath"] = re.Id
|
||||||
|
|
||||||
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
c.RenderArgs["resultMsg"] = re.Msg
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
return c.RenderTemplate(renderHtml)
|
return c.RenderTemplate("file/blog_logo.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传的是博客logo
|
// 拖拉上传, pasteImage
|
||||||
func (c File) UploadBlogLogo() revel.Result {
|
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
|
||||||
return c.UploadImage("file/blog_logo.html");
|
func (c File) PasteImage(noteId string) revel.Result {
|
||||||
|
re := c.uploadImage("pasteImage", "");
|
||||||
|
|
||||||
|
userId := c.GetUserId()
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.UserId != "" {
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
if noteUserId != userId {
|
||||||
|
// 是否是有权限协作的
|
||||||
|
if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
|
||||||
|
// 复制图片之, 图片复制给noteUserId
|
||||||
|
_, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
|
||||||
|
} else {
|
||||||
|
// 怎么可能在这个笔记下paste图片呢?
|
||||||
|
// 正常情况下不会
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拖拉上传
|
// 头像设置
|
||||||
func (c File) UploadImageJson(renderHtml string) revel.Result {
|
func (c File) UploadAvatar() revel.Result {
|
||||||
re := c.uploadImage();
|
re := c.uploadImage("logo", "");
|
||||||
re.Id = siteUrl + re.Id
|
|
||||||
// re.Id = re.Id
|
c.RenderArgs["fileUrlPath"] = re.Id
|
||||||
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
|
if re.Ok {
|
||||||
|
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
|
||||||
|
if re.Ok {
|
||||||
|
c.UpdateSession("Logo", re.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// leaui image plugin upload image
|
||||||
|
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||||
|
re := c.uploadImage("", albumId);
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传图片, 公用方法
|
// 上传图片, 公用方法
|
||||||
func (c File) uploadImage() (re info.Re) {
|
// upload image common func
|
||||||
|
func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||||
var fileUrlPath = ""
|
var fileUrlPath = ""
|
||||||
|
var fileId = ""
|
||||||
var resultCode = 0 // 1表示正常
|
var resultCode = 0 // 1表示正常
|
||||||
var resultMsg = "内部错误" // 错误信息
|
var resultMsg = "error" // 错误信息
|
||||||
|
var Ok = false
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
re.Id = fileUrlPath
|
re.Id = fileId // 只是id, 没有其它信息
|
||||||
re.Code = resultCode
|
re.Code = resultCode
|
||||||
re.Msg = resultMsg
|
re.Msg = resultMsg
|
||||||
|
re.Ok = Ok
|
||||||
}()
|
}()
|
||||||
|
|
||||||
file, handel, err := c.Request.FormFile("file")
|
file, handel, err := c.Request.FormFile("file")
|
||||||
@@ -60,20 +101,30 @@ func (c File) uploadImage() (re info.Re) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
// 生成上传路径
|
// 生成上传路径
|
||||||
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
|
if(from == "logo" || from == "blogLogo") {
|
||||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||||
|
} else {
|
||||||
|
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||||
|
}
|
||||||
|
dir := revel.BasePath + "/" + fileUrlPath
|
||||||
err = os.MkdirAll(dir, 0755)
|
err = os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log(err)
|
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
// 生成新的文件名
|
// 生成新的文件名
|
||||||
filename := handel.Filename
|
filename := handel.Filename
|
||||||
_, ext := SplitFilename(filename)
|
|
||||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
var ext string;
|
||||||
resultMsg = "不是图片"
|
if from == "pasteImage" {
|
||||||
return re
|
ext = ".png"; // TODO 可能不是png类型
|
||||||
|
} else {
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
|
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||||
|
resultMsg = "Please upload image"
|
||||||
|
return re
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = NewGuid() + ext
|
filename = NewGuid() + ext
|
||||||
data, err := ioutil.ReadAll(file)
|
data, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -81,10 +132,22 @@ func (c File) uploadImage() (re info.Re) {
|
|||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var maxFileSize float64
|
||||||
|
if(from == "logo") {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
|
||||||
|
} else if from == "blogLogo" {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
|
||||||
|
} else {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadImageSize");
|
||||||
|
}
|
||||||
|
if maxFileSize <= 0 {
|
||||||
|
maxFileSize = 1000
|
||||||
|
}
|
||||||
|
|
||||||
// > 2M?
|
// > 2M?
|
||||||
if(len(data) > 5 * 1024 * 1024) {
|
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||||
resultCode = 0
|
resultCode = 0
|
||||||
resultMsg = "图片大于2M"
|
resultMsg = fmt.Sprintf("The file Size is bigger than %vM", maxFileSize)
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,10 +159,103 @@ func (c File) uploadImage() (re info.Re) {
|
|||||||
}
|
}
|
||||||
// 改变成gif图片
|
// 改变成gif图片
|
||||||
_, toPathGif := TransToGif(toPath, 0, true)
|
_, toPathGif := TransToGif(toPath, 0, true)
|
||||||
|
filename = GetFilename(toPathGif)
|
||||||
fileUrlPath += "/" + GetFilename(toPathGif)
|
filesize := GetFilesize(toPathGif)
|
||||||
|
fileUrlPath += "/" + filename
|
||||||
resultCode = 1
|
resultCode = 1
|
||||||
resultMsg = "上传成功!"
|
resultMsg = "Upload Success!"
|
||||||
|
|
||||||
|
// File
|
||||||
|
fileInfo := info.File{Name: filename,
|
||||||
|
Title: handel.Filename,
|
||||||
|
Path: fileUrlPath,
|
||||||
|
Size: filesize}
|
||||||
|
|
||||||
|
id := bson.NewObjectId();
|
||||||
|
fileInfo.FileId = id
|
||||||
|
fileId = id.Hex()
|
||||||
|
if(from == "logo" || from == "blogLogo") {
|
||||||
|
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok, resultMsg = fileService.AddImage(fileInfo, albumId, c.GetUserId(), from == "" || from == "pasteImage")
|
||||||
|
resultMsg = c.Message(resultMsg)
|
||||||
|
|
||||||
|
fileInfo.Path = ""; // 不要返回
|
||||||
|
re.Item = fileInfo
|
||||||
|
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get all images by userId with page
|
||||||
|
func (c File) GetImages(albumId, key string, page int) revel.Result {
|
||||||
|
re := fileService.ListImagesWithPage(c.GetUserId(), albumId, key, page, 12)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c File) UpdateImageTitle(fileId, title string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = fileService.UpdateImageTitle(c.GetUserId(), fileId, title)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c File) DeleteImage(fileId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
// 输出image
|
||||||
|
// 权限判断
|
||||||
|
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("")
|
||||||
|
}
|
||||||
|
fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
|
||||||
|
file, _ := os.Open(fn)
|
||||||
|
return c.RenderFile(file, revel.Inline) // revel.Attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
// 协作时复制图片到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"
|
||||||
|
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
filesize, filename, _, ok := netutil.WriteUrl(src, dir)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
re.Msg = "copy error"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File
|
||||||
|
fileInfo := info.File{Name: filename,
|
||||||
|
Title: filename,
|
||||||
|
Path: fileUrlPath + "/" + filename,
|
||||||
|
Size: filesize}
|
||||||
|
|
||||||
|
id := bson.NewObjectId();
|
||||||
|
fileInfo.FileId = id
|
||||||
|
|
||||||
|
re.Id = id.Hex()
|
||||||
|
re.Item = fileInfo.Path
|
||||||
|
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -12,14 +12,22 @@ type Index struct {
|
|||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Index) Default() revel.Result {
|
||||||
|
if configService.HomePageIsAdminsBlog(){
|
||||||
|
blog := Blog{c.BaseController}
|
||||||
|
return blog.Index(configService.GetAdminUsername());
|
||||||
|
}
|
||||||
|
return c.Index()
|
||||||
|
}
|
||||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||||
func (c Index) Index() revel.Result {
|
func (c Index) Index() revel.Result {
|
||||||
|
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.RenderArgs["title"] = "leanote"
|
c.RenderArgs["title"] = "leanote"
|
||||||
c.RenderArgs["openRegister"] = openRegister
|
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||||
c.SetLocale()
|
lang := c.SetLocale()
|
||||||
|
|
||||||
return c.RenderTemplate("home/index.html");
|
return c.RenderTemplate("home/index_" + lang + ".html");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 建议
|
// 建议
|
||||||
@@ -29,7 +37,7 @@ func (c Index) Suggestion(addr, suggestion string) revel.Result {
|
|||||||
|
|
||||||
// 发给我
|
// 发给我
|
||||||
go func() {
|
go func() {
|
||||||
SendToLeanote("建议", "建议", "UserId: " + c.GetUserId() + " <br /> Suggestions: " + suggestion)
|
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: " + c.GetUserId() + " <br /> Suggestions: " + suggestion)
|
||||||
}();
|
}();
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
|
|||||||
@@ -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");
|
|
||||||
}
|
|
||||||
@@ -3,14 +3,16 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/lea/html2image"
|
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// "os"
|
"os/exec"
|
||||||
|
// "time"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
|
// "bytes"
|
||||||
|
// "os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Note struct {
|
type Note struct {
|
||||||
@@ -20,9 +22,8 @@ type Note struct {
|
|||||||
// 笔记首页, 判断是否已登录
|
// 笔记首页, 判断是否已登录
|
||||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||||
// 否则, 转向登录页面
|
// 否则, 转向登录页面
|
||||||
func (c Note) Index() revel.Result {
|
func (c Note) Index(noteId string) revel.Result {
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
|
|
||||||
userId := userInfo.UserId.Hex()
|
userId := userInfo.UserId.Hex()
|
||||||
@@ -32,7 +33,7 @@ func (c Note) Index() revel.Result {
|
|||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["openRegister"] = openRegister
|
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
||||||
|
|
||||||
// 已登录了, 那么得到所有信息
|
// 已登录了, 那么得到所有信息
|
||||||
notebooks := notebookService.GetNotebooks(userId)
|
notebooks := notebookService.GetNotebooks(userId)
|
||||||
@@ -41,28 +42,90 @@ func (c Note) Index() revel.Result {
|
|||||||
// 还需要按时间排序(DESC)得到notes
|
// 还需要按时间排序(DESC)得到notes
|
||||||
notes := []info.Note{}
|
notes := []info.Note{}
|
||||||
noteContent := info.NoteContent{}
|
noteContent := info.NoteContent{}
|
||||||
|
|
||||||
if len(notebooks) > 0 {
|
if len(notebooks) > 0 {
|
||||||
// _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), pageSize, defaultSortField, false, false);
|
// noteId是否存在
|
||||||
// 变成最新
|
// 是否传入了正确的noteId
|
||||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
hasRightNoteId := false
|
||||||
if len(notes) > 0 {
|
if IsObjectId(noteId) {
|
||||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
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
|
// 当然, 还需要得到第一个notes的content
|
||||||
//...
|
//...
|
||||||
|
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||||
|
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
c.RenderArgs["notebooks"] = notebooks
|
||||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
|
||||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
|
||||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
|
||||||
|
|
||||||
c.RenderArgs["notes"] = c.Json(notes)
|
c.RenderArgs["notes"] = notes
|
||||||
c.RenderArgs["noteContentJson"] = c.Json(noteContent)
|
c.RenderArgs["noteContentJson"] = noteContent
|
||||||
c.RenderArgs["noteContent"] = noteContent.Content
|
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 {
|
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||||
return c.RenderTemplate("note/note-dev.html")
|
return c.RenderTemplate("note/note-dev.html")
|
||||||
@@ -117,10 +180,9 @@ type NoteOrContent struct {
|
|||||||
// 这里不能用json, 要用post
|
// 这里不能用json, 要用post
|
||||||
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||||
// 新添加note
|
// 新添加note
|
||||||
LogJ(noteOrContent)
|
|
||||||
if noteOrContent.IsNew {
|
if noteOrContent.IsNew {
|
||||||
userId := c.GetObjectUserId();
|
userId := c.GetObjectUserId();
|
||||||
myUserId := userId
|
// myUserId := userId
|
||||||
// 为共享新建?
|
// 为共享新建?
|
||||||
if noteOrContent.FromUserId != "" {
|
if noteOrContent.FromUserId != "" {
|
||||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||||
@@ -142,7 +204,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
Content: noteOrContent.Content,
|
Content: noteOrContent.Content,
|
||||||
Abstract: noteOrContent.Abstract};
|
Abstract: noteOrContent.Abstract};
|
||||||
|
|
||||||
note = noteService.AddNoteAndContent(note, noteContent, myUserId)
|
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||||
return c.RenderJson(note)
|
return c.RenderJson(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,31 +284,137 @@ func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
|||||||
return c.RenderJson(blogs)
|
return c.RenderJson(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------
|
//------------------
|
||||||
// html2image
|
// html2image
|
||||||
|
// 判断是否有权限生成
|
||||||
|
// 博客也可以调用
|
||||||
|
// 这是脚本调用, 没有cookie, 不执行权限控制, 通过传来的appKey判断
|
||||||
|
func (c Note) ToImage(noteId, appKey string) revel.Result {
|
||||||
|
// 虽然传了cookie但是这里还是不能得到userId, 所以还是通过appKey来验证之
|
||||||
|
appKeyTrue, _ := revel.Config.String("app.secret")
|
||||||
|
if appKeyTrue != appKey {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.NoteId == "" {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
|
c.RenderArgs["blog"] = note
|
||||||
|
c.RenderArgs["content"] = content.Content
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
return c.RenderTemplate("html2Image/index.html")
|
||||||
|
}
|
||||||
|
|
||||||
func (c Note) Html2Image(noteId string) revel.Result {
|
func (c Note) Html2Image(noteId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
note := noteService.GetNote(noteId, userId)
|
note := noteService.GetNoteById(noteId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
|
re.Msg = "No Note"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
content := noteService.GetNoteContent(noteId, userId)
|
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
// 是否有权限
|
||||||
|
if noteUserId != userId {
|
||||||
|
// 是否是有权限协作的
|
||||||
|
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
||||||
|
re.Msg = "No Perm"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// path 判断是否需要重新生成之
|
// path 判断是否需要重新生成之
|
||||||
fileUrlPath := "/upload/" + userId + "/images/weibo"
|
fileUrlPath := "/upload/" + noteUserId + "/images/weibo"
|
||||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||||
if !ClearDir(dir) {
|
if !ClearDir(dir) {
|
||||||
|
re.Msg = "No Dir"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := note.NoteId.Hex() + ".png";
|
filename := note.NoteId.Hex() + ".png";
|
||||||
path := dir + "/" + filename
|
path := dir + "/" + filename
|
||||||
|
|
||||||
// 生成之
|
// cookie
|
||||||
html2image.ToImage(userId, c.GetUsername(), noteId, note.Title, content.Content, path)
|
cookieName := revel.CookiePrefix + "_SESSION"
|
||||||
|
cookie, err := c.Request.Cookie(cookieName)
|
||||||
|
cookieStr := cookie.String()
|
||||||
|
cookieValue := ""
|
||||||
|
if err == nil && len(cookieStr) > len(cookieName) {
|
||||||
|
cookieValue = cookieStr[len(cookieName)+1:]
|
||||||
|
}
|
||||||
|
|
||||||
re.Ok = true
|
appKey, _ := revel.Config.String("app.secret")
|
||||||
re.Id = fileUrlPath + "/" + filename
|
cookieDomain, _ := revel.Config.String("cookie.domain")
|
||||||
|
// 生成之
|
||||||
|
url := configService.GetSiteUrl() + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
||||||
|
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
|
||||||
|
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
|
if binPath == "" {
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
cc := binPath + " \"" + url + "\" \"" + path + "\" \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
|
Log(cc);
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
re.Ok = true
|
||||||
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
re.Msg = string(b)
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 这里速度慢, 生成不完全(图片和内容都不全)
|
||||||
|
content := noteService.GetNoteContent(noteId, noteUserId)
|
||||||
|
userInfo := userService.GetUserInfo(noteUserId);
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
c.RenderArgs["blog"] = note
|
||||||
|
c.RenderArgs["content"] = content.Content
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
html := c.RenderTemplateStr("html2Image/index.html") // Result类型的
|
||||||
|
contentFile := dir + "/html";
|
||||||
|
fout, err := os.Create(contentFile)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
fout.WriteString(html);
|
||||||
|
fout.Close()
|
||||||
|
|
||||||
|
cc := "/Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/c.js \"" + contentFile + "\" \"" + path + "\""
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", cc)
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
re.Ok = true
|
||||||
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置/取消Blog; 置顶
|
||||||
|
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||||
|
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
)
|
)
|
||||||
@@ -29,11 +29,14 @@ func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加notebook
|
// 添加notebook
|
||||||
func (c Notebook) AddNotebook(notebookId, title string) revel.Result {
|
func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.Result {
|
||||||
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
|
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||||
Title: title,
|
Title: title,
|
||||||
Seq: -1,
|
Seq: -1,
|
||||||
UserId: c.GetObjectUserId()}
|
UserId: c.GetObjectUserId()}
|
||||||
|
if(parentNotebookId != "") {
|
||||||
|
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
||||||
|
}
|
||||||
re := notebookService.AddNotebook(notebook)
|
re := notebookService.AddNotebook(notebook)
|
||||||
|
|
||||||
if(re) {
|
if(re) {
|
||||||
@@ -46,7 +49,29 @@ func (c Notebook) AddNotebook(notebookId, title string) revel.Result {
|
|||||||
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||||
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
|
// 无用
|
||||||
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||||
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
|
||||||
|
type DragNotebooksInfo struct {
|
||||||
|
CurNotebookId string
|
||||||
|
ParentNotebookId string
|
||||||
|
Siblings []string
|
||||||
|
}
|
||||||
|
// 传过来的data是JSON.stringfy数据
|
||||||
|
func (c Notebook) DragNotebooks(data string) revel.Result {
|
||||||
|
info := DragNotebooksInfo{}
|
||||||
|
json.Unmarshal([]byte(data), &info)
|
||||||
|
|
||||||
|
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置notebook <-> blog
|
||||||
|
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||||
|
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -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(""))
|
||||||
|
}
|
||||||
@@ -3,18 +3,21 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
// "labix.org/v2/mgo/bson"
|
// "gopkg.in/mgo.v2/bson"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Share struct {
|
type Share struct {
|
||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AttachToken = 2
|
||||||
|
|
||||||
// 添加共享note
|
// 添加共享note
|
||||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -36,6 +39,8 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
|||||||
return c.RenderJson(status)
|
return c.RenderJson(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 添加共享notebook
|
// 添加共享notebook
|
||||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||||
status := make(map[string]info.Re, len(emails))
|
status := make(map[string]info.Re, len(emails))
|
||||||
@@ -87,6 +92,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
|||||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||||
|
|
||||||
|
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = true
|
c.RenderArgs["isNote"] = true
|
||||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||||
c.RenderArgs["title"] = note.Title
|
c.RenderArgs["title"] = note.Title
|
||||||
@@ -99,6 +106,9 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
|||||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||||
|
|
||||||
|
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||||
|
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = false
|
c.RenderArgs["isNote"] = false
|
||||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||||
c.RenderArgs["title"] = notebook.Title
|
c.RenderArgs["title"] = notebook.Title
|
||||||
@@ -140,3 +150,104 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str
|
|||||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------
|
||||||
|
// 用户组
|
||||||
|
|
||||||
|
|
||||||
|
// 将笔记分享给分组
|
||||||
|
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 更新, 也是一样, 先删后加
|
||||||
|
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
|
||||||
|
return c.AddShareNoteGroup(noteId, groupId, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------
|
||||||
|
|
||||||
|
// 将笔记分享给分组
|
||||||
|
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 更新, 也是一样, 先删后加
|
||||||
|
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||||
|
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
//生成笔记分享密码及更新到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)
|
||||||
|
}
|
||||||
@@ -3,12 +3,12 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
// "labix.org/v2/mgo/bson"
|
// "gopkg.in/mgo.v2/bson"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
"fmt"
|
// "fmt"
|
||||||
// "math"
|
// "math"
|
||||||
// "os"
|
// "os"
|
||||||
// "path"
|
// "path"
|
||||||
@@ -19,43 +19,48 @@ type User struct {
|
|||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c User) Account(tab int) revel.Result {
|
||||||
|
userInfo := c.GetUserInfo()
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
c.RenderArgs["tab"] = tab
|
||||||
|
c.SetLocale()
|
||||||
|
return c.RenderTemplate("user/account.html")
|
||||||
|
}
|
||||||
|
|
||||||
// 修改用户名, 需要重置session
|
// 修改用户名, 需要重置session
|
||||||
func (c User) UpdateUsername(username string) revel.Result {
|
func (c User) UpdateUsername(username string) revel.Result {
|
||||||
re := info.NewRe();
|
re := info.NewRe();
|
||||||
// 判断是否满足最基本的, 4位, 不含特殊字符, 大小写无关. email大小写无关
|
if(c.GetUsername() == "demo") {
|
||||||
if len(username) < 4 {
|
re.Msg = "cannotUpdateDemo"
|
||||||
re.Ok = false
|
return c.RenderRe(re);
|
||||||
re.Msg = "至少4位"
|
|
||||||
return c.RenderJson(re);
|
|
||||||
}
|
}
|
||||||
if !IsUsername(username) {
|
|
||||||
re.Ok = false
|
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
||||||
re.Msg = "不能包含特殊字符"
|
return c.RenderRe(re);
|
||||||
return c.RenderJson(re);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
|
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
|
||||||
if(re.Ok) {
|
if(re.Ok) {
|
||||||
c.UpdateSession("Username", username)
|
c.UpdateSession("Username", username)
|
||||||
}
|
}
|
||||||
return c.RenderJson(re);
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改密码
|
// 修改密码
|
||||||
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
||||||
re := info.NewRe();
|
re := info.NewRe();
|
||||||
if oldPwd == "" {
|
if(c.GetUsername() == "demo") {
|
||||||
re.Msg = "旧密码错误"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderJson(re);
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
||||||
re.Ok, re.Msg = IsGoodPwd(pwd)
|
return c.RenderRe(re);
|
||||||
if !re.Ok {
|
}
|
||||||
return c.RenderJson(re);
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
|
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
|
||||||
return c.RenderJson(re);
|
return c.RenderRe(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新主题
|
// 更新主题
|
||||||
@@ -75,13 +80,7 @@ func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
|||||||
return c.RenderJson(re);
|
return c.RenderJson(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送邮件
|
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
|
||||||
var userInfo = c.GetUserInfo();
|
|
||||||
url := "http://leanote.com/register?from=" + userInfo.Username
|
|
||||||
body := fmt.Sprintf("点击链接注册leanote: <a href='%v'>%v</a>. ", url, url);
|
|
||||||
body = content + "<br />" + body
|
|
||||||
re.Ok = SendEmail(toEmail, userInfo.Username + "邀请您注册leanote", "邀请注册", body)
|
|
||||||
|
|
||||||
return c.RenderJson(re);
|
return c.RenderJson(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,15 +89,23 @@ func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
|||||||
// 重新发送激活邮件
|
// 重新发送激活邮件
|
||||||
func (c User) ReSendActiveEmail() revel.Result {
|
func (c User) ReSendActiveEmail() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = userService.RegisterSendActiveEmail(c.GetUserId(), c.GetEmail())
|
re.Ok = emailService.RegisterSendActiveEmail(c.GetUserInfo(), c.GetEmail())
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改Email发送激活邮箱
|
// 修改Email发送激活邮箱
|
||||||
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
|
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = userService.UpdateEmailSendActiveEmail(c.GetUserId(), email)
|
if(c.GetUsername() == "demo") {
|
||||||
return c.RenderJson(re)
|
re.Msg = "cannotUpdateDemo"
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok, re.Msg = emailService.UpdateEmailSendActiveEmail(c.GetUserInfo(), email)
|
||||||
|
return c.RenderRe(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过点击链接
|
// 通过点击链接
|
||||||
@@ -145,21 +152,11 @@ func (c User) ActiveEmail(token string) revel.Result {
|
|||||||
func (c User) AddAccount(email, pwd string) revel.Result {
|
func (c User) AddAccount(email, pwd string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
|
|
||||||
if email == "" {
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
re.Msg = "请输入邮箱"
|
return c.RenderRe(re);
|
||||||
return c.RenderJson(re)
|
|
||||||
} else if !IsEmail(email) {
|
|
||||||
re.Msg = "请输入正确的邮箱"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
// 密码
|
return c.RenderRe(re);
|
||||||
if pwd == "" {
|
|
||||||
re.Msg = "请输入密码"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
} else if len(pwd) < 6 {
|
|
||||||
re.Msg = "密码长度至少6位"
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.ThirdAddUser(c.GetUserId(), email, pwd)
|
re.Ok, re.Msg = userService.ThirdAddUser(c.GetUserId(), email, pwd)
|
||||||
@@ -168,17 +165,20 @@ func (c User) AddAccount(email, pwd string) revel.Result {
|
|||||||
c.UpdateSession("Email", email);
|
c.UpdateSession("Email", email);
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderRe(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------
|
//-----------------
|
||||||
// 用户偏爱
|
// 用户偏爱
|
||||||
func (c User) UpdateColumnWidth(notebookWidth, noteListWidth int) revel.Result {
|
func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth)
|
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth, mdEditorWidth)
|
||||||
if re.Ok {
|
if re.Ok {
|
||||||
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
|
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
|
||||||
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
|
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
|
||||||
|
c.UpdateSession("MdEditorWidth", strconv.Itoa(mdEditorWidth));
|
||||||
|
|
||||||
|
LogJ(c.Session)
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
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 AdminBaseController struct {
|
||||||
|
controllers.BaseController // 不能用*BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到sorterField 和 isAsc
|
||||||
|
// okSorter = ['email', 'username']
|
||||||
|
func (c AdminBaseController) 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 AdminBaseController) updateConfig(keys []string) {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
for _, key := range keys {
|
||||||
|
v := c.Params.Values.Get(key)
|
||||||
|
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type AdminBlog struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
||||||
|
pageNumber := c.GetPage()
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
|
||||||
|
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||||
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
|
c.RenderArgs["blogs"] = blogs
|
||||||
|
c.RenderArgs["keywords"] = keywords
|
||||||
|
return c.RenderTemplate("admin/blog/list.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.SetRecommend(noteId, recommend);
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type Admin struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
func (c Admin) Index() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = "leanote"
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
c.RenderArgs["countUser"] = userService.CountUser()
|
||||||
|
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||||
|
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||||
|
|
||||||
|
return c.RenderTemplate("admin/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板
|
||||||
|
func (c Admin) 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
|
||||||
|
c.RenderArgs["version"] = configService.GetVersion()
|
||||||
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Admin) GetView(view string) revel.Result {
|
||||||
|
return c.RenderTemplate("admin/" + view);
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"os"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 数据管理, 备份和恢复
|
||||||
|
|
||||||
|
type AdminData struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminData) Index() revel.Result {
|
||||||
|
backups := configService.GetGlobalArrMapConfig("backups")
|
||||||
|
// 逆序之
|
||||||
|
backups2 := make([]map[string]string, len(backups))
|
||||||
|
j := 0
|
||||||
|
for i := len(backups)-1; i >= 0; i-- {
|
||||||
|
backups2[j] = backups[i]
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
c.RenderArgs["backups"] = backups2
|
||||||
|
return c.RenderTemplate("admin/data/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminData) Backup() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = configService.Backup("")
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 还原
|
||||||
|
func (c AdminData) Restore(createdTime string) revel.Result {
|
||||||
|
re := info.Re{}
|
||||||
|
re.Ok, re.Msg = configService.Restore(createdTime)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminData) Delete(createdTime string) revel.Result {
|
||||||
|
re := info.Re{}
|
||||||
|
re.Ok, re.Msg = configService.DeleteBackup(createdTime)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c AdminData) UpdateRemark(createdTime, remark string) revel.Result {
|
||||||
|
re := info.Re{}
|
||||||
|
re.Ok, re.Msg = configService.UpdateBackupRemark(createdTime, remark)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c AdminData) Download(createdTime string) revel.Result {
|
||||||
|
backup, ok := configService.GetBackup(createdTime)
|
||||||
|
if !ok {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
dbname, _ := revel.Config.String("db.dbname")
|
||||||
|
path := backup["path"] + "/" + dbname
|
||||||
|
allFiles := ListDir(path)
|
||||||
|
|
||||||
|
filename := "backup_" + dbname + "_" + backup["createdTime"] + ".tar.gz"
|
||||||
|
|
||||||
|
// file write
|
||||||
|
fw, err := os.Create(revel.BasePath + "/files/" + filename)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
// defer fw.Close() // 不需要关闭, 还要读取给用户下载
|
||||||
|
// gzip write
|
||||||
|
gw := gzip.NewWriter(fw)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
// tar write
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// 遍历文件列表
|
||||||
|
for _, file := range allFiles {
|
||||||
|
fn := path + "/" + file
|
||||||
|
fr, err := os.Open(fn)
|
||||||
|
fileInfo, _ := fr.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("")
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// 信息头
|
||||||
|
h := new(tar.Header)
|
||||||
|
h.Name = file
|
||||||
|
h.Size = fileInfo.Size()
|
||||||
|
h.Mode = int64(fileInfo.Mode())
|
||||||
|
h.ModTime = fileInfo.ModTime()
|
||||||
|
|
||||||
|
// 写信息头
|
||||||
|
err = tw.WriteHeader(h)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写文件
|
||||||
|
_, err = io.Copy(tw, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} // for
|
||||||
|
|
||||||
|
return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachm
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type AdminEmail struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// email配置
|
||||||
|
func (c AdminEmail) Email() revel.Result {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// blog标签设置
|
||||||
|
func (c AdminEmail) Blog() revel.Result {
|
||||||
|
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
||||||
|
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||||
|
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||||
|
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
||||||
|
return c.RenderTemplate("admin/setting/blog.html");
|
||||||
|
}
|
||||||
|
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// demo
|
||||||
|
// blog标签设置
|
||||||
|
func (c AdminEmail) Demo() revel.Result {
|
||||||
|
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||||
|
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||||
|
return c.RenderTemplate("admin/setting/demo.html");
|
||||||
|
}
|
||||||
|
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
userInfo := authService.Login(demoUsername, demoPassword)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
re.Msg = "The User is Not Exists";
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToImage
|
||||||
|
// 长微博的bin路径phantomJs
|
||||||
|
func (c AdminEmail) ToImage() revel.Result {
|
||||||
|
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
|
return c.RenderTemplate("admin/setting/toImage.html");
|
||||||
|
}
|
||||||
|
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailHost", emailHost)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPort", emailPort)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailUsername", emailUsername)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c AdminEmail) Template() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
keys := []string{"emailTemplateHeader", "emailTemplateFooter",
|
||||||
|
"emailTemplateRegisterSubject",
|
||||||
|
"emailTemplateRegister",
|
||||||
|
"emailTemplateFindPasswordSubject",
|
||||||
|
"emailTemplateFindPassword",
|
||||||
|
"emailTemplateUpdateEmailSubject",
|
||||||
|
"emailTemplateUpdateEmail",
|
||||||
|
"emailTemplateInviteSubject",
|
||||||
|
"emailTemplateInvite",
|
||||||
|
"emailTemplateCommentSubject",
|
||||||
|
"emailTemplateComment",
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := c.GetUserId()
|
||||||
|
for _, key := range keys {
|
||||||
|
v := c.Params.Values.Get(key)
|
||||||
|
if v != "" {
|
||||||
|
ok, msg := emailService.ValidTpl(v)
|
||||||
|
if !ok {
|
||||||
|
re.Ok = false
|
||||||
|
re.Msg = "Error key: " + key + "<br />" + msg
|
||||||
|
return c.RenderJson(re)
|
||||||
|
} else {
|
||||||
|
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送Email
|
||||||
|
func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
|
||||||
|
|
||||||
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
|
re.Msg = "subject or body is blank"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
if saveAsOldEmail {
|
||||||
|
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||||
|
oldEmails[latestEmailSubject] = latestEmailBody
|
||||||
|
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEmails = strings.Replace(sendEmails, "\r", "", -1)
|
||||||
|
emails := strings.Split(sendEmails, "\n")
|
||||||
|
|
||||||
|
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody);
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送Email
|
||||||
|
func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
c.updateConfig([]string{"sendEmails", "latestEmailSubject", "latestEmailBody"})
|
||||||
|
|
||||||
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
|
re.Msg = "subject or body is blank"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
if saveAsOldEmail {
|
||||||
|
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||||
|
oldEmails[latestEmailSubject] = latestEmailBody
|
||||||
|
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||||
|
}
|
||||||
|
|
||||||
|
emails = strings.Replace(emails, "\r", "", -1)
|
||||||
|
emailsArr := strings.Split(emails, "\n")
|
||||||
|
|
||||||
|
users := userService.ListUserInfosByEmails(emailsArr)
|
||||||
|
LogJ(emailsArr)
|
||||||
|
|
||||||
|
|
||||||
|
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send Email dialog
|
||||||
|
func (c AdminEmail) SendEmailDialog(emails string) revel.Result{
|
||||||
|
emailsArr := strings.Split(emails, ",")
|
||||||
|
emailsNl := strings.Join(emailsArr, "\n")
|
||||||
|
|
||||||
|
c.RenderArgs["emailsNl"] = emailsNl
|
||||||
|
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||||
|
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||||
|
|
||||||
|
return c.RenderTemplate("admin/email/emailDialog.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilterBlackList, latestEmailSubject, latestEmailBody string, verified, saveAsOldEmail bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
c.updateConfig([]string{"userFilterEmail", "userFilterWhiteList", "userFilterBlackList", "latestEmailSubject", "latestEmailBody"})
|
||||||
|
|
||||||
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
|
re.Msg = "subject or body is blank"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
if saveAsOldEmail {
|
||||||
|
oldEmails := configService.GetGlobalMapConfig("oldEmails")
|
||||||
|
oldEmails[latestEmailSubject] = latestEmailBody
|
||||||
|
configService.UpdateGlobalMapConfig(c.GetUserId(), "oldEmails", oldEmails);
|
||||||
|
}
|
||||||
|
|
||||||
|
users := userService.GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList, verified)
|
||||||
|
|
||||||
|
if(users == nil || len(users) == 0) {
|
||||||
|
re.Ok = false
|
||||||
|
re.Msg = "no users"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody);
|
||||||
|
if(!re.Ok) {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok = true
|
||||||
|
re.Msg = "users:" + strconv.Itoa(len(users))
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除emails
|
||||||
|
func (c AdminEmail) DeleteEmails(ids string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = emailService.DeleteEmails(strings.Split(ids, ","))
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminEmail) List(sorter, keywords string) revel.Result {
|
||||||
|
pageNumber := c.GetPage()
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"});
|
||||||
|
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
||||||
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
|
c.RenderArgs["emails"] = emails
|
||||||
|
c.RenderArgs["keywords"] = keywords
|
||||||
|
return c.RenderTemplate("admin/email/list.html");
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type AdminSetting struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// email配置
|
||||||
|
func (c AdminSetting) Email() revel.Result {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// blog标签设置
|
||||||
|
func (c AdminSetting) Blog() revel.Result {
|
||||||
|
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
||||||
|
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||||
|
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||||
|
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
||||||
|
return c.RenderTemplate("admin/setting/blog.html");
|
||||||
|
}
|
||||||
|
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 共享设置
|
||||||
|
func (c AdminSetting) ShareNote(registerSharedUserId string,
|
||||||
|
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||||
|
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) revel.Result {
|
||||||
|
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds);
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// demo
|
||||||
|
// blog标签设置
|
||||||
|
func (c AdminSetting) Demo() revel.Result {
|
||||||
|
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||||
|
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||||
|
return c.RenderTemplate("admin/setting/demo.html");
|
||||||
|
}
|
||||||
|
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
userInfo := authService.Login(demoUsername, demoPassword)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
re.Msg = "The User is Not Exists";
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToImage
|
||||||
|
// 长微博的bin路径phantomJs
|
||||||
|
func (c AdminSetting) ToImage() revel.Result {
|
||||||
|
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
|
return c.RenderTemplate("admin/setting/toImage.html");
|
||||||
|
}
|
||||||
|
func (c AdminSetting) DoToImage(toImageBinPath string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubDomain
|
||||||
|
func (c AdminSetting) SubDomain() revel.Result {
|
||||||
|
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||||
|
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
|
|
||||||
|
c.RenderArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
|
||||||
|
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
|
||||||
|
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
|
||||||
|
|
||||||
|
return c.RenderTemplate("admin/setting/subDomain.html");
|
||||||
|
}
|
||||||
|
func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, blackSubDomains, allowCustomDomain, blackCustomDomains string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "noteSubDomain", noteSubDomain)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "blogSubDomain", blogSubDomain)
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "leaSubDomain", leaSubDomain)
|
||||||
|
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "allowCustomDomain", allowCustomDomain)
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackSubDomains", strings.Split(blackSubDomains, ","))
|
||||||
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackCustomDomains", strings.Split(blackCustomDomains, ","))
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "openRegister", openRegister)
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
// "io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upgrade controller
|
||||||
|
type AdminUpgrade struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "time"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type AdminUser struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
var userPageSize = 10
|
||||||
|
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||||
|
pageNumber := c.GetPage()
|
||||||
|
if userPageSize == 0 {
|
||||||
|
pageSize = userPageSize
|
||||||
|
}
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
|
||||||
|
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
|
||||||
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
|
c.RenderArgs["users"] = users
|
||||||
|
c.RenderArgs["keywords"] = keywords
|
||||||
|
return c.RenderTemplate("admin/user/list.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
// 拦截器
|
||||||
|
// 不需要拦截的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 username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() {
|
||||||
|
return nil // 已登录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有登录, 判断是否是ajax操作
|
||||||
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Msg = "NOTLOGIN"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect("/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最外层init.go调用
|
||||||
|
// 获取service, 单例
|
||||||
|
func InitService() {
|
||||||
|
notebookService = service.NotebookS
|
||||||
|
noteService = service.NoteS
|
||||||
|
noteContentHistoryService = service.NoteContentHistoryS
|
||||||
|
trashService = service.TrashS
|
||||||
|
shareService = service.ShareS
|
||||||
|
userService = service.UserS
|
||||||
|
tagService = service.TagS
|
||||||
|
blogService = service.BlogS
|
||||||
|
tokenService = service.TokenS
|
||||||
|
noteImageService = service.NoteImageS
|
||||||
|
fileService = service.FileS
|
||||||
|
albumService= service.AlbumS
|
||||||
|
attachService = service.AttachS
|
||||||
|
pwdService = service.PwdS
|
||||||
|
suggestionService = service.SuggestionS
|
||||||
|
authService = service.AuthS
|
||||||
|
configService = service.ConfigS
|
||||||
|
emailService = service.EmailS
|
||||||
|
upgradeService = service.UpgradeS
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Admin{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminSetting{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUser{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminBlog{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{})
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/info"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
// "strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApiUser struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户名, 需要重置session
|
||||||
|
func (c ApiUser) Info() revel.Result {
|
||||||
|
Log("APIUser");
|
||||||
|
return c.RenderTemplate("home/index.html");
|
||||||
|
// return nil;
|
||||||
|
}
|
||||||
+77
-47
@@ -3,18 +3,17 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/service"
|
"github.com/leanote/leanote/app/service"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/lea/blog"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 该文件初始化所有service方法
|
|
||||||
|
|
||||||
var userService *service.UserService
|
var userService *service.UserService
|
||||||
var noteService *service.NoteService
|
var noteService *service.NoteService
|
||||||
var trashService *service.TrashService
|
var trashService *service.TrashService
|
||||||
var notebookService *service.NotebookService
|
var notebookService *service.NotebookService
|
||||||
var noteContentHistoryService *service.NoteContentHistoryService
|
var noteContentHistoryService *service.NoteContentHistoryService
|
||||||
|
|
||||||
var authService *service.AuthService
|
var authService *service.AuthService
|
||||||
var shareService *service.ShareService
|
var shareService *service.ShareService
|
||||||
var blogService *service.BlogService
|
var blogService *service.BlogService
|
||||||
@@ -22,50 +21,68 @@ var tagService *service.TagService
|
|||||||
var pwdService *service.PwdService
|
var pwdService *service.PwdService
|
||||||
var tokenService *service.TokenService
|
var tokenService *service.TokenService
|
||||||
var suggestionService *service.SuggestionService
|
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 pageSize = 1000
|
||||||
var defaultSortField = "UpdatedTime"
|
var defaultSortField = "UpdatedTime"
|
||||||
var leanoteUserId = "52d26b4e99c37b609a000001"
|
|
||||||
var siteUrl = "http://leanote.com"
|
|
||||||
var openRegister = true
|
|
||||||
|
|
||||||
// 拦截器
|
// 拦截器
|
||||||
// 不需要拦截的url
|
// 不需要拦截的url
|
||||||
// Index 除了Note之外都不需要
|
// Index 除了Note之外都不需要
|
||||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||||
"Login": true,
|
"Login": true,
|
||||||
"DoLogin": true,
|
"DoLogin": true,
|
||||||
"Logout": true,
|
"Logout": true,
|
||||||
"Register": true,
|
"Register": true,
|
||||||
"DoRegister": true,
|
"DoRegister": true,
|
||||||
"FindPasswword": true,
|
"FindPasswword": true,
|
||||||
"DoFindPassword": true,
|
"DoFindPassword": true,
|
||||||
"FindPassword2": true,
|
"FindPassword2": true,
|
||||||
"FindPasswordUpdate": true,
|
"FindPasswordUpdate": true,
|
||||||
"Suggestion": true,
|
"Suggestion": true,
|
||||||
},
|
},
|
||||||
|
"Note": map[string]bool{"ToImage": true},
|
||||||
|
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
|
||||||
"Blog": map[string]bool{"Index": true,
|
"Blog": map[string]bool{"Index": true,
|
||||||
"View": true,
|
"View": true,
|
||||||
"AboutMe": true,
|
"AboutMe": true,
|
||||||
"SearchBlog": true,
|
"Cate": true,
|
||||||
},
|
"ListCateLatest": true,
|
||||||
|
"Search": true,
|
||||||
|
"GetLikeAndComments": true,
|
||||||
|
"IncReadNum": true,
|
||||||
|
"ListComments": true,
|
||||||
|
"Single": true,
|
||||||
|
"Archive": true,
|
||||||
|
"Tags": true,
|
||||||
|
},
|
||||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||||
"User": map[string]bool{"UpdateEmail": true,
|
"User": map[string]bool{"UpdateEmail": true,
|
||||||
"ActiveEmail":true,
|
"ActiveEmail": true,
|
||||||
},
|
},
|
||||||
"oauth": map[string]bool{"githubCallback": true},
|
"Oauth": map[string]bool{"GithubCallback": true},
|
||||||
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
|
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||||
}
|
}
|
||||||
|
|
||||||
func needValidate(controller, method string) bool {
|
func needValidate(controller, method string) bool {
|
||||||
// 在里面
|
// 在里面
|
||||||
if v, ok := commonUrl[controller]; ok {
|
if v, ok := commonUrl[controller]; ok {
|
||||||
// 不在commonUrl里
|
// 在commonUrl里
|
||||||
if _, ok2 := v[method]; ok2 {
|
if _, ok2 := v[method]; ok2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
// controller不在这里的, 肯定要验证
|
// controller不在这里的, 肯定要验证
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||||
@@ -73,13 +90,11 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
var controller = strings.Title(c.Name)
|
var controller = strings.Title(c.Name)
|
||||||
var method = strings.Title(c.MethodName)
|
var method = strings.Title(c.MethodName)
|
||||||
|
|
||||||
|
|
||||||
// 是否需要验证?
|
// 是否需要验证?
|
||||||
if !needValidate(controller, method) {
|
if !needValidate(controller, method) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 验证是否已登录
|
// 验证是否已登录
|
||||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||||
return nil // 已登录
|
return nil // 已登录
|
||||||
@@ -95,6 +110,36 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
return c.Redirect("/login")
|
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
|
||||||
|
tagService = service.TagS
|
||||||
|
blogService = service.BlogS
|
||||||
|
tokenService = service.TokenS
|
||||||
|
noteImageService = service.NoteImageS
|
||||||
|
fileService = service.FileS
|
||||||
|
albumService = service.AlbumS
|
||||||
|
attachService = service.AttachS
|
||||||
|
pwdService = service.PwdS
|
||||||
|
suggestionService = service.SuggestionS
|
||||||
|
authService = service.AuthS
|
||||||
|
configService = service.ConfigS
|
||||||
|
emailService = service.EmailS
|
||||||
|
sessionService = service.SessionS
|
||||||
|
themeService = service.ThemeS
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化博客模板
|
||||||
|
// 博客模板不由revel的
|
||||||
|
func initBlogTemplate() {
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// interceptor
|
// interceptor
|
||||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
||||||
@@ -103,27 +148,12 @@ func init() {
|
|||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||||
|
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||||
|
|
||||||
// service
|
|
||||||
|
|
||||||
userService = &service.UserService{}
|
|
||||||
noteService = &service.NoteService{}
|
|
||||||
trashService = &service.TrashService{}
|
|
||||||
notebookService = &service.NotebookService{}
|
|
||||||
noteContentHistoryService = &service.NoteContentHistoryService{}
|
|
||||||
authService = &service.AuthService{}
|
|
||||||
shareService = &service.ShareService{}
|
|
||||||
blogService = &service.BlogService{}
|
|
||||||
tagService = &service.TagService{}
|
|
||||||
pwdService = &service.PwdService{}
|
|
||||||
tokenService = &service.TokenService{}
|
|
||||||
suggestionService = &service.SuggestionService{}
|
|
||||||
|
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
leanoteUserId, _ = revel.Config.String("adminUsername")
|
// 博客初始化模板
|
||||||
siteUrl, _ = revel.Config.String("site.url")
|
blog.Init()
|
||||||
openRegister, _ = revel.Config.Bool("register.open")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
@@ -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() {
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
包括基本信息设置
|
||||||
|
博客设置
|
||||||
+80
-20
@@ -2,9 +2,10 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"labix.org/v2/mgo"
|
|
||||||
"labix.org/v2/mgo/bson"
|
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"gopkg.in/mgo.v2"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init mgo and the common DAO
|
// Init mgo and the common DAO
|
||||||
@@ -23,9 +24,12 @@ var ShareNotebooks *mgo.Collection
|
|||||||
var HasShareNotes *mgo.Collection
|
var HasShareNotes *mgo.Collection
|
||||||
var Blogs *mgo.Collection
|
var Blogs *mgo.Collection
|
||||||
var Users *mgo.Collection
|
var Users *mgo.Collection
|
||||||
|
var Groups *mgo.Collection
|
||||||
|
var GroupUsers *mgo.Collection
|
||||||
|
|
||||||
var Tags *mgo.Collection
|
var Tags *mgo.Collection
|
||||||
var TagNotes *mgo.Collection
|
//var TagNotes *mgo.Collection
|
||||||
|
var TagCounts *mgo.Collection
|
||||||
|
|
||||||
var UserBlogs *mgo.Collection
|
var UserBlogs *mgo.Collection
|
||||||
|
|
||||||
@@ -33,13 +37,35 @@ var Tokens *mgo.Collection
|
|||||||
|
|
||||||
var Suggestions *mgo.Collection
|
var Suggestions *mgo.Collection
|
||||||
|
|
||||||
|
// Album & file(image)
|
||||||
|
var Albums *mgo.Collection
|
||||||
|
var Files *mgo.Collection
|
||||||
|
var Attachs *mgo.Collection
|
||||||
|
|
||||||
|
var NoteImages *mgo.Collection
|
||||||
|
var Configs *mgo.Collection
|
||||||
|
var EmailLogs *mgo.Collection
|
||||||
|
|
||||||
|
// blog
|
||||||
|
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() {
|
func Init(url, dbname string) {
|
||||||
var url string
|
ok := true
|
||||||
var ok bool
|
config := revel.Config
|
||||||
config := revel.Config;
|
if url == "" {
|
||||||
url, ok = config.String("db.url")
|
url, ok = config.String("db.url")
|
||||||
dbname, _ := config.String("db.dbname")
|
}
|
||||||
|
if dbname == "" {
|
||||||
|
dbname, _ = config.String("db.dbname")
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
host, _ := revel.Config.String("db.host")
|
host, _ := revel.Config.String("db.host")
|
||||||
port, _ := revel.Config.String("db.port")
|
port, _ := revel.Config.String("db.port")
|
||||||
@@ -49,8 +75,9 @@ func Init() {
|
|||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
usernameAndPassword = ""
|
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://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
||||||
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||||
@@ -80,28 +107,48 @@ func Init() {
|
|||||||
|
|
||||||
// user
|
// user
|
||||||
Users = Session.DB(dbname).C("users")
|
Users = Session.DB(dbname).C("users")
|
||||||
|
// group
|
||||||
|
Groups = Session.DB(dbname).C("groups")
|
||||||
|
GroupUsers = Session.DB(dbname).C("group_users")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
Blogs = Session.DB(dbname).C("blogs")
|
Blogs = Session.DB(dbname).C("blogs")
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
Tags = Session.DB(dbname).C("tags")
|
Tags = Session.DB(dbname).C("tags")
|
||||||
TagNotes = Session.DB(dbname).C("tag_notes")
|
// TagNotes = Session.DB(dbname).C("tag_notes")
|
||||||
|
TagCounts = Session.DB(dbname).C("tag_count")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||||
|
BlogSingles = Session.DB(dbname).C("blog_singles")
|
||||||
|
Themes = Session.DB(dbname).C("themes")
|
||||||
|
|
||||||
// find password
|
// find password
|
||||||
Tokens = Session.DB(dbname).C("tokens")
|
Tokens = Session.DB(dbname).C("tokens")
|
||||||
|
|
||||||
//
|
// Suggestion
|
||||||
Suggestions = Session.DB(dbname).C("suggestions")
|
Suggestions = Session.DB(dbname).C("suggestions")
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
// Album & file
|
||||||
revel.OnAppStart(func() {
|
Albums = Session.DB(dbname).C("albums")
|
||||||
Init()
|
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
func close() {
|
func close() {
|
||||||
@@ -143,22 +190,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId,
|
|||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
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 {
|
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
|
func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
|
return Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
// 查询条件和值
|
// 查询条件和值
|
||||||
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
@@ -224,6 +278,7 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i
|
|||||||
}
|
}
|
||||||
collection.Find(q).Select(selector).One(i)
|
collection.Find(q).Select(selector).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||||
selector := make(bson.M, len(fields))
|
selector := make(bson.M, len(fields))
|
||||||
@@ -239,6 +294,11 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i
|
|||||||
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按field去重
|
||||||
|
func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) {
|
||||||
|
collection.Find(q).Distinct(field, i)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
|
|
||||||
func Count(collection *mgo.Collection, q interface{}) int {
|
func Count(collection *mgo.Collection, q interface{}) int {
|
||||||
@@ -272,7 +332,7 @@ func Err(err error) bool {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
// 删除时, 查找
|
// 删除时, 查找
|
||||||
if err.Error() == "not found" {
|
if err.Error() == "not found" {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-3
@@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
// convert revel msg to js msg
|
// convert revel msg to js msg
|
||||||
|
|
||||||
var msgBasePath = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/messages/"
|
var msgBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/messages/"
|
||||||
var targetBasePath = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/public/js/i18n/"
|
var targetBasePath = "/Users/life/Documents/Go/package1/src/github.com/leanote/leanote/public/js/i18n/"
|
||||||
func parse(filename string) {
|
func parse(filename string) {
|
||||||
file, err := os.Open(msgBasePath + filename)
|
file, err := os.Open(msgBasePath + filename)
|
||||||
reader := bufio.NewReader(file)
|
reader := bufio.NewReader(file)
|
||||||
@@ -62,11 +62,28 @@ func parse(filename string) {
|
|||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
file2, err2 = os.Create(targetName)
|
file2, err2 = os.Create(targetName)
|
||||||
}
|
}
|
||||||
file2.WriteString("var MSG = " + str + ";")
|
file2.WriteString("var MSG = " + str + ";" + `
|
||||||
|
function getMsg(key, data) {
|
||||||
|
var msg = MSG[key]
|
||||||
|
if(msg) {
|
||||||
|
if(data) {
|
||||||
|
if(!isArray(data)) {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
for(var i = 0; i < data.length; ++i) {
|
||||||
|
msg = msg.replace("%s", data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成js的i18n文件
|
// 生成js的i18n文件
|
||||||
func main() {
|
func main() {
|
||||||
parse("msg.en")
|
parse("msg.en")
|
||||||
parse("msg.zh")
|
parse("msg.zh")
|
||||||
|
parse("blog.zh")
|
||||||
|
parse("blog.en")
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Album struct {
|
||||||
|
AlbumId bson.ObjectId `bson:"_id,omitempty"` //
|
||||||
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
|
Name string `Name` // album name
|
||||||
|
Type int `Type` // type, the default is image: 0
|
||||||
|
Seq int `Seq`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attach belongs to note
|
||||||
|
type Attach struct {
|
||||||
|
AttachId bson.ObjectId `bson:"_id,omitempty"` //
|
||||||
|
NoteId bson.ObjectId `bson:"NoteId"` //
|
||||||
|
UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
|
||||||
|
Name string `Name` // file name, md5, such as 13232312.doc
|
||||||
|
Title string `Title` // raw file name
|
||||||
|
Size int64 `Size` // file size (byte)
|
||||||
|
Type string `Type` // file type, "doc" = word
|
||||||
|
Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|
||||||
|
// FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
+101
-16
@@ -1,43 +1,128 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 只为blog, 不为note
|
// 只为blog, 不为note
|
||||||
|
|
||||||
type BlogItem struct {
|
type BlogItem struct {
|
||||||
Note
|
Note
|
||||||
|
Abstract string
|
||||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||||
HasMore bool // 是否是否还有
|
HasMore bool // 是否是否还有
|
||||||
|
User User // 用户信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogBase struct {
|
type UserBlogBase struct {
|
||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
// AboutMe string `AboutMe` // 关于我
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogComment struct {
|
type UserBlogComment struct {
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
DisqusId string `DisqusId`
|
CommentType string `CommentType` // default 或 disqus
|
||||||
|
DisqusId string `DisqusId`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogStyle struct {
|
type UserBlogStyle struct {
|
||||||
Style string `Style` // 风格
|
Style string `Style` // 风格
|
||||||
|
Css string `Css` // 自定义css
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每个用户一份博客设置信息
|
// 每个用户一份博客设置信息
|
||||||
type UserBlog struct {
|
type UserBlog struct {
|
||||||
UserId bson.ObjectId `bson:"_id"` // 谁的
|
UserId bson.ObjectId `bson:"_id"` // 谁的
|
||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
AboutMe string `AboutMe` // 关于我, 弃用
|
||||||
|
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
DisqusId string `DisqusId`
|
|
||||||
|
CommentType string `CommentType` // default 或 disqus
|
||||||
|
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` // 自定义域名
|
||||||
|
|
||||||
Style string `Style` // 风格
|
}
|
||||||
|
|
||||||
|
// 博客统计信息
|
||||||
|
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`
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// 社交功能, 点赞, 分享, 评论
|
||||||
|
|
||||||
|
// 点赞记录
|
||||||
|
type BlogLike struct {
|
||||||
|
LikeId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
NoteId bson.ObjectId `NoteId`
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 评论
|
||||||
|
type BlogComment struct {
|
||||||
|
CommentId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
NoteId bson.ObjectId `NoteId`
|
||||||
|
|
||||||
|
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
||||||
|
Content string `Content` // 评论内容
|
||||||
|
|
||||||
|
ToCommentId bson.ObjectId `ToCommendId,omitempty` // 对某条评论进行回复
|
||||||
|
ToUserId bson.ObjectId `ToUserId,omitempty` // 为空表示直接评论, 不回空表示回复某人
|
||||||
|
|
||||||
|
LikeNum int `LikeNum` // 点赞次数, 评论也可以点赞
|
||||||
|
LikeUserIds []string `LikeUserIds` // 点赞的用户ids
|
||||||
|
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 配置, 每一个配置一行记录
|
||||||
|
type Config struct {
|
||||||
|
ConfigId bson.ObjectId `bson:"_id"`
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
Key string `Key`
|
||||||
|
ValueStr string `ValueStr,omitempty` // "1"
|
||||||
|
ValueArr []string `ValueArr,omitempty` // ["1","b","c"]
|
||||||
|
ValueMap map[string]string `ValueMap,omitempty` // {"a":"bb", "CC":"xx"}
|
||||||
|
ValueArrMap []map[string]string `ValueArrMap,omitempty` // [{"a":"B"}, {}, {}]
|
||||||
|
IsArr bool `IsArr` // 是否是数组
|
||||||
|
IsMap bool `IsMap` // 是否是Map
|
||||||
|
IsArrMap bool `IsArrMap` // 是否是数组Map
|
||||||
|
|
||||||
|
// StringConfigs map[string]string `StringConfigs` // key => value
|
||||||
|
// ArrayConfigs map[string][]string `ArrayConfigs` // key => []value
|
||||||
|
|
||||||
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
type EmailLog struct {
|
||||||
|
LogId bson.ObjectId `bson:"_id"`
|
||||||
|
|
||||||
|
Email string `Email` // 发送者
|
||||||
|
Subject string `Subject` // 主题
|
||||||
|
Body string `Body` // 内容
|
||||||
|
Msg string `Msg` // 发送失败信息
|
||||||
|
Ok bool `Ok` // 发送是否成功
|
||||||
|
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
FileId bson.ObjectId `bson:"_id,omitempty"` //
|
||||||
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
|
AlbumId bson.ObjectId `bson:"AlbumId"`
|
||||||
|
Name string `Name` // file name
|
||||||
|
Title string `Title` // file name or user defined for search
|
||||||
|
Size int64 `Size` // file size (byte)
|
||||||
|
Type string `Type` // file type, "" = image, "doc" = word
|
||||||
|
Path string `Path` // the file path
|
||||||
|
IsDefaultAlbum bool `IsDefaultAlbum`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|
||||||
|
FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
|
||||||
|
}
|
||||||
@@ -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`
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 笔记内部图片
|
||||||
|
type NoteImage struct {
|
||||||
|
NoteImageId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
NoteId bson.ObjectId `bson:"NoteId"` // 笔记
|
||||||
|
ImageId bson.ObjectId `bson:"ImageId"` // 图片fileId
|
||||||
|
}
|
||||||
+27
-12
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,18 +15,33 @@ type Note struct {
|
|||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
Desc string `Desc` // 描述, 非html
|
Desc string `Desc` // 描述, 非html
|
||||||
|
|
||||||
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
||||||
Tags []string `Tags,omitempty`
|
Tags []string `Tags,omitempty`
|
||||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
|
||||||
|
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||||
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
|
||||||
|
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||||
|
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||||
|
|
||||||
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
||||||
|
|
||||||
|
AttachNum int `AttachNum` // 2014/9/21, attachments num
|
||||||
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||||
|
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||||
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
|
|
||||||
|
SharePass int `SharePass` //分享笔记的密码
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
@@ -54,11 +69,11 @@ type NoteAndContent struct {
|
|||||||
// 每一个历史记录对象
|
// 每一个历史记录对象
|
||||||
type EachHistory struct {
|
type EachHistory struct {
|
||||||
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
Content string `Content`
|
Content string `Content`
|
||||||
}
|
}
|
||||||
type NoteContentHistory struct {
|
type NoteContentHistory struct {
|
||||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||||
Histories []EachHistory `Histories`
|
Histories []EachHistory `Histories`
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ type Notebook struct {
|
|||||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
||||||
Seq int `Seq` // 排序
|
Seq int `Seq` // 排序
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
|
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
||||||
NumberNotes int `NumberNotes` // 笔记数
|
NumberNotes int `NumberNotes` // 笔记数
|
||||||
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||||
@@ -21,7 +22,7 @@ type Notebook struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 仅仅是为了返回前台
|
// 仅仅是为了返回前台
|
||||||
type SubNotebooks []Notebooks
|
type SubNotebooks []*Notebooks // 存地址, 为了生成tree
|
||||||
type Notebooks struct {
|
type Notebooks struct {
|
||||||
Notebook
|
Notebook
|
||||||
Subs SubNotebooks // 子notebook 在数据库中是没有的
|
Subs SubNotebooks // 子notebook 在数据库中是没有的
|
||||||
@@ -32,7 +33,7 @@ func (this SubNotebooks) Len() int {
|
|||||||
return len(this)
|
return len(this)
|
||||||
}
|
}
|
||||||
func (this SubNotebooks) Less(i, j int) bool {
|
func (this SubNotebooks) Less(i, j int) bool {
|
||||||
return this[i].Seq < this[j].Seq
|
return (*this[i]).Seq < (*this[j]).Seq
|
||||||
}
|
}
|
||||||
func (this SubNotebooks) Swap(i, j int) {
|
func (this SubNotebooks) Swap(i, j int) {
|
||||||
this[i], this[j] = this[j], this[i]
|
this[i], this[j] = this[j], this[i]
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 举报
|
||||||
|
type Report struct {
|
||||||
|
ReportId bson.ObjectId `bson:"_id"`
|
||||||
|
NoteId bson.ObjectId `NoteId`
|
||||||
|
|
||||||
|
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
||||||
|
Reason string `Reason` // 评论内容
|
||||||
|
|
||||||
|
CommentId bson.ObjectId `CommendId,omitempty` // 对某条评论进行回复
|
||||||
|
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// http://docs.mongodb.org/manual/tutorial/expire-data/
|
||||||
|
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这个时间会自动清空
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,7 +76,9 @@ type SharingNotebookAndNotes struct {
|
|||||||
type ShareNotebook struct {
|
type ShareNotebook struct {
|
||||||
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||||
|
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||||
|
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||||
Seq int `bson:"Seq"` // 排序
|
Seq int `bson:"Seq"` // 排序
|
||||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||||
@@ -134,7 +136,9 @@ type ShareNotebooksByUser struct {
|
|||||||
type ShareNote struct {
|
type ShareNote struct {
|
||||||
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||||
|
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||||
|
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||||
NoteId bson.ObjectId `bson:"NoteId"`
|
NoteId bson.ObjectId `bson:"NoteId"`
|
||||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 建议
|
// 建议
|
||||||
|
|||||||
+24
-1
@@ -1,19 +1,42 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 这里主要是为了统计每个tag的note数目
|
// 这里主要是为了统计每个tag的note数目
|
||||||
|
// 暂时没用
|
||||||
|
/*
|
||||||
type TagNote struct {
|
type TagNote struct {
|
||||||
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
Tag string `Title` // 标题
|
Tag string `Title` // 标题
|
||||||
NoteNum int `NoteNum` // note数目
|
NoteNum int `NoteNum` // note数目
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// 每个用户一条记录, 存储用户的所有tags
|
// 每个用户一条记录, 存储用户的所有tags
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
UserId bson.ObjectId `bson:"_id"`
|
UserId bson.ObjectId `bson:"_id"`
|
||||||
Tags []string `Tags`
|
Tags []string `Tags`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -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`
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+46
-1
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,16 +20,61 @@ type User struct {
|
|||||||
Pwd string `bson:"Pwd" json:"-"`
|
Pwd string `bson:"Pwd" json:"-"`
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|
||||||
|
Logo string `Logo` // 9-24
|
||||||
// 主题
|
// 主题
|
||||||
Theme string `Theme`
|
Theme string `Theme`
|
||||||
|
|
||||||
// 用户配置
|
// 用户配置
|
||||||
NotebookWidth int `NotebookWidth` // 笔记本宽度
|
NotebookWidth int `NotebookWidth` // 笔记本宽度
|
||||||
NoteListWidth int `NoteListWidth` // 笔记列表宽度
|
NoteListWidth int `NoteListWidth` // 笔记列表宽度
|
||||||
|
MdEditorWidth int `MdEditorWidth` // markdown 左侧编辑器宽度
|
||||||
LeftIsMin bool `LeftIsMin` // 左侧是否是隐藏的, 默认是打开的
|
LeftIsMin bool `LeftIsMin` // 左侧是否是隐藏的, 默认是打开的
|
||||||
|
|
||||||
// 这里 第三方登录
|
// 这里 第三方登录
|
||||||
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
||||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||||
ThirdType int `ThirdType` // 第三方类型
|
ThirdType int `ThirdType` // 第三方类型
|
||||||
|
|
||||||
|
// 用户的帐户类型
|
||||||
|
|
||||||
|
ImageNum int `bson:"ImageNum" json:"-"` // 图片数量
|
||||||
|
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
|
||||||
|
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
|
||||||
|
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
|
||||||
|
FromUserId bson.ObjectId `FromUserId,omitempty` // 邀请的用户
|
||||||
|
|
||||||
|
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||||
|
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||||
|
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||||
|
// 阈值
|
||||||
|
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||||
|
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||||
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
}
|
||||||
|
|
||||||
|
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 // 各个页面
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -8,5 +9,15 @@ import (
|
|||||||
type Page struct {
|
type Page struct {
|
||||||
CurPage int // 当前页码
|
CurPage int // 当前页码
|
||||||
TotalPage int // 总页
|
TotalPage int // 总页
|
||||||
|
PerPageSize int
|
||||||
|
Count int // 总记录数
|
||||||
List interface{}
|
List interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewPage(page, perPageSize, count int, list interface{}) Page {
|
||||||
|
totalPage := 0
|
||||||
|
if count > 0 {
|
||||||
|
totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
|
||||||
|
}
|
||||||
|
return Page{page, totalPage, perPageSize, count, list}
|
||||||
|
}
|
||||||
+270
-12
@@ -3,26 +3,41 @@ package app
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/service"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"github.com/leanote/leanote/app/controllers"
|
||||||
|
"github.com/leanote/leanote/app/controllers/admin"
|
||||||
|
"github.com/leanote/leanote/app/controllers/member"
|
||||||
_ "github.com/leanote/leanote/app/lea/binder"
|
_ "github.com/leanote/leanote/app/lea/binder"
|
||||||
|
"github.com/leanote/leanote/app/lea/session"
|
||||||
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
|
"github.com/leanote/leanote/app/lea/route"
|
||||||
"reflect"
|
"reflect"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"math"
|
"math"
|
||||||
|
"strings"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Filters is the default set of global filters.
|
// Filters is the default set of global filters.
|
||||||
revel.Filters = []revel.Filter{
|
revel.Filters = []revel.Filter{
|
||||||
revel.PanicFilter, // Recover from panics and display an error page instead.
|
revel.PanicFilter, // Recover from panics and display an error page instead.
|
||||||
revel.RouterFilter, // Use the routing table to select the right Action
|
route.RouterFilter,
|
||||||
|
// revel.RouterFilter, // Use the routing table to select the right Action
|
||||||
// AuthFilter, // Invoke the action.
|
// AuthFilter, // Invoke the action.
|
||||||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
||||||
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
||||||
revel.SessionFilter, // Restore and write the session cookie.
|
// revel.SessionFilter, // Restore and write the session cookie.
|
||||||
|
|
||||||
// session.SessionFilter, // leanote memcache session life
|
// 使用SessionFilter标准版从cookie中得到sessionID, 然后通过MssessionFilter从Memcache中得到
|
||||||
|
// session, 之后MSessionFilter将session只存sessionID然后返回给SessionFilter返回到web
|
||||||
|
session.SessionFilter, // leanote session
|
||||||
|
// session.MSessionFilter, // leanote memcache session
|
||||||
|
|
||||||
revel.FlashFilter, // Restore and write the flash cookie.
|
revel.FlashFilter, // Restore and write the flash cookie.
|
||||||
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
|
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
|
||||||
@@ -35,16 +50,58 @@ func init() {
|
|||||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||||
return template.HTML(str)
|
return template.HTML(str)
|
||||||
}
|
}
|
||||||
revel.TemplateFuncs["add"] = func(i int) template.HTML {
|
revel.TemplateFuncs["add"] = func(i int) string {
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
return template.HTML(fmt.Sprintf("%v", i))
|
return fmt.Sprintf("%v", i)
|
||||||
|
}
|
||||||
|
revel.TemplateFuncs["sub"] = func(i int) int {
|
||||||
|
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("")
|
||||||
|
}
|
||||||
|
return template.HTML(strings.Join(arr, ","))
|
||||||
}
|
}
|
||||||
revel.TemplateFuncs["concat"] = func(s1, s2 string) template.HTML {
|
revel.TemplateFuncs["concat"] = func(s1, s2 string) template.HTML {
|
||||||
return template.HTML(s1 + s2)
|
return template.HTML(s1 + s2)
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["concatStr"] = func(strs ...string) string {
|
||||||
|
str := ""
|
||||||
|
for _, s := range strs {
|
||||||
|
str += s
|
||||||
|
}
|
||||||
|
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 {
|
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML {
|
||||||
|
return template.HTML(t.Format(format))
|
||||||
|
}
|
||||||
|
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
||||||
|
sec, _ := strconv.Atoi(unixSec)
|
||||||
|
t := time.Unix(int64(sec), 0)
|
||||||
|
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||||
|
}
|
||||||
|
|
||||||
// interface是否有该字段
|
// interface是否有该字段
|
||||||
revel.TemplateFuncs["has"] = func(i interface{}, key string) bool {
|
revel.TemplateFuncs["has"] = func(i interface{}, key string) bool {
|
||||||
@@ -54,6 +111,77 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
|
// 2014/12/30 标签添加链接
|
||||||
|
revel.TemplateFuncs["blogTags"] = func(renderArgs map[string]interface{}, tags []string) template.HTML {
|
||||||
|
if tags == nil || len(tags) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
|
||||||
if tags == nil || len(tags) == 0 {
|
if tags == nil || len(tags) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@@ -74,9 +202,86 @@ func init() {
|
|||||||
}
|
}
|
||||||
return template.HTML(tagStr)
|
return template.HTML(tagStr)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
revel.TemplateFuncs["li"] = func(a string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// str连接
|
||||||
|
revel.TemplateFuncs["urlConcat"] = func(url string, v... interface{}) string {
|
||||||
|
html := ""
|
||||||
|
for i := 0; i < len(v); i = i + 2 {
|
||||||
|
item := v[i]
|
||||||
|
if i+1 == len(v) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value := v[i+1]
|
||||||
|
if item != nil && value != nil {
|
||||||
|
keyStr, _ := item.(string)
|
||||||
|
valueStr, err := value.(string)
|
||||||
|
if !err {
|
||||||
|
valueInt, _ := value.(int)
|
||||||
|
valueStr = strconv.Itoa(valueInt)
|
||||||
|
}
|
||||||
|
if keyStr != "" && valueStr != "" {
|
||||||
|
s := keyStr + "=" + valueStr
|
||||||
|
if html != "" {
|
||||||
|
html += "&" + s
|
||||||
|
} else {
|
||||||
|
html += s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if html != "" {
|
||||||
|
if strings.Index(url, "?") >= 0 {
|
||||||
|
return url + "&" + html
|
||||||
|
} else {
|
||||||
|
return url + "?" + html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
revel.TemplateFuncs["urlCond"] = func(url string, sorterI, keyords interface{}) template.HTML {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/14226416/go-lang-templates-always-quotes-a-string-and-removes-comments
|
||||||
|
revel.TemplateFuncs["rawMsg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.JS {
|
||||||
|
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return template.JS(revel.Message(str, message, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为后台管理sorter th使用
|
||||||
|
// 必须要返回HTMLAttr, 返回html, golang 会执行安全检查返回ZgotmplZ
|
||||||
|
// sorterI 可能是nil, 所以用interfalce{}来接收
|
||||||
|
/*
|
||||||
|
data-url="/adminUser/index"
|
||||||
|
data-sorter="email"
|
||||||
|
class="th-sortable {{if eq .sorter "email-up"}}th-sort-up{{else}}{{if eq .sorter "email-down"}}th-sort-down{{end}}{{end}}"
|
||||||
|
*/
|
||||||
|
revel.TemplateFuncs["sorterTh"] = func(url, sorterField string, sorterI interface{}) template.HTMLAttr {
|
||||||
|
sorter := ""
|
||||||
|
if sorterI != nil {
|
||||||
|
sorter, _ = sorterI.(string)
|
||||||
|
}
|
||||||
|
html := "data-url=\"" + url + "\" data-sorter=\"" + sorterField + "\"";
|
||||||
|
html += " class=\"th-sortable ";
|
||||||
|
if sorter == sorterField + "-up" {
|
||||||
|
html += "th-sort-up\"";
|
||||||
|
} else if(sorter == sorterField + "-down") {
|
||||||
|
html += "th-sort-down";
|
||||||
|
}
|
||||||
|
html += "\"";
|
||||||
|
return template.HTMLAttr(html)
|
||||||
|
}
|
||||||
|
|
||||||
// pagination
|
// pagination
|
||||||
revel.TemplateFuncs["page"] = func(userId, notebookId string, page, pageSize, count int) template.HTML {
|
revel.TemplateFuncs["page"] = func(urlBase string, page, pageSize, count int) template.HTML {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -91,11 +296,6 @@ func init() {
|
|||||||
nextPage := page + 1
|
nextPage := page + 1
|
||||||
var preUrl, nextUrl string
|
var preUrl, nextUrl string
|
||||||
|
|
||||||
urlBase := "/blog/" + userId
|
|
||||||
if notebookId != "" {
|
|
||||||
urlBase += "/" + notebookId
|
|
||||||
}
|
|
||||||
|
|
||||||
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
|
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
|
||||||
nextUrl = urlBase + "?page=" + strconv.Itoa(nextPage)
|
nextUrl = urlBase + "?page=" + strconv.Itoa(nextPage)
|
||||||
|
|
||||||
@@ -111,9 +311,67 @@ func init() {
|
|||||||
}
|
}
|
||||||
return template.HTML("<li class='" + preClass + "'><a href='" + preUrl + "'>Previous</a></li> <li class='" + nextClass + "'><a href='" + nextUrl + "'>Next</a></li>")
|
return template.HTML("<li class='" + preClass + "'><a href='" + preUrl + "'>Previous</a></li> <li class='" + nextClass + "'><a href='" + nextUrl + "'>Next</a></li>")
|
||||||
}
|
}
|
||||||
|
// life
|
||||||
|
// 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:
|
||||||
|
switch a2.(type) {
|
||||||
|
case string:
|
||||||
|
return reflect.ValueOf(a1).String() > reflect.ValueOf(a2).String()
|
||||||
|
}
|
||||||
|
case int, int8, int16, int32, int64:
|
||||||
|
switch a2.(type) {
|
||||||
|
case int, int8, int16, int32, int64:
|
||||||
|
return reflect.ValueOf(a1).Int() > reflect.ValueOf(a2).Int()
|
||||||
|
}
|
||||||
|
case uint, uint8, uint16, uint32, uint64:
|
||||||
|
switch a2.(type) {
|
||||||
|
case uint, uint8, uint16, uint32, uint64:
|
||||||
|
return reflect.ValueOf(a1).Uint() > reflect.ValueOf(a2).Uint()
|
||||||
|
}
|
||||||
|
case float32, float64:
|
||||||
|
switch a2.(type) {
|
||||||
|
case float32, float64:
|
||||||
|
return reflect.ValueOf(a1).Float() > reflect.ValueOf(a2).Float()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
{{range $i := N 1 10}}
|
||||||
|
<div>{{$i}}</div>
|
||||||
|
{{end}}
|
||||||
|
*/
|
||||||
|
revel.TemplateFuncs["N"] = func(start, end int) (stream chan int) {
|
||||||
|
stream = make(chan int)
|
||||||
|
go func() {
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
stream <- i
|
||||||
|
}
|
||||||
|
close(stream)
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// init Email
|
// init Email
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
|
// 数据库
|
||||||
|
db.Init("", "")
|
||||||
|
// email配置
|
||||||
InitEmail()
|
InitEmail()
|
||||||
})
|
InitVd()
|
||||||
|
memcache.InitMemcache() // session服务
|
||||||
|
// 其它service
|
||||||
|
service.InitService()
|
||||||
|
controllers.InitService()
|
||||||
|
admin.InitService()
|
||||||
|
member.InitService()
|
||||||
|
service.ConfigS.InitGlobalConfigs()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package lea
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Log(i interface{}) {
|
func Log(i interface{}) {
|
||||||
@@ -13,3 +14,13 @@ func LogJ(i interface{}) {
|
|||||||
b, _ := json.MarshalIndent(i, "", " ")
|
b, _ := json.MarshalIndent(i, "", " ")
|
||||||
revel.INFO.Println(string(b))
|
revel.INFO.Println(string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 为test用
|
||||||
|
func L(i interface{}) {
|
||||||
|
fmt.Println(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LJ(i interface{}) {
|
||||||
|
b, _ := json.MarshalIndent(i, "", " ")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
}
|
||||||
+6
-7
@@ -22,7 +22,7 @@ func InitEmail() {
|
|||||||
var bodyTpl = `
|
var bodyTpl = `
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<div style="width: 800px; margin:auto; border-radius:5px; border: 1px solid #ccc; padding: 20px;">
|
<div style="width: 600px; margin:auto; border-radius:5px; border: 1px solid #ccc; padding: 20px;">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div style="float:left; height: 40px;">
|
<div style="float:left; height: 40px;">
|
||||||
@@ -56,7 +56,7 @@ var bodyTpl = `
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
func SendEmail(to, subject, title, body string) bool {
|
func SendEmailOld(to, subject, body string) bool {
|
||||||
hp := strings.Split(host, ":")
|
hp := strings.Split(host, ":")
|
||||||
auth := smtp.PlainAuth("", username, password, hp[0])
|
auth := smtp.PlainAuth("", username, password, hp[0])
|
||||||
|
|
||||||
@@ -69,9 +69,8 @@ func SendEmail(to, subject, title, body string) bool {
|
|||||||
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录之
|
//body = strings.Replace(bodyTpl, "$body", body, 1)
|
||||||
body = strings.Replace(bodyTpl, "$body", body, 1)
|
//body = strings.Replace(body, "$title", title, 1)
|
||||||
body = strings.Replace(body, "$title", title, 1)
|
|
||||||
|
|
||||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||||
send_to := strings.Split(to, ";")
|
send_to := strings.Split(to, ";")
|
||||||
@@ -84,7 +83,7 @@ func SendEmail(to, subject, title, body string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendToLeanote(subject, title, body string) {
|
func SendToLeanoteOld(subject, title, body string) {
|
||||||
to := "leanote@leanote.com"
|
to := "leanote@leanote.com"
|
||||||
SendEmail(to, subject, title, body);
|
SendEmailOld(to, subject, body);
|
||||||
}
|
}
|
||||||
+142
-5
@@ -1,9 +1,11 @@
|
|||||||
package lea
|
package lea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"io"
|
||||||
"path/filepath"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 分离文件名与扩展名(包含.)
|
// 分离文件名与扩展名(包含.)
|
||||||
@@ -13,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) {
|
|||||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||||
baseName = strings.TrimRight(filename, ext)
|
baseName = strings.TrimRight(filename, ext)
|
||||||
ext = strings.ToLower(ext)
|
ext = strings.ToLower(ext)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换文件的格式
|
// 转换文件的格式
|
||||||
// toExt包含.
|
// toExt包含.
|
||||||
func TransferExt(path string, toExt string) string {
|
func TransferExt(path string, toExt string) string {
|
||||||
dir := filepath.Dir(path) + "/" // 文件路径
|
dir := filepath.Dir(path) + "/" // 文件路径
|
||||||
name := filepath.Base(path) // 文件名 a.jpg
|
name := filepath.Base(path) // 文件名 a.jpg
|
||||||
// 获取文件名与路径
|
// 获取文件名与路径
|
||||||
baseName, _ := SplitFilename(name)
|
baseName, _ := SplitFilename(name)
|
||||||
return dir + baseName + toExt
|
return dir + baseName + toExt
|
||||||
@@ -30,6 +32,16 @@ func GetFilename(path string) string {
|
|||||||
return filepath.Base(path)
|
return filepath.Base(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// file size
|
||||||
|
// length in bytes
|
||||||
|
func GetFilesize(path string) int64 {
|
||||||
|
fileinfo, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return fileinfo.Size()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// 清空dir下所有的文件和文件夹
|
// 清空dir下所有的文件和文件夹
|
||||||
// RemoveAll会清空本文件夹, 所以还要创建之
|
// RemoveAll会清空本文件夹, 所以还要创建之
|
||||||
func ClearDir(dir string) bool {
|
func ClearDir(dir string) bool {
|
||||||
@@ -43,3 +55,128 @@ func ClearDir(dir string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// list dir's all file, return filenames
|
||||||
|
func ListDir(dir string) []string {
|
||||||
|
f, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
names, _ := f.Readdirnames(0)
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyFile(srcName, dstName 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得文件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
|
||||||
|
}
|
||||||
+13
-1
@@ -8,7 +8,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io"
|
"io"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
math_rand "math/rand"
|
math_rand "math/rand"
|
||||||
)
|
)
|
||||||
@@ -267,3 +267,15 @@ func RandomPwd(num int) string {
|
|||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InArray(arr []string, str string) bool {
|
||||||
|
if arr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
+170
@@ -0,0 +1,170 @@
|
|||||||
|
package lea
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 验证
|
||||||
|
|
||||||
|
var rulesStr = `{
|
||||||
|
"username": [
|
||||||
|
{"rule": "required", "msg": "inputUsername"},
|
||||||
|
{"rule": "noSpecialChars", "msg": "noSpecialChars"},
|
||||||
|
{"rule": "minLength", "data": "4", "msg": "minLength", "msgData": "4"}
|
||||||
|
],
|
||||||
|
"email": [
|
||||||
|
{"rule": "required", "msg": "inputEmail"},
|
||||||
|
{"rule": "email", "msg": "errorEmail"}
|
||||||
|
],
|
||||||
|
"password": [
|
||||||
|
{"rule": "required", "msg": "inputPassword"},
|
||||||
|
{"rule": "password", "msg": "errorPassword"}
|
||||||
|
],
|
||||||
|
"subDomain": [
|
||||||
|
{"rule": "subDomain", "msg": "errorSubDomain"}
|
||||||
|
],
|
||||||
|
"domain": [
|
||||||
|
{"rule": "domain", "msg": "errorDomain"}
|
||||||
|
],
|
||||||
|
"perPageSize": [
|
||||||
|
{"rule": "min", "data": "1", "msg": "errorPerPageSize"}
|
||||||
|
],
|
||||||
|
"sortField": [
|
||||||
|
{"rule": "sortField", "msg": "errorSortField"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
var rulesMap map[string][]map[string]string
|
||||||
|
|
||||||
|
var rules = map[string]func(string, map[string]string)(bool, string) {
|
||||||
|
"required": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
},
|
||||||
|
"minLength": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := rule["data"]
|
||||||
|
dataI, _ := strconv.Atoi(data)
|
||||||
|
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 == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = len(value) >= 6
|
||||||
|
return
|
||||||
|
},
|
||||||
|
"email": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = IsEmail(value)
|
||||||
|
return
|
||||||
|
},
|
||||||
|
"noSpecialChars": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = IsUsername(value)
|
||||||
|
return
|
||||||
|
},
|
||||||
|
// www.baidu.com
|
||||||
|
//
|
||||||
|
"domain": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
ok = true
|
||||||
|
return // 可为空
|
||||||
|
}
|
||||||
|
ok2, _ := regexp.MatchString(`[^0-9a-zA-Z_\.\-]`, value)
|
||||||
|
ok = !ok2
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
},
|
||||||
|
// abcd
|
||||||
|
"subDomain": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
ok = true
|
||||||
|
return // 可为空
|
||||||
|
}
|
||||||
|
if len(value) < 4 {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok2, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, value)
|
||||||
|
ok = !ok2
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitVd() {
|
||||||
|
json.Unmarshal([]byte(rulesStr), &rulesMap)
|
||||||
|
LogJ(rulesMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证
|
||||||
|
// Vd("username", "life")
|
||||||
|
|
||||||
|
func Vd(name, value string) (ok bool, msg string) {
|
||||||
|
rs, _ := rulesMap[name]
|
||||||
|
|
||||||
|
for _, rule := range rs {
|
||||||
|
ruleFunc, _ := rules[rule["rule"]]
|
||||||
|
if ok2, msg2 := ruleFunc(value, rule); !ok2 {
|
||||||
|
ok = false
|
||||||
|
if msg2 != "" {
|
||||||
|
msg = msg2
|
||||||
|
} else {
|
||||||
|
msg = rule["msg"]
|
||||||
|
}
|
||||||
|
msgData := rule["msgData"]
|
||||||
|
if msgData != "" {
|
||||||
|
msg += "-" + msgData
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Vds(m map[string]string) (ok bool, msg string) {
|
||||||
|
for name, value := range m {
|
||||||
|
ok, msg = Vd(name, value)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
crand "crypto/rand"
|
||||||
|
"time"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
const (
|
||||||
|
stdWidth = 100
|
||||||
|
stdHeight = 40
|
||||||
|
maxSkew = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fontWidth = 5
|
||||||
|
fontHeight = 8
|
||||||
|
blackChar = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var font = [][]byte{
|
||||||
|
{ // 0
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 1
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 1, 1, 0, 0,
|
||||||
|
1, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
},
|
||||||
|
{ // 2
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 1, 1,
|
||||||
|
0, 1, 1, 0, 0,
|
||||||
|
1, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
},
|
||||||
|
{ // 3
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 4
|
||||||
|
1, 0, 0, 1, 0,
|
||||||
|
1, 0, 0, 1, 0,
|
||||||
|
1, 0, 0, 1, 0,
|
||||||
|
1, 0, 0, 1, 0,
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 5
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
1, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 6
|
||||||
|
0, 0, 1, 1, 1,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 7
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
},
|
||||||
|
{ // 8
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
{ // 9
|
||||||
|
0, 1, 1, 1, 0,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 1, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
*image.NRGBA
|
||||||
|
color *color.NRGBA
|
||||||
|
width int //a digit width
|
||||||
|
height int //a digit height
|
||||||
|
dotsize int
|
||||||
|
}
|
||||||
|
func init(){
|
||||||
|
rand.Seed(int64(time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewImage(digits []byte, width, height int) *Image {
|
||||||
|
img := new(Image)
|
||||||
|
r := image.Rect(img.width, img.height, stdWidth, stdHeight)
|
||||||
|
img.NRGBA = image.NewNRGBA(r)
|
||||||
|
|
||||||
|
img.color = &color.NRGBA{
|
||||||
|
uint8(rand.Intn(129)),
|
||||||
|
uint8(rand.Intn(129)),
|
||||||
|
uint8(rand.Intn(129)),
|
||||||
|
0xFF,
|
||||||
|
}
|
||||||
|
// Draw background (10 random circles of random brightness)
|
||||||
|
img.calculateSizes(width, height, len(digits))
|
||||||
|
img.fillWithCircles(10, img.dotsize)
|
||||||
|
|
||||||
|
maxx := width - (img.width+img.dotsize)*len(digits) - img.dotsize
|
||||||
|
maxy := height - img.height - img.dotsize*2
|
||||||
|
|
||||||
|
x := rnd(img.dotsize*2, maxx)
|
||||||
|
y := rnd(img.dotsize*2, maxy)
|
||||||
|
|
||||||
|
// Draw digits.
|
||||||
|
for _, n := range digits {
|
||||||
|
img.drawDigit(font[n], x, y)
|
||||||
|
x += img.width + img.dotsize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw strike-through line.
|
||||||
|
// 中间线不要
|
||||||
|
//img.strikeThrough()
|
||||||
|
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
return 0, png.Encode(w, img)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) calculateSizes(width, height, ncount int) {
|
||||||
|
|
||||||
|
// Goal: fit all digits inside the image.
|
||||||
|
var border int
|
||||||
|
if width > height {
|
||||||
|
border = height / 5
|
||||||
|
} else {
|
||||||
|
border = width / 5
|
||||||
|
}
|
||||||
|
// Convert everything to floats for calculations.
|
||||||
|
w := float64(width - border*2) //268
|
||||||
|
h := float64(height - border*2) //48
|
||||||
|
// fw takes into account 1-dot spacing between digits.
|
||||||
|
|
||||||
|
fw := float64(fontWidth) + 1 //6
|
||||||
|
|
||||||
|
fh := float64(fontHeight) //8
|
||||||
|
nc := float64(ncount) //7
|
||||||
|
|
||||||
|
// Calculate the width of a single digit taking into account only the
|
||||||
|
// width of the image.
|
||||||
|
nw := w / nc //38
|
||||||
|
// Calculate the height of a digit from this width.
|
||||||
|
nh := nw * fh / fw //51
|
||||||
|
|
||||||
|
// Digit too high?
|
||||||
|
|
||||||
|
if nh > h {
|
||||||
|
// Fit digits based on height.
|
||||||
|
nh = h //nh = 44
|
||||||
|
nw = fw / fh * nh
|
||||||
|
}
|
||||||
|
// Calculate dot size.
|
||||||
|
img.dotsize = int(nh / fh)
|
||||||
|
// Save everything, making the actual width smaller by 1 dot to account
|
||||||
|
// for spacing between digits.
|
||||||
|
img.width = int(nw)
|
||||||
|
img.height = int(nh) - img.dotsize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) fillWithCircles(n, maxradius int) {
|
||||||
|
color := img.color
|
||||||
|
maxx := img.Bounds().Max.X
|
||||||
|
maxy := img.Bounds().Max.Y
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
setRandomBrightness(color, 255)
|
||||||
|
r := rnd(1, maxradius)
|
||||||
|
img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
|
||||||
|
for x := fromX; x <= toX; x++ {
|
||||||
|
img.Set(x, y, color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) drawCircle(color color.Color, x, y, radius int) {
|
||||||
|
f := 1 - radius
|
||||||
|
dfx := 1
|
||||||
|
dfy := -2 * radius
|
||||||
|
xx := 0
|
||||||
|
yy := radius
|
||||||
|
|
||||||
|
img.Set(x, y+radius, color)
|
||||||
|
img.Set(x, y-radius, color)
|
||||||
|
img.drawHorizLine(color, x-radius, x+radius, y)
|
||||||
|
|
||||||
|
for xx < yy {
|
||||||
|
if f >= 0 {
|
||||||
|
yy--
|
||||||
|
dfy += 2
|
||||||
|
f += dfy
|
||||||
|
}
|
||||||
|
xx++
|
||||||
|
dfx += 2
|
||||||
|
f += dfx
|
||||||
|
img.drawHorizLine(color, x-xx, x+xx, y+yy)
|
||||||
|
img.drawHorizLine(color, x-xx, x+xx, y-yy)
|
||||||
|
img.drawHorizLine(color, x-yy, x+yy, y+xx)
|
||||||
|
img.drawHorizLine(color, x-yy, x+yy, y-xx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) strikeThrough() {
|
||||||
|
r := 0
|
||||||
|
maxx := img.Bounds().Max.X
|
||||||
|
maxy := img.Bounds().Max.Y
|
||||||
|
y := rnd(maxy/3, maxy-maxy/3)
|
||||||
|
for x := 0; x < maxx; x += r {
|
||||||
|
r = rnd(1, img.dotsize/3)
|
||||||
|
y += rnd(-img.dotsize/2, img.dotsize/2)
|
||||||
|
if y <= 0 || y >= maxy {
|
||||||
|
y = rnd(maxy/3, maxy-maxy/3)
|
||||||
|
}
|
||||||
|
img.drawCircle(img.color, x, y, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (img *Image) drawDigit(digit []byte, x, y int) {
|
||||||
|
skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
|
||||||
|
xs := float64(x)
|
||||||
|
minr := img.dotsize / 2 // minumum radius
|
||||||
|
maxr := img.dotsize/2 + img.dotsize/4 // maximum radius
|
||||||
|
y += rnd(-minr, minr)
|
||||||
|
for yy := 0; yy < fontHeight; yy++ {
|
||||||
|
for xx := 0; xx < fontWidth; xx++ {
|
||||||
|
if digit[yy*fontWidth+xx] != blackChar {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Introduce random variations.
|
||||||
|
or := rnd(minr, maxr)
|
||||||
|
ox := x + (xx * img.dotsize) + rnd(0, or/2)
|
||||||
|
oy := y + (yy * img.dotsize) + rnd(0, or/2)
|
||||||
|
|
||||||
|
img.drawCircle(img.color, ox, oy, or)
|
||||||
|
}
|
||||||
|
xs += skf
|
||||||
|
x = int(xs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setRandomBrightness(c *color.NRGBA, max uint8) {
|
||||||
|
minc := min3(c.R, c.G, c.B)
|
||||||
|
maxc := max3(c.R, c.G, c.B)
|
||||||
|
if maxc > max {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n := rand.Intn(int(max-maxc)) - int(minc)
|
||||||
|
c.R = uint8(int(c.R) + n)
|
||||||
|
c.G = uint8(int(c.G) + n)
|
||||||
|
c.B = uint8(int(c.B) + n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func min3(x, y, z uint8) (o uint8) {
|
||||||
|
o = x
|
||||||
|
if y < o {
|
||||||
|
o = y
|
||||||
|
}
|
||||||
|
if z < o {
|
||||||
|
o = z
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func max3(x, y, z uint8) (o uint8) {
|
||||||
|
o = x
|
||||||
|
if y > o {
|
||||||
|
o = y
|
||||||
|
}
|
||||||
|
if z > o {
|
||||||
|
o = z
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// rnd returns a random number in range [from, to].
|
||||||
|
func rnd(from, to int) int {
|
||||||
|
//println(to+1-from)
|
||||||
|
return rand.Intn(to+1-from) + from
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Standard length of uniuri string to achive ~95 bits of entropy.
|
||||||
|
StdLen = 16
|
||||||
|
// Length of uniurl string to achive ~119 bits of entropy, closest
|
||||||
|
// to what can be losslessly converted to UUIDv4 (122 bits).
|
||||||
|
UUIDLen = 20
|
||||||
|
)
|
||||||
|
|
||||||
|
// Standard characters allowed in uniuri string.
|
||||||
|
var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
|
||||||
|
|
||||||
|
// New returns a new random string of the standard length, consisting of
|
||||||
|
// standard characters.
|
||||||
|
func New() string {
|
||||||
|
return NewLenChars(StdLen, StdChars)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLen returns a new random string of the provided length, consisting of
|
||||||
|
// standard characters.
|
||||||
|
func NewLen(length int) string {
|
||||||
|
return NewLenChars(length, StdChars)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLenChars returns a new random string of the provided length, consisting
|
||||||
|
// of the provided byte slice of allowed characters (maximum 256).
|
||||||
|
func NewLenChars(length int, chars []byte) string {
|
||||||
|
b := make([]byte, length)
|
||||||
|
r := make([]byte, length+(length/4)) // storage for random bytes.
|
||||||
|
clen := byte(len(chars))
|
||||||
|
maxrb := byte(256 - (256 % len(chars)))
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
if _, err := io.ReadFull(crand.Reader, r); err != nil {
|
||||||
|
panic("error reading from random source: " + err.Error())
|
||||||
|
}
|
||||||
|
for _, c := range r {
|
||||||
|
if c >= maxrb {
|
||||||
|
// Skip this number to avoid modulo bias.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b[i] = chars[c%clen]
|
||||||
|
i++
|
||||||
|
if i == length {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fetch() (*Image, string) {
|
||||||
|
d := make([]byte, 4)
|
||||||
|
s := NewLen(4)
|
||||||
|
ss := ""
|
||||||
|
d = []byte(s)
|
||||||
|
for v := range d {
|
||||||
|
d[v] %= 10
|
||||||
|
ss += strconv.FormatInt(int64(d[v]), 32)
|
||||||
|
}
|
||||||
|
return NewImage(d, 100, 40), ss
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package html2image
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Html2Image(userInfo info.User, note info.Note, content, toPath string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,9 +3,20 @@ package memcache
|
|||||||
import (
|
import (
|
||||||
"github.com/robfig/gomemcache/memcache"
|
"github.com/robfig/gomemcache/memcache"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Set(key string, value map[string]string, expiration int32) {
|
var client *memcache.Client
|
||||||
|
|
||||||
|
// onAppStart后调用
|
||||||
|
func InitMemcache() {
|
||||||
|
client = memcache.New("localhost:11211")
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// map
|
||||||
|
|
||||||
|
func SetMap(key string, value map[string]string, expiration int32) {
|
||||||
// 把value转成byte
|
// 把value转成byte
|
||||||
bytes, _ := json.Marshal(value)
|
bytes, _ := json.Marshal(value)
|
||||||
if expiration == -1 {
|
if expiration == -1 {
|
||||||
@@ -14,7 +25,7 @@ func Set(key string, value map[string]string, expiration int32) {
|
|||||||
client.Set(&memcache.Item{Key: key, Value: bytes, Expiration: expiration})
|
client.Set(&memcache.Item{Key: key, Value: bytes, Expiration: expiration})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(key string) map[string]string {
|
func GetMap(key string) map[string]string {
|
||||||
item, err := client.Get(key)
|
item, err := client.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -24,3 +35,32 @@ func Get(key string) map[string]string {
|
|||||||
json.Unmarshal(item.Value, &m)
|
json.Unmarshal(item.Value, &m)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// string
|
||||||
|
func GetString(key string) string {
|
||||||
|
item, err := client.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(item.Value)
|
||||||
|
}
|
||||||
|
func SetString(key string, value string, expiration int32) {
|
||||||
|
if expiration == -1 {
|
||||||
|
expiration = 30 * 24 * 60 * 60 // 30天
|
||||||
|
}
|
||||||
|
client.Set(&memcache.Item{Key: key, Value: []byte(value), Expiration: expiration})
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
// int, 是通过转成string来存的
|
||||||
|
|
||||||
|
func GetInt(key string) int {
|
||||||
|
str := GetString(key)
|
||||||
|
i, _ := strconv.Atoi(str)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
func SetInt(key string, value int, expiration int32) {
|
||||||
|
str := strconv.Itoa(value)
|
||||||
|
SetString(key, str, expiration)
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package memcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/robfig/gomemcache/memcache"
|
|
||||||
)
|
|
||||||
|
|
||||||
var client *memcache.Client
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// client = memcache.New("localhost:11211")
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
// "path/filepath"
|
// "path/filepath"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
@@ -13,7 +14,7 @@ import (
|
|||||||
// toPath 文件保存的目录
|
// toPath 文件保存的目录
|
||||||
// 默认是/tmp
|
// 默认是/tmp
|
||||||
// 返回文件的完整目录
|
// 返回文件的完整目录
|
||||||
func WriteUrl(url string, toPath string) (path string, ok bool) {
|
func WriteUrl(url string, toPath string) (length int64, newFilename, path string, ok bool) {
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -22,6 +23,8 @@ func WriteUrl(url string, toPath string) (path string, ok bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
length = int64(len(content))
|
||||||
|
|
||||||
// a.html?a=a11&xxx
|
// a.html?a=a11&xxx
|
||||||
url = trimQueryParams(url)
|
url = trimQueryParams(url)
|
||||||
_, ext := SplitFilename(url)
|
_, ext := SplitFilename(url)
|
||||||
@@ -29,13 +32,8 @@ func WriteUrl(url string, toPath string) (path string, ok bool) {
|
|||||||
toPath = "/tmp"
|
toPath = "/tmp"
|
||||||
}
|
}
|
||||||
// dir := filepath.Dir(toPath)
|
// dir := filepath.Dir(toPath)
|
||||||
newFilename := NewGuid() + ext
|
newFilename = NewGuid() + ext
|
||||||
fullPath := toPath + "/" + newFilename
|
fullPath := toPath + "/" + newFilename
|
||||||
/*
|
|
||||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 写到文件中
|
// 写到文件中
|
||||||
file, err := os.Create(fullPath)
|
file, err := os.Create(fullPath)
|
||||||
@@ -54,6 +52,7 @@ func WriteUrl(url string, toPath string) (path string, ok bool) {
|
|||||||
func GetContent(url string) (content []byte, err error) {
|
func GetContent(url string) (content []byte, err error) {
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
resp, err = http.Get(url)
|
resp, err = http.Get(url)
|
||||||
|
Log(err)
|
||||||
if(resp != nil && resp.Body != nil) {
|
if(resp != nil && resp.Body != nil) {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
} else {
|
} else {
|
||||||
@@ -65,6 +64,7 @@ func GetContent(url string) (content []byte, err error) {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
buf, err = ioutil.ReadAll(resp.Body)
|
buf, err = ioutil.ReadAll(resp.Body)
|
||||||
if(err != nil) {
|
if(err != nil) {
|
||||||
|
Log(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,3 +91,12 @@ func trimQueryParams(url string) string {
|
|||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通过domain得到ip
|
||||||
|
func GetIpFromDomain(domain string) string {
|
||||||
|
ip, _ := net.LookupIP(domain)
|
||||||
|
if ip != nil && len(ip) > 0 {
|
||||||
|
return ip[0].String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "github.com/leanote/leanote/app/service"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// overwite revel RouterFilter
|
||||||
|
// /api/user/Info => ApiUser.Info()
|
||||||
|
var staticPrefix = []string{"/public", "/favicon.ico", "/css", "/js", "/images", "/tinymce", "/upload", "/fonts"}
|
||||||
|
func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
// 补全controller部分
|
||||||
|
path := c.Request.Request.URL.Path
|
||||||
|
|
||||||
|
// Figure out the Controller/Action
|
||||||
|
var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)
|
||||||
|
if route == nil {
|
||||||
|
c.Result = c.NotFound("No matching route found: " + c.Request.RequestURI)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The route may want to explicitly return a 404.
|
||||||
|
if route.Action == "404" {
|
||||||
|
c.Result = c.NotFound("(intentionally)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// life start
|
||||||
|
/*
|
||||||
|
type URL struct {
|
||||||
|
Scheme string
|
||||||
|
Opaque string // encoded opaque data
|
||||||
|
User *Userinfo // username and password information
|
||||||
|
Host string // host or host:port
|
||||||
|
Path string
|
||||||
|
RawQuery string // encoded query values, without '?'
|
||||||
|
Fragment string // fragment for references, without '#'
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if route.ControllerName != "Static" {
|
||||||
|
// api设置
|
||||||
|
// leanote.com/api/user/get => ApiUser::Get
|
||||||
|
//* /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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the action.
|
||||||
|
if err := c.SetAction(route.ControllerName, route.MethodName); err != nil {
|
||||||
|
c.Result = c.NotFound(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the route and fixed params to the Request Params.
|
||||||
|
c.Params.Route = route.Params
|
||||||
|
|
||||||
|
// Add the fixed parameters mapped by name.
|
||||||
|
// TODO: Pre-calculate this mapping.
|
||||||
|
for i, value := range route.FixedParams {
|
||||||
|
if c.Params.Fixed == nil {
|
||||||
|
c.Params.Fixed = make(url.Values)
|
||||||
|
}
|
||||||
|
if i < len(c.MethodType.Args) {
|
||||||
|
arg := c.MethodType.Args[i]
|
||||||
|
c.Params.Fixed.Set(arg.Name, value)
|
||||||
|
} else {
|
||||||
|
revel.WARN.Println("Too many parameters to", route.Action, "trying to add", value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fc[0](c, fc[1:])
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 使用filter
|
||||||
|
// 很巧妙就使用了memcache来处理session
|
||||||
|
// revel的session(cookie)只存sessionId, 其它信息存在memcache中
|
||||||
|
|
||||||
|
func MSessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
|
||||||
|
// 从memcache中得到cache, 赋给session
|
||||||
|
cache := revel.Session(memcache.GetMap(sessionId))
|
||||||
|
|
||||||
|
Log("memcache")
|
||||||
|
LogJ(cache)
|
||||||
|
if cache == nil {
|
||||||
|
cache = revel.Session{}
|
||||||
|
cache.Id()
|
||||||
|
}
|
||||||
|
c.Session = cache
|
||||||
|
|
||||||
|
// Make session vars available in templates as {{.session.xyz}}
|
||||||
|
c.RenderArgs["session"] = c.Session
|
||||||
|
|
||||||
|
fc[0](c, fc[1:])
|
||||||
|
|
||||||
|
// 再把session保存之
|
||||||
|
LogJ(c.Session)
|
||||||
|
memcache.SetMap(sessionId, c.Session, -1)
|
||||||
|
|
||||||
|
// 只留下sessionId
|
||||||
|
c.Session = revel.Session{revel.SESSION_ID_KEY: sessionId}
|
||||||
|
}
|
||||||
+197
-18
@@ -1,31 +1,210 @@
|
|||||||
package session
|
package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/robfig/revel"
|
"github.com/revel/revel"
|
||||||
"leanote/app/lea/memcache"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
// . "leanote/app/lea"
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 使用filter
|
// 主要修改revel的cookie, 设置Domain
|
||||||
// 很巧妙就使用了memcache来处理session
|
// 为了使sub domain共享cookie
|
||||||
// revel的session(cookie)只存sessionId, 其它信息存在memcache中
|
// cookie.domain = leanote.com
|
||||||
|
|
||||||
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
// A signed cookie (and thus limited to 4kb in size).
|
||||||
sessionId := c.Session.Id()
|
// Restriction: Keys may not have a colon in them.
|
||||||
|
type Session map[string]string
|
||||||
|
|
||||||
// 从memcache中得到cache, 赋给session
|
const (
|
||||||
cache := revel.Session(memcache.Get(sessionId))
|
SESSION_ID_KEY = "_ID"
|
||||||
if cache == nil {
|
TIMESTAMP_KEY = "_TS"
|
||||||
cache = revel.Session{}
|
)
|
||||||
cache.Id()
|
|
||||||
|
// expireAfterDuration is the time to live, in seconds, of a session cookie.
|
||||||
|
// It may be specified in config as "session.expires". Values greater than 0
|
||||||
|
// set a persistent cookie with a time to live as specified, and the value 0
|
||||||
|
// sets a session cookie.
|
||||||
|
var expireAfterDuration time.Duration
|
||||||
|
var cookieDomain = "" // life
|
||||||
|
func init() {
|
||||||
|
// Set expireAfterDuration, default to 30 days if no value in config
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
var err error
|
||||||
|
if expiresString, ok := revel.Config.String("session.expires"); !ok {
|
||||||
|
expireAfterDuration = 30 * 24 * time.Hour
|
||||||
|
} else if expiresString == "session" {
|
||||||
|
expireAfterDuration = 0
|
||||||
|
} else if expireAfterDuration, err = time.ParseDuration(expiresString); err != nil {
|
||||||
|
panic(fmt.Errorf("session.expires invalid: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
cookieDomain, _ = revel.Config.String("cookie.domain")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
||||||
|
// session.
|
||||||
|
func (s Session) Id() string {
|
||||||
|
|
||||||
|
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
||||||
|
return sessionIdStr
|
||||||
}
|
}
|
||||||
c.Session = cache
|
|
||||||
|
buffer := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(buffer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s[SESSION_ID_KEY] = hex.EncodeToString(buffer)
|
||||||
|
return s[SESSION_ID_KEY]
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExpiration return a time.Time with the session's expiration date.
|
||||||
|
// If previous session has set to "session", remain it
|
||||||
|
func (s Session) getExpiration() time.Time {
|
||||||
|
if expireAfterDuration == 0 || s[TIMESTAMP_KEY] == "session" {
|
||||||
|
// Expire after closing browser
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
return time.Now().Add(expireAfterDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cookie returns an http.Cookie containing the signed session.
|
||||||
|
func (s Session) cookie() *http.Cookie {
|
||||||
|
var sessionValue string
|
||||||
|
ts := s.getExpiration()
|
||||||
|
s[TIMESTAMP_KEY] = getSessionExpirationCookie(ts)
|
||||||
|
for key, value := range s {
|
||||||
|
if strings.ContainsAny(key, ":\x00") {
|
||||||
|
panic("Session keys may not have colons or null bytes")
|
||||||
|
}
|
||||||
|
if strings.Contains(value, "\x00") {
|
||||||
|
panic("Session values may not have null bytes")
|
||||||
|
}
|
||||||
|
sessionValue += "\x00" + key + ":" + value + "\x00"
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionData := url.QueryEscape(sessionValue)
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: revel.CookiePrefix + "_SESSION",
|
||||||
|
Value: revel.Sign(sessionData) + "-" + sessionData,
|
||||||
|
Path: "/",
|
||||||
|
HttpOnly: revel.CookieHttpOnly,
|
||||||
|
Secure: revel.CookieSecure,
|
||||||
|
Expires: ts.UTC(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cookieDomain != "" {
|
||||||
|
cookie.Domain = cookieDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionTimeoutExpiredOrMissing returns a boolean of whether the session
|
||||||
|
// cookie is either not present or present but beyond its time to live; i.e.,
|
||||||
|
// whether there is not a valid session.
|
||||||
|
func sessionTimeoutExpiredOrMissing(session Session) bool {
|
||||||
|
if exp, present := session[TIMESTAMP_KEY]; !present {
|
||||||
|
return true
|
||||||
|
} else if exp == "session" {
|
||||||
|
return false
|
||||||
|
} else if expInt, _ := strconv.Atoi(exp); int64(expInt) < time.Now().Unix() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSessionFromCookie returns a Session struct pulled from the signed
|
||||||
|
// session cookie.
|
||||||
|
func getSessionFromCookie(cookie *http.Cookie) Session {
|
||||||
|
session := make(Session)
|
||||||
|
|
||||||
|
// Separate the data from the signature.
|
||||||
|
hyphen := strings.Index(cookie.Value, "-")
|
||||||
|
if hyphen == -1 || hyphen >= len(cookie.Value)-1 {
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
|
||||||
|
|
||||||
|
// Verify the signature.
|
||||||
|
if !revel.Verify(data, sig) {
|
||||||
|
revel.INFO.Println("Session cookie signature failed")
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
revel.ParseKeyValueCookie(data, func(key, val string) {
|
||||||
|
session[key] = val
|
||||||
|
})
|
||||||
|
|
||||||
|
if sessionTimeoutExpiredOrMissing(session) {
|
||||||
|
session = make(Session)
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionFilter is a Revel Filter that retrieves and sets the session cookie.
|
||||||
|
// Within Revel, it is available as a Session attribute on Controller instances.
|
||||||
|
// The name of the Session cookie is set as CookiePrefix + "_SESSION".
|
||||||
|
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
session := restoreSession(c.Request.Request)
|
||||||
|
// c.Session, 重新生成一个revel.Session给controller!!!
|
||||||
|
// Log("sessoin--------")
|
||||||
|
// LogJ(session)
|
||||||
|
|
||||||
|
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
||||||
|
c.Session = revelSession
|
||||||
|
// 生成sessionId
|
||||||
|
c.Session.Id()
|
||||||
|
sessionWasEmpty := len(c.Session) == 0
|
||||||
|
|
||||||
|
// Make session vars available in templates as {{.session.xyz}}
|
||||||
|
c.RenderArgs["session"] = c.Session
|
||||||
|
|
||||||
fc[0](c, fc[1:])
|
fc[0](c, fc[1:])
|
||||||
|
|
||||||
// 再把session保存之
|
// Store the signed session if it could have changed.
|
||||||
memcache.Set(sessionId, c.Session, -1)
|
if len(c.Session) > 0 || !sessionWasEmpty {
|
||||||
|
// 转换成lea.Session
|
||||||
|
session = Session(c.Session)
|
||||||
|
c.SetCookie(session.cookie())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 只留下sessionId
|
// restoreSession returns either the current session, retrieved from the
|
||||||
c.Session = revel.Session{revel.SESSION_ID_KEY: sessionId}
|
// session cookie, or a new session.
|
||||||
|
func restoreSession(req *http.Request) Session {
|
||||||
|
cookie, err := req.Cookie(revel.CookiePrefix + "_SESSION")
|
||||||
|
if err != nil {
|
||||||
|
return make(Session)
|
||||||
|
} else {
|
||||||
|
return getSessionFromCookie(cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSessionExpirationCookie retrieves the cookie's time to live as a
|
||||||
|
// string of either the number of seconds, for a persistent cookie, or
|
||||||
|
// "session".
|
||||||
|
func getSessionExpirationCookie(t time.Time) string {
|
||||||
|
if t.IsZero() {
|
||||||
|
return "session"
|
||||||
|
}
|
||||||
|
return strconv.FormatInt(t.Unix(), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNoExpiration sets session to expire when browser session ends
|
||||||
|
func (s Session) SetNoExpiration() {
|
||||||
|
s[TIMESTAMP_KEY] = "session"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultExpiration sets session to expire after default duration
|
||||||
|
func (s Session) SetDefaultExpiration() {
|
||||||
|
delete(s, TIMESTAMP_KEY)
|
||||||
}
|
}
|
||||||
+33
-11
@@ -7,6 +7,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
用golang exec 总是说找不到uglifyjs命令, 需要全部路径
|
用golang exec 总是说找不到uglifyjs命令, 需要全部路径
|
||||||
而且node, npm要在/usr/bin下, 已建ln
|
而且node, npm要在/usr/bin下, 已建ln
|
||||||
@@ -31,13 +32,15 @@ import (
|
|||||||
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
||||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
"js/object_id"}
|
||||||
|
|
||||||
var base = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/public/"
|
var base1 = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/"
|
||||||
|
var base = "/Users/life/Documents/Go/package2/src/github.com/leanote/leanote/public/"
|
||||||
var cmdPath = "/usr/local/bin/uglifyjs"
|
var cmdPath = "/usr/local/bin/uglifyjs"
|
||||||
|
|
||||||
func cmdError(err error) {
|
func cmdError(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
fmt.Fprintf(os.Stderr, "The command failed to perform: %s (Command: %s, Arguments: %s)", err, "", "")
|
fmt.Fprintf(os.Stderr, "The command failed to perform: %s (Command: %s, Arguments: %s)", err, "", "")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("OK")
|
fmt.Println("OK")
|
||||||
@@ -50,7 +53,7 @@ func compressJs(filename string) {
|
|||||||
to := base + filename + "-min.js"
|
to := base + filename + "-min.js"
|
||||||
cmd := exec.Command(cmdPath, source, "-o", to)
|
cmd := exec.Command(cmdPath, source, "-o", to)
|
||||||
_, err := cmd.CombinedOutput()
|
_, err := cmd.CombinedOutput()
|
||||||
|
fmt.Println(source);
|
||||||
cmdError(err)
|
cmdError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +65,7 @@ func combineJs() {
|
|||||||
|
|
||||||
for _, js := range jss {
|
for _, js := range jss {
|
||||||
to := base + js + "-min.js"
|
to := base + js + "-min.js"
|
||||||
|
fmt.Println(to)
|
||||||
compressJs(js)
|
compressJs(js)
|
||||||
|
|
||||||
// 每个压缩后的文件放入之
|
// 每个压缩后的文件放入之
|
||||||
@@ -77,20 +81,25 @@ func combineJs() {
|
|||||||
// 改note-dev->note
|
// 改note-dev->note
|
||||||
func dev() {
|
func dev() {
|
||||||
// 即替换note.js->note-min.js
|
// 即替换note.js->note-min.js
|
||||||
m := map[string]string{"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",
|
"app.js": "app-min.js",
|
||||||
"page.js": "page-min.js",
|
"page.js": "page-min.js",
|
||||||
"common.js": "common-min.js",
|
"common.js": "common-min.js",
|
||||||
"notebook.js": "notebook-min.js",
|
"notebook.js": "notebook-min.js",
|
||||||
"share.js": "share-min.js",
|
"share.js": "share-min.js",
|
||||||
"tag.js": "tag-min.js",
|
"tag.js": "tag-min.js",
|
||||||
|
"main.js": "main-min.js",
|
||||||
|
"jquery.slimscroll.js": "jquery.slimscroll-min.js",
|
||||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||||
"editor/editor.js": "editor/editor-min.js",
|
"editor/editor.js": "editor/editor-min.js",
|
||||||
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
||||||
"console.log(o);": "",
|
"console.log(o);": "",
|
||||||
}
|
}
|
||||||
path := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note-dev.html"
|
path := base1 + "/src/views/note/note-dev.html"
|
||||||
target := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note.html"
|
target := base1 + "/src/views/note/note.html"
|
||||||
|
|
||||||
bs, _ := ioutil.ReadFile(path)
|
bs, _ := ioutil.ReadFile(path)
|
||||||
content := string(bs)
|
content := string(bs)
|
||||||
@@ -107,19 +116,30 @@ 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", "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 := 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"
|
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||||
_, err := cmd.CombinedOutput()
|
|
||||||
cmdError(err)
|
// 必须要先删除
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// 压缩tinymce
|
||||||
|
tinymce()
|
||||||
|
|
||||||
dev();
|
dev();
|
||||||
|
|
||||||
// 其它零散的需要压缩的js
|
// 其它零散的需要压缩的js
|
||||||
otherJss := []string{"tinymce/tinymce", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
otherJss := []string{"tinymce/tinymce", "js/main", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
||||||
"mdeditor/editor/scrollLink",
|
"mdeditor/editor/scrollLink",
|
||||||
"mdeditor/editor/editor",
|
"mdeditor/editor/editor",
|
||||||
"mdeditor/editor/jquery.waitforimages",
|
"mdeditor/editor/jquery.waitforimages",
|
||||||
"mdeditor/editor/pagedown/local/Markdown.local.zh",
|
"mdeditor/editor/pagedown/local/Markdown.local.zh",
|
||||||
|
"mdeditor/editor/pagedown/local/Markdown.local.en",
|
||||||
"mdeditor/editor/pagedown/Markdown.Editor",
|
"mdeditor/editor/pagedown/Markdown.Editor",
|
||||||
"mdeditor/editor/pagedown/Markdown.Sanitizer",
|
"mdeditor/editor/pagedown/Markdown.Sanitizer",
|
||||||
"mdeditor/editor/pagedown/Markdown.Converter",
|
"mdeditor/editor/pagedown/Markdown.Converter",
|
||||||
@@ -127,6 +147,10 @@ func main() {
|
|||||||
"mdeditor/editor/underscore",
|
"mdeditor/editor/underscore",
|
||||||
"mdeditor/editor/mathJax",
|
"mdeditor/editor/mathJax",
|
||||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
"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 {
|
for _, js := range otherJss {
|
||||||
@@ -136,6 +160,4 @@ func main() {
|
|||||||
// 先压缩后合并
|
// 先压缩后合并
|
||||||
combineJs()
|
combineJs()
|
||||||
|
|
||||||
// 压缩tinymce
|
|
||||||
tinymce()
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const IMAGE_TYPE = 0
|
||||||
|
|
||||||
|
type AlbumService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// add album
|
||||||
|
func (this *AlbumService) AddAlbum(album info.Album) bool {
|
||||||
|
album.CreatedTime = time.Now()
|
||||||
|
album.Type = IMAGE_TYPE
|
||||||
|
return db.Insert(db.Albums, album)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get albums
|
||||||
|
func (this *AlbumService) GetAlbums(userId string) []info.Album {
|
||||||
|
albums := []info.Album{}
|
||||||
|
db.ListByQ(db.Albums, bson.M{"UserId": bson.ObjectIdHex(userId)}, &albums)
|
||||||
|
return albums
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete album
|
||||||
|
// presupposition: has no images under this ablum
|
||||||
|
func (this *AlbumService) DeleteAlbum(userId, albumId string) (bool, string) {
|
||||||
|
if db.Count(db.Files, bson.M{"AlbumId": bson.ObjectIdHex(albumId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
}) == 0 {
|
||||||
|
return db.DeleteByIdAndUserId(db.Albums, albumId, userId), ""
|
||||||
|
}
|
||||||
|
return false, "has images"
|
||||||
|
}
|
||||||
|
|
||||||
|
// update album name
|
||||||
|
func (this *AlbumService) UpdateAlbum(albumId, userId, name string) bool {
|
||||||
|
return db.UpdateByIdAndUserIdField(db.Albums, albumId, userId, "Name", name)
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttachService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// add attach
|
||||||
|
func (this *AttachService) AddAttach(attach info.Attach) (ok bool, msg string) {
|
||||||
|
attach.CreatedTime = time.Now()
|
||||||
|
ok = db.Insert(db.Attachs, attach)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
// 更新笔记的attachs num
|
||||||
|
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新笔记的附件个数
|
||||||
|
// addNum 1或-1
|
||||||
|
func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int) bool {
|
||||||
|
num := db.Count(db.Attachs, bson.M{"NoteId": noteId})
|
||||||
|
/*
|
||||||
|
note := info.Note{}
|
||||||
|
note = noteService.GetNoteById(noteId.Hex())
|
||||||
|
note.AttachNum += addNum
|
||||||
|
if note.AttachNum < 0 {
|
||||||
|
note.AttachNum = 0
|
||||||
|
}
|
||||||
|
Log(note.AttachNum)
|
||||||
|
*/
|
||||||
|
return db.UpdateByQField(db.Notes, bson.M{"_id": noteId}, "AttachNum", num)
|
||||||
|
}
|
||||||
|
|
||||||
|
// list attachs
|
||||||
|
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
|
||||||
|
attachs := []info.Attach{}
|
||||||
|
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
|
||||||
|
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
|
||||||
|
return attachs
|
||||||
|
}
|
||||||
|
|
||||||
|
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
||||||
|
|
||||||
|
return attachs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
|
||||||
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Delete note to delete attas firstly
|
||||||
|
func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.UserId.Hex() == userId {
|
||||||
|
attachs := []info.Attach{}
|
||||||
|
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
||||||
|
for _, attach := range attachs {
|
||||||
|
attach.Path = strings.TrimLeft(attach.Path, "/")
|
||||||
|
os.Remove(revel.BasePath + "/" + attach.Path)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete attach
|
||||||
|
func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
|
||||||
|
attach := info.Attach{}
|
||||||
|
db.Get(db.Attachs, attachId, &attach)
|
||||||
|
|
||||||
|
if(attach.AttachId != "") {
|
||||||
|
// 判断是否有权限为笔记添加附件
|
||||||
|
if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
|
||||||
|
return false, "No Perm"
|
||||||
|
}
|
||||||
|
|
||||||
|
if db.Delete(db.Attachs, bson.M{"_id": bson.ObjectIdHex(attachId)}) {
|
||||||
|
this.updateNoteAttachNum(attach.NoteId, -1)
|
||||||
|
attach.Path = strings.TrimLeft(attach.Path, "/")
|
||||||
|
err := os.Remove(revel.BasePath + "/" + attach.Path)
|
||||||
|
if err == nil {
|
||||||
|
return true, "delete file error"
|
||||||
|
}
|
||||||
|
return false, "delete file error"
|
||||||
|
}
|
||||||
|
return false, "db error"
|
||||||
|
}
|
||||||
|
return false, "no such item"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件路径
|
||||||
|
// 要判断是否具有权限
|
||||||
|
// userId是否具有attach的访问权限
|
||||||
|
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
|
||||||
|
if attachId == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attach = info.Attach{}
|
||||||
|
db.Get(db.Attachs, attachId, &attach)
|
||||||
|
path := attach.Path
|
||||||
|
if path == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
note := noteService.GetNoteById(attach.NoteId.Hex())
|
||||||
|
|
||||||
|
// 判断权限
|
||||||
|
|
||||||
|
// 笔记是否是公开的
|
||||||
|
if note.IsBlog {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 笔记是否是我的
|
||||||
|
if note.UserId.Hex() == userId {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 我是否有权限查看或协作
|
||||||
|
if shareService.HasReadNotePerm(attach.NoteId.Hex(), userId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//userId为空则是分享笔记的附件
|
||||||
|
if userId == "" && sessionId != "" {
|
||||||
|
if token != "" {
|
||||||
|
realToken := sessionService.GetToken(sessionId)
|
||||||
|
if token == realToken {
|
||||||
|
Log("attach token is equal!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attach = info.Attach{}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制笔记时需要复制附件
|
||||||
|
// noteService调用, 权限已判断
|
||||||
|
func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
|
||||||
|
attachs := []info.Attach{}
|
||||||
|
db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
|
||||||
|
|
||||||
|
// 复制之
|
||||||
|
toNoteIdO := bson.ObjectIdHex(toNoteId)
|
||||||
|
for _, attach := range attachs {
|
||||||
|
attach.AttachId = ""
|
||||||
|
attach.NoteId = toNoteIdO
|
||||||
|
|
||||||
|
// 文件复制一份
|
||||||
|
_, ext := SplitFilename(attach.Name)
|
||||||
|
newFilename := NewGuid() + ext
|
||||||
|
dir := "files/" + toUserId + "/attachs"
|
||||||
|
filePath := dir + "/" + newFilename
|
||||||
|
err := os.MkdirAll(revel.BasePath + "/" + dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = CopyFile(revel.BasePath + "/" + attach.Path, revel.BasePath + "/" + filePath)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
attach.Name = newFilename
|
||||||
|
attach.Path = filePath
|
||||||
|
|
||||||
|
this.AddAttach(attach)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
+38
-16
@@ -1,12 +1,14 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "github.com/leanote/leanote/app/db"
|
// "github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/revel/revel"
|
// "github.com/revel/revel"
|
||||||
|
"strings"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 登录与权限
|
// 登录与权限
|
||||||
@@ -16,7 +18,10 @@ type AuthService struct {
|
|||||||
|
|
||||||
// pwd已md5了
|
// pwd已md5了
|
||||||
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||||
return userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
emailOrUsername = strings.Trim(emailOrUsername, " ")
|
||||||
|
// pwd = strings.Trim(pwd, " ")
|
||||||
|
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||||
|
return userInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
@@ -30,12 +35,16 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
|||||||
// 1. 添加用户
|
// 1. 添加用户
|
||||||
// 2. 将leanote共享给我
|
// 2. 将leanote共享给我
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
func (this *AuthService) Register(email, pwd, fromUserId string) (bool, string) {
|
||||||
// 用户是否已存在
|
// 用户是否已存在
|
||||||
if userService.IsExistsUser(email) {
|
if userService.IsExistsUser(email) {
|
||||||
return false, email + " 已被注册"
|
return false, "userHasBeenRegistered-" + email
|
||||||
}
|
}
|
||||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
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)
|
return this.register(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,20 +65,30 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
email := user.Email
|
email := user.Email
|
||||||
|
|
||||||
// 添加leanote -> 该用户的共享
|
// 添加leanote -> 该用户的共享
|
||||||
leanoteUserId, _ := revel.Config.String("register.sharedUserId"); // "5368c1aa99c37b029d000001";
|
registerSharedUserId := configService.GetGlobalStringConfig("registerSharedUserId")
|
||||||
nk1, _ := revel.Config.String("register.sharedUserShareNotebookId"); // 5368c1aa99c37b029d000002" // leanote
|
if(registerSharedUserId != "") {
|
||||||
welcomeNoteId, _ := revel.Config.String("register.welcomeNoteId") // "5368c1b919807a6f95000000" // 欢迎来到leanote
|
registerSharedNotebooks := configService.GetGlobalArrMapConfig("registerSharedNotebooks")
|
||||||
|
registerSharedNotes := configService.GetGlobalArrMapConfig("registerSharedNotes")
|
||||||
|
registerCopyNoteIds := configService.GetGlobalArrayConfig("registerCopyNoteIds")
|
||||||
|
|
||||||
if leanoteUserId != "" && nk1 != "" && welcomeNoteId != "" {
|
// 添加共享笔记本
|
||||||
shareService.AddShareNotebook(nk1, 0, leanoteUserId, email);
|
for _, notebook := range registerSharedNotebooks {
|
||||||
shareService.AddShareNote(welcomeNoteId, 0, leanoteUserId, email);
|
perm, _ := strconv.Atoi(notebook["perm"])
|
||||||
|
shareService.AddShareNotebook(notebook["notebookId"], perm, registerSharedUserId, email);
|
||||||
|
}
|
||||||
|
|
||||||
// 将welcome copy给我
|
// 添加共享笔记
|
||||||
note := noteService.CopySharedNote(welcomeNoteId, title2Id["life"].Hex(), leanoteUserId, user.UserId.Hex());
|
for _, note := range registerSharedNotes {
|
||||||
|
perm, _ := strconv.Atoi(note["perm"])
|
||||||
|
shareService.AddShareNote(note["noteId"], perm, registerSharedUserId, email);
|
||||||
|
}
|
||||||
|
|
||||||
// 公开为博客
|
// 复制笔记
|
||||||
noteUpdate := bson.M{"IsBlog": true}
|
for _, noteId := range registerCopyNoteIds {
|
||||||
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
||||||
|
noteUpdate := bson.M{"IsBlog": true}
|
||||||
|
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
@@ -78,7 +97,10 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
Title: user.Username + " 's Blog",
|
Title: user.Username + " 's Blog",
|
||||||
SubTitle: "love leanote!",
|
SubTitle: "love leanote!",
|
||||||
AboutMe: "Hello, I am (^_^)",
|
AboutMe: "Hello, I am (^_^)",
|
||||||
|
CanComment: true,
|
||||||
})
|
})
|
||||||
|
// 添加一个单页面
|
||||||
|
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, ""
|
return true, ""
|
||||||
|
|||||||
+1094
-30
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,584 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"time"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 配置服务
|
||||||
|
// 只是全局的, 用户的配置没有
|
||||||
|
type ConfigService struct {
|
||||||
|
adminUserId string
|
||||||
|
siteUrl string
|
||||||
|
adminUsername string
|
||||||
|
// 全局的
|
||||||
|
GlobalAllConfigs map[string]interface{}
|
||||||
|
GlobalStringConfigs map[string]string
|
||||||
|
GlobalArrayConfigs map[string][]string
|
||||||
|
GlobalMapConfigs map[string]map[string]string
|
||||||
|
GlobalArrMapConfigs map[string][]map[string]string
|
||||||
|
}
|
||||||
|
// appStart时 将全局的配置从数据库中得到作为全局
|
||||||
|
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||||
|
this.GlobalAllConfigs = map[string]interface{}{}
|
||||||
|
this.GlobalStringConfigs = map[string]string{}
|
||||||
|
this.GlobalArrayConfigs = map[string][]string{}
|
||||||
|
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||||
|
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||||
|
|
||||||
|
this.adminUsername, _ = revel.Config.String("adminUsername")
|
||||||
|
if this.adminUsername == "" {
|
||||||
|
this.adminUsername = "admin"
|
||||||
|
}
|
||||||
|
this.siteUrl, _ = revel.Config.String("site.url")
|
||||||
|
|
||||||
|
userInfo := userService.GetUserInfoByAny(this.adminUsername)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.adminUserId = userInfo.UserId.Hex()
|
||||||
|
|
||||||
|
configs := []info.Config{}
|
||||||
|
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||||
|
|
||||||
|
for _, config := range configs {
|
||||||
|
if config.IsArr {
|
||||||
|
this.GlobalArrayConfigs[config.Key] = config.ValueArr
|
||||||
|
this.GlobalAllConfigs[config.Key] = config.ValueArr
|
||||||
|
} else if config.IsMap {
|
||||||
|
this.GlobalMapConfigs[config.Key] = config.ValueMap
|
||||||
|
this.GlobalAllConfigs[config.Key] = config.ValueMap
|
||||||
|
} else if config.IsArrMap {
|
||||||
|
this.GlobalArrMapConfigs[config.Key] = config.ValueArrMap
|
||||||
|
this.GlobalAllConfigs[config.Key] = config.ValueArrMap
|
||||||
|
} else {
|
||||||
|
this.GlobalStringConfigs[config.Key] = config.ValueStr
|
||||||
|
this.GlobalAllConfigs[config.Key] = config.ValueStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// 判断是否存在
|
||||||
|
if _, ok := this.GlobalAllConfigs[key]; !ok {
|
||||||
|
// 需要添加
|
||||||
|
config := info.Config{ConfigId: bson.NewObjectId(),
|
||||||
|
UserId: bson.ObjectIdHex(userId),
|
||||||
|
Key: key,
|
||||||
|
IsArr: isArr,
|
||||||
|
IsMap: isMap,
|
||||||
|
IsArrMap: isArrMap,
|
||||||
|
UpdatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
if(isArr) {
|
||||||
|
v, _ := value.([]string)
|
||||||
|
config.ValueArr = v
|
||||||
|
this.GlobalArrayConfigs[key] = v
|
||||||
|
} else if isMap {
|
||||||
|
v, _ := value.(map[string]string)
|
||||||
|
config.ValueMap = v
|
||||||
|
this.GlobalMapConfigs[key] = v
|
||||||
|
} else if isArrMap {
|
||||||
|
v, _ := value.([]map[string]string)
|
||||||
|
config.ValueArrMap = v
|
||||||
|
this.GlobalArrMapConfigs[key] = v
|
||||||
|
} else {
|
||||||
|
v, _ := value.(string)
|
||||||
|
config.ValueStr = v
|
||||||
|
this.GlobalStringConfigs[key] = v
|
||||||
|
}
|
||||||
|
return db.Insert(db.Configs, config)
|
||||||
|
} else {
|
||||||
|
i := bson.M{"UpdatedTime": time.Now()}
|
||||||
|
this.GlobalAllConfigs[key] = value
|
||||||
|
if(isArr) {
|
||||||
|
v, _ := value.([]string)
|
||||||
|
i["ValueArr"] = v
|
||||||
|
this.GlobalArrayConfigs[key] = v
|
||||||
|
} else if isMap {
|
||||||
|
v, _ := value.(map[string]string)
|
||||||
|
i["ValueMap"] = v
|
||||||
|
this.GlobalMapConfigs[key] = v
|
||||||
|
} else if isArrMap {
|
||||||
|
v, _ := value.([]map[string]string)
|
||||||
|
i["ValueArrMap"] = v
|
||||||
|
this.GlobalArrMapConfigs[key] = v
|
||||||
|
} else {
|
||||||
|
v, _ := value.(string)
|
||||||
|
i["ValueStr"] = v
|
||||||
|
this.GlobalStringConfigs[key] = v
|
||||||
|
}
|
||||||
|
return db.UpdateByQMap(db.Configs, bson.M{"UserId": bson.ObjectIdHex(userId), "Key": key}, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新用户配置
|
||||||
|
func (this *ConfigService) UpdateGlobalStringConfig(userId, key string, value string) bool {
|
||||||
|
return this.updateGlobalConfig(userId, key, value, false, false, false)
|
||||||
|
}
|
||||||
|
func (this *ConfigService) UpdateGlobalArrayConfig(userId, key string, value []string) bool {
|
||||||
|
return this.updateGlobalConfig(userId, key, value, true, false, false)
|
||||||
|
}
|
||||||
|
func (this *ConfigService) UpdateGlobalMapConfig(userId, key string, value map[string]string) bool {
|
||||||
|
return this.updateGlobalConfig(userId, key, value, false, true, false)
|
||||||
|
}
|
||||||
|
func (this *ConfigService) UpdateGlobalArrMapConfig(userId, key string, value []map[string]string) bool {
|
||||||
|
return this.updateGlobalConfig(userId, key, value, false, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取全局配置, 博客平台使用
|
||||||
|
func (this *ConfigService) GetGlobalStringConfig(key string) string {
|
||||||
|
return this.GlobalStringConfigs[key]
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetGlobalArrayConfig(key string) []string {
|
||||||
|
arr := this.GlobalArrayConfigs[key]
|
||||||
|
if arr == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetGlobalMapConfig(key string) map[string]string {
|
||||||
|
m := this.GlobalMapConfigs[key]
|
||||||
|
if m == nil {
|
||||||
|
return map[string]string{}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetGlobalArrMapConfig(key string) []map[string]string {
|
||||||
|
m := this.GlobalArrMapConfigs[key]
|
||||||
|
if m == nil {
|
||||||
|
return []map[string]string{}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) IsOpenRegister() bool {
|
||||||
|
return this.GetGlobalStringConfig("openRegister") != ""
|
||||||
|
}
|
||||||
|
//-------
|
||||||
|
// 修改共享笔记的配置
|
||||||
|
func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||||
|
registerSharedNotebookPerms, registerSharedNotePerms []int,
|
||||||
|
registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds []string) (ok bool, msg string) {
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
// 用户是否存在?
|
||||||
|
if registerSharedUserId == "" {
|
||||||
|
ok = true
|
||||||
|
msg = "share userId is blank, So it share nothing to register"
|
||||||
|
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
user := userService.GetUserInfo(registerSharedUserId)
|
||||||
|
if user.UserId == "" {
|
||||||
|
ok = false
|
||||||
|
msg = "no such user: " + registerSharedUserId
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notebooks := []map[string]string{}
|
||||||
|
// 共享笔记本
|
||||||
|
if len(registerSharedNotebookIds) > 0 {
|
||||||
|
for i := 0; i < len(registerSharedNotebookIds); i++ {
|
||||||
|
// 判断笔记本是否存在
|
||||||
|
notebookId := registerSharedNotebookIds[i]
|
||||||
|
if notebookId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
notebook := notebookService.GetNotebook(notebookId, registerSharedUserId)
|
||||||
|
if notebook.NotebookId == "" {
|
||||||
|
ok = false
|
||||||
|
msg = "The user has no such notebook: " + notebookId
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
perm := "0";
|
||||||
|
if registerSharedNotebookPerms[i] == 1 {
|
||||||
|
perm = "1"
|
||||||
|
}
|
||||||
|
notebooks = append(notebooks, map[string]string{"notebookId": notebookId, "perm": perm})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks)
|
||||||
|
|
||||||
|
notes := []map[string]string{}
|
||||||
|
// 共享笔记
|
||||||
|
if len(registerSharedNoteIds) > 0 {
|
||||||
|
for i := 0; i < len(registerSharedNoteIds); i++ {
|
||||||
|
// 判断笔记本是否存在
|
||||||
|
noteId := registerSharedNoteIds[i]
|
||||||
|
if noteId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
note := noteService.GetNote(noteId, registerSharedUserId)
|
||||||
|
if note.NoteId == "" {
|
||||||
|
ok = false
|
||||||
|
msg = "The user has no such note: " + noteId
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
perm := "0";
|
||||||
|
if registerSharedNotePerms[i] == 1 {
|
||||||
|
perm = "1"
|
||||||
|
}
|
||||||
|
notes = append(notes, map[string]string{"noteId": noteId, "perm": perm})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
|
||||||
|
|
||||||
|
// 复制
|
||||||
|
noteIds := []string{}
|
||||||
|
if len(registerCopyNoteIds) > 0 {
|
||||||
|
for i := 0; i < len(registerCopyNoteIds); i++ {
|
||||||
|
// 判断笔记本是否存在
|
||||||
|
noteId := registerCopyNoteIds[i]
|
||||||
|
if noteId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
note := noteService.GetNote(noteId, registerSharedUserId)
|
||||||
|
if note.NoteId == "" {
|
||||||
|
ok = false
|
||||||
|
msg = "The user has no such note: " + noteId
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
noteIds = append(noteIds, noteId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds)
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加备份
|
||||||
|
func (this *ConfigService) AddBackup(path, remark string) bool {
|
||||||
|
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||||
|
n := time.Now().Unix()
|
||||||
|
nstr := fmt.Sprintf("%v", n)
|
||||||
|
backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark})
|
||||||
|
return this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) getBackupDirname() string {
|
||||||
|
n := time.Now()
|
||||||
|
y, m, d := n.Date()
|
||||||
|
return strconv.Itoa(y) + "_" + m.String() + "_" + strconv.Itoa(d) + "_" + fmt.Sprintf("%v", n.Unix())
|
||||||
|
}
|
||||||
|
func (this *ConfigService) Backup(remark string) (ok bool, msg string) {
|
||||||
|
binPath := configService.GetGlobalStringConfig("mongodumpPath")
|
||||||
|
config := revel.Config;
|
||||||
|
dbname, _ := config.String("db.dbname")
|
||||||
|
host, _ := revel.Config.String("db.host")
|
||||||
|
port, _ := revel.Config.String("db.port")
|
||||||
|
username, _ := revel.Config.String("db.username")
|
||||||
|
password, _ := revel.Config.String("db.password")
|
||||||
|
// mongodump -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
|
binPath = binPath + " -h " + host + " -d " + dbname + " -port " + port
|
||||||
|
if username != "" {
|
||||||
|
binPath += " -u " + username + " -p " + password
|
||||||
|
}
|
||||||
|
// 保存的路径
|
||||||
|
dir := revel.BasePath + "/mongodb_backup/" + this.getBackupDirname()
|
||||||
|
binPath += " -o " + dir
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
ok = false
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||||
|
Log(binPath);
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
ok = false
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = configService.AddBackup(dir, remark)
|
||||||
|
return ok, msg
|
||||||
|
}
|
||||||
|
// 还原
|
||||||
|
func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
||||||
|
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||||
|
var i int
|
||||||
|
var backup map[string]string
|
||||||
|
for i, backup = range backups {
|
||||||
|
if backup["createdTime"] == createdTime {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == len(backups) {
|
||||||
|
return false, "Backup Not Found"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先备份当前
|
||||||
|
ok, msg = this.Backup("Auto backup when restore from " + backup["createdTime"] )
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// mongorestore -h localhost -d leanote --directoryperdb /home/user1/gopackage/src/github.com/leanote/leanote/mongodb_backup/leanote_install_data/
|
||||||
|
binPath := configService.GetGlobalStringConfig("mongorestorePath")
|
||||||
|
config := revel.Config;
|
||||||
|
dbname, _ := config.String("db.dbname")
|
||||||
|
host, _ := revel.Config.String("db.host")
|
||||||
|
port, _ := revel.Config.String("db.port")
|
||||||
|
username, _ := revel.Config.String("db.username")
|
||||||
|
password, _ := revel.Config.String("db.password")
|
||||||
|
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
|
binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
|
||||||
|
if username != "" {
|
||||||
|
binPath += " -u " + username + " -p " + password
|
||||||
|
}
|
||||||
|
|
||||||
|
path := backup["path"] + "/" + dbname
|
||||||
|
// 判断路径是否存在
|
||||||
|
if !IsDirExists(path) {
|
||||||
|
return false, path + " Is Not Exists"
|
||||||
|
}
|
||||||
|
|
||||||
|
binPath += " --directoryperdb " + path
|
||||||
|
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", binPath)
|
||||||
|
Log(binPath);
|
||||||
|
b, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
ok = false
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
|
||||||
|
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||||
|
var i int
|
||||||
|
var backup map[string]string
|
||||||
|
for i, backup = range backups {
|
||||||
|
if backup["createdTime"] == createdTime {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == len(backups) {
|
||||||
|
return false, "Backup Not Found"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件夹之
|
||||||
|
err := os.RemoveAll(backups[i]["path"])
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除之
|
||||||
|
backups = append(backups[0:i], backups[i+1:]...)
|
||||||
|
|
||||||
|
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
|
return ok, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool, string) {
|
||||||
|
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||||
|
var i int
|
||||||
|
var backup map[string]string
|
||||||
|
for i, backup = range backups {
|
||||||
|
if backup["createdTime"] == createdTime {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == len(backups) {
|
||||||
|
return false, "Backup Not Found"
|
||||||
|
}
|
||||||
|
backup["remark"] = remark;
|
||||||
|
|
||||||
|
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
|
return ok, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到备份
|
||||||
|
func (this *ConfigService) GetBackup(createdTime string) (map[string]string, bool) {
|
||||||
|
backups := this.GetGlobalArrMapConfig("backups") // [{}, {}]
|
||||||
|
var i int
|
||||||
|
var backup map[string]string
|
||||||
|
for i, backup = range backups {
|
||||||
|
if backup["createdTime"] == createdTime {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == len(backups) {
|
||||||
|
return map[string]string{}, false
|
||||||
|
}
|
||||||
|
return backup, true
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
// sub domain
|
||||||
|
var defaultDomain string
|
||||||
|
var schema = "http://"
|
||||||
|
var port string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
port = strconv.Itoa(revel.HttpPort)
|
||||||
|
if port != "80" {
|
||||||
|
port = ":" + port
|
||||||
|
} else {
|
||||||
|
port = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
||||||
|
if strings.HasPrefix(siteUrl, "http://") {
|
||||||
|
defaultDomain = siteUrl[len("http://"):]
|
||||||
|
} else if strings.HasPrefix(siteUrl, "https://") {
|
||||||
|
defaultDomain = siteUrl[len("https://"):]
|
||||||
|
schema = "https://"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) GetSchema() string {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
// 默认
|
||||||
|
func (this *ConfigService) GetDefaultDomain() string {
|
||||||
|
return defaultDomain
|
||||||
|
}
|
||||||
|
// 包含http://
|
||||||
|
func (this *ConfigService) GetDefaultUrl() string {
|
||||||
|
return schema + defaultDomain
|
||||||
|
}
|
||||||
|
// note
|
||||||
|
func (this *ConfigService) GetNoteDomain() string {
|
||||||
|
subDomain := this.GetGlobalStringConfig("noteSubDomain");
|
||||||
|
if subDomain != "" {
|
||||||
|
return subDomain + port
|
||||||
|
}
|
||||||
|
return this.GetDefaultDomain() + "/note"
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetNoteUrl() string {
|
||||||
|
return schema + this.GetNoteDomain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// blog
|
||||||
|
func (this *ConfigService) GetBlogDomain() string {
|
||||||
|
subDomain := this.GetGlobalStringConfig("blogSubDomain");
|
||||||
|
if subDomain != "" {
|
||||||
|
return subDomain + port
|
||||||
|
}
|
||||||
|
return this.GetDefaultDomain() + "/blog"
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetBlogUrl() string {
|
||||||
|
return schema + this.GetBlogDomain();
|
||||||
|
}
|
||||||
|
// lea
|
||||||
|
func (this *ConfigService) GetLeaDomain() string {
|
||||||
|
subDomain := this.GetGlobalStringConfig("leaSubDomain");
|
||||||
|
if subDomain != "" {
|
||||||
|
return subDomain + port
|
||||||
|
}
|
||||||
|
return this.GetDefaultDomain() + "/lea"
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetLeaUrl() string {
|
||||||
|
return schema + this.GetLeaDomain();
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) GetUserUrl(domain string) string {
|
||||||
|
return schema + domain + port
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetUserSubUrl(subDomain string) string {
|
||||||
|
return schema + subDomain + "." + this.GetDefaultDomain()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否允许自定义域名
|
||||||
|
func (this *ConfigService) AllowCustomDomain() bool {
|
||||||
|
return configService.GetGlobalStringConfig("allowCustomDomain") != ""
|
||||||
|
}
|
||||||
|
// 是否是好的自定义域名
|
||||||
|
func (this *ConfigService) IsGoodCustomDomain(domain string) bool {
|
||||||
|
blacks := this.GetGlobalArrayConfig("blackCustomDomains")
|
||||||
|
for _, black := range blacks {
|
||||||
|
if strings.Contains(domain, black) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (this *ConfigService) IsGoodSubDomain(domain string) bool {
|
||||||
|
blacks := this.GetGlobalArrayConfig("blackSubDomains")
|
||||||
|
LogJ(blacks)
|
||||||
|
for _, black := range blacks {
|
||||||
|
if domain == black {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
}
|
||||||
@@ -0,0 +1,474 @@
|
|||||||
|
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"
|
||||||
|
"net/smtp"
|
||||||
|
"strconv"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
|
||||||
|
type EmailService struct {
|
||||||
|
tpls map[string]*template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEmailService() (*EmailService) {
|
||||||
|
return &EmailService{tpls: map[string]*template.Template{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
var host = ""
|
||||||
|
var emailPort = ""
|
||||||
|
var username = ""
|
||||||
|
var password = ""
|
||||||
|
|
||||||
|
func InitEmailFromDb() {
|
||||||
|
host = configService.GetGlobalStringConfig("emailHost")
|
||||||
|
emailPort = configService.GetGlobalStringConfig("emailPort")
|
||||||
|
username = configService.GetGlobalStringConfig("emailUsername")
|
||||||
|
password = configService.GetGlobalStringConfig("emailPassword")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmailService) SendEmail(to, subject, body string) (ok bool, e string) {
|
||||||
|
InitEmailFromDb()
|
||||||
|
|
||||||
|
if host == "" || emailPort == "" || username == "" || password == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hp := strings.Split(host, ":")
|
||||||
|
auth := smtp.PlainAuth("", username, password, hp[0])
|
||||||
|
|
||||||
|
var content_type string
|
||||||
|
|
||||||
|
mailtype := "html"
|
||||||
|
if mailtype == "html" {
|
||||||
|
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
|
||||||
|
} else{
|
||||||
|
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||||
|
send_to := strings.Split(to, ";")
|
||||||
|
err := smtp.SendMail(host+":"+emailPort, auth, username, send_to, msg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
e = fmt.Sprint(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUser调用
|
||||||
|
// 可以使用一个goroutine
|
||||||
|
func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email string) bool {
|
||||||
|
token := tokenService.NewToken(userInfo.UserId.Hex(), email, info.TokenActiveEmail)
|
||||||
|
if token == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
subject := configService.GetGlobalStringConfig("emailTemplateRegisterSubject");
|
||||||
|
tpl := configService.GetGlobalStringConfig("emailTemplateRegister");
|
||||||
|
|
||||||
|
if(tpl == "") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
|
"user": map[string]interface{}{
|
||||||
|
"userId": userInfo.UserId.Hex(),
|
||||||
|
"email": userInfo.Email,
|
||||||
|
"username": userInfo.Username,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
ok, _, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
ok, _ = this.SendEmail(email, subject, tpl)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改邮箱
|
||||||
|
func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email string) (ok bool, msg string) {
|
||||||
|
// 先验证该email是否被注册了
|
||||||
|
if userService.IsExistsUser(email) {
|
||||||
|
ok = false
|
||||||
|
msg = "该邮箱已注册"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token := tokenService.NewToken(userInfo.UserId.Hex(), email, info.TokenUpdateEmail)
|
||||||
|
|
||||||
|
if token == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subject := configService.GetGlobalStringConfig("emailTemplateUpdateEmailSubject");
|
||||||
|
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
|
"newEmail": email,
|
||||||
|
"user": map[string]interface{}{
|
||||||
|
"userId": userInfo.UserId.Hex(),
|
||||||
|
"email": userInfo.Email,
|
||||||
|
"username": userInfo.Username,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
ok, msg = this.SendEmail(email, subject, tpl)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg string) {
|
||||||
|
subject := configService.GetGlobalStringConfig("emailTemplateFindPasswordSubject");
|
||||||
|
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
|
||||||
|
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
||||||
|
|
||||||
|
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 发送邮件
|
||||||
|
ok, msg = this.SendEmail(email, subject, tpl)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送邀请链接
|
||||||
|
func (this *EmailService) SendInviteEmail(userInfo info.User, email, content string) bool {
|
||||||
|
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
|
||||||
|
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
||||||
|
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
|
||||||
|
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
|
||||||
|
"content": content,
|
||||||
|
"user": map[string]interface{}{
|
||||||
|
"username": userInfo.Username,
|
||||||
|
"email": userInfo.Email,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
ok, _, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 发送邮件
|
||||||
|
ok, _ = this.SendEmail(email, subject, tpl)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送评论
|
||||||
|
func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComment, userId, content string) bool {
|
||||||
|
subject := configService.GetGlobalStringConfig("emailTemplateCommentSubject");
|
||||||
|
tpl := configService.GetGlobalStringConfig("emailTemplateComment");
|
||||||
|
|
||||||
|
// title := "评论提醒"
|
||||||
|
|
||||||
|
/*
|
||||||
|
toUserId := note.UserId.Hex()
|
||||||
|
// title := "评论提醒"
|
||||||
|
|
||||||
|
// 表示回复回复的内容, 那么发送给之前回复的
|
||||||
|
if comment.CommentId != "" {
|
||||||
|
toUserId = comment.UserId.Hex()
|
||||||
|
}
|
||||||
|
toUserInfo := userService.GetUserInfo(toUserId)
|
||||||
|
sendUserInfo := userService.GetUserInfo(userId)
|
||||||
|
|
||||||
|
subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
|
||||||
|
if comment.CommentId != "" {
|
||||||
|
subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
|
||||||
|
if userId == note.UserId.Hex() {
|
||||||
|
subject += "(作者)";
|
||||||
|
}
|
||||||
|
subject += " 的评论";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
toUserId := note.UserId.Hex()
|
||||||
|
// 表示回复回复的内容, 那么发送给之前回复的
|
||||||
|
if comment.CommentId != "" {
|
||||||
|
toUserId = comment.UserId.Hex()
|
||||||
|
}
|
||||||
|
toUserInfo := userService.GetUserInfo(toUserId) // 被评论者
|
||||||
|
sendUserInfo := userService.GetUserInfo(userId) // 评论者
|
||||||
|
|
||||||
|
// {siteUrl} {blogUrl}
|
||||||
|
// {blog.id} {blog.title} {blog.url}
|
||||||
|
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
||||||
|
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(),
|
||||||
|
"blog": map[string]string{
|
||||||
|
"id": note.NoteId.Hex(),
|
||||||
|
"title": note.Title,
|
||||||
|
"url": configService.GetBlogUrl() + "/view/" + note.NoteId.Hex(),
|
||||||
|
},
|
||||||
|
"commentContent": content,
|
||||||
|
// 评论者信息
|
||||||
|
"commentUser": map[string]interface{}{"userId": sendUserInfo.UserId.Hex(),
|
||||||
|
"username": sendUserInfo.Username,
|
||||||
|
"email": sendUserInfo.Email,
|
||||||
|
"isBlogAuthor": userId == note.UserId.Hex(),
|
||||||
|
},
|
||||||
|
// 被评论者信息
|
||||||
|
"commentedUser": map[string]interface{}{"userId": toUserId,
|
||||||
|
"username": toUserInfo.Username,
|
||||||
|
"email": toUserInfo.Email,
|
||||||
|
"isBlogAuthor": toUserId == note.UserId.Hex(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := false
|
||||||
|
ok, _, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
ok, _ = this.SendEmail(toUserInfo.Email, subject, tpl)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 验证模板是否正确
|
||||||
|
func (this *EmailService) ValidTpl(str string) (ok bool, msg string){
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
header := configService.GetGlobalStringConfig("emailTemplateHeader");
|
||||||
|
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
|
||||||
|
str = strings.Replace(str, "{{header}}", header, -1)
|
||||||
|
str = strings.Replace(str, "{{footer}}", footer, -1)
|
||||||
|
_, err := template.New("tpl name").Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, msg, subject, tpl
|
||||||
|
func (this *EmailService) getTpl(str string) (ok bool, msg string, tpl *template.Template){
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var has bool
|
||||||
|
|
||||||
|
if tpl, has = this.tpls[str]; !has {
|
||||||
|
tpl, err = template.New("tpl name").Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.tpls[str] = tpl
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过subject, body和值得到内容
|
||||||
|
func (this *EmailService) renderEmail(subject, body string, values map[string]interface{}) (ok bool, msg string, o string, b string) {
|
||||||
|
ok = false
|
||||||
|
msg = ""
|
||||||
|
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
msg = fmt.Sprint(err) // 这里的err其实就是panic传入的内容,
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
var tpl *template.Template
|
||||||
|
|
||||||
|
values["siteUrl"] = configService.GetSiteUrl();
|
||||||
|
|
||||||
|
// subject
|
||||||
|
if subject != "" {
|
||||||
|
ok, msg, tpl = this.getTpl(subject)
|
||||||
|
if(!ok) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err := tpl.Execute(&buffer, values)
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o = buffer.String()
|
||||||
|
} else {
|
||||||
|
o = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// content
|
||||||
|
header := configService.GetGlobalStringConfig("emailTemplateHeader");
|
||||||
|
footer := configService.GetGlobalStringConfig("emailTemplateFooter");
|
||||||
|
body = strings.Replace(body, "{{header}}", header, -1)
|
||||||
|
body = strings.Replace(body, "{{footer}}", footer, -1)
|
||||||
|
values["subject"] = o
|
||||||
|
ok, msg, tpl = this.getTpl(body)
|
||||||
|
if(!ok) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buffer2 bytes.Buffer
|
||||||
|
err := tpl.Execute(&buffer2, values)
|
||||||
|
if err != nil {
|
||||||
|
msg = fmt.Sprint(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b = buffer2.String()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送email给用户
|
||||||
|
// 需要记录
|
||||||
|
func (this *EmailService) SendEmailToUsers(users []info.User, subject, body string) (ok bool, msg string) {
|
||||||
|
if(users == nil || len(users) == 0) {
|
||||||
|
msg = "no users"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试renderHtml
|
||||||
|
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
|
||||||
|
if(!ok) {
|
||||||
|
Log(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, user := range users {
|
||||||
|
LogJ(user)
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
m["userId"] = user.UserId.Hex()
|
||||||
|
m["username"] = user.Username
|
||||||
|
m["email"] = user.Email
|
||||||
|
ok2, msg2, subject2, body2 := this.renderEmail(subject, body, m)
|
||||||
|
ok = ok2
|
||||||
|
msg = msg2
|
||||||
|
if(ok2) {
|
||||||
|
sendOk, msg := this.SendEmail(user.Email, subject2, body2);
|
||||||
|
this.AddEmailLog(user.Email, subject, body, sendOk, msg) // 把模板记录下
|
||||||
|
// 记录到Email Log
|
||||||
|
if sendOk {
|
||||||
|
// Log("ok " + user.Email)
|
||||||
|
} else {
|
||||||
|
// Log("no " + user.Email)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *EmailService) SendEmailToEmails(emails []string, subject, body string) (ok bool, msg string) {
|
||||||
|
if(emails == nil || len(emails) == 0) {
|
||||||
|
msg = "no emails"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试renderHtml
|
||||||
|
ok, msg, _, _ = this.renderEmail(subject, body, map[string]interface{}{})
|
||||||
|
if(!ok) {
|
||||||
|
Log(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// go func() {
|
||||||
|
for _, email := range emails {
|
||||||
|
if email == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
m["email"] = email
|
||||||
|
ok, msg, subject, body = this.renderEmail(subject, body, m)
|
||||||
|
if(ok) {
|
||||||
|
sendOk, msg := this.SendEmail(email, subject, body);
|
||||||
|
this.AddEmailLog(email, subject, body, sendOk, msg)
|
||||||
|
// 记录到Email Log
|
||||||
|
if sendOk {
|
||||||
|
Log("ok " + email)
|
||||||
|
} else {
|
||||||
|
Log("no " + email)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加邮件日志
|
||||||
|
func (this *EmailService) AddEmailLog(email, subject, body string, ok bool, msg string) {
|
||||||
|
log := info.EmailLog{LogId: bson.NewObjectId(), Email: email, Subject: subject, Body: body, Ok: ok, Msg: msg, CreatedTime: time.Now()}
|
||||||
|
db.Insert(db.EmailLogs, log)
|
||||||
|
}
|
||||||
|
// 展示邮件日志
|
||||||
|
|
||||||
|
func (this *EmailService) DeleteEmails(ids []string) bool {
|
||||||
|
idsO := make([]bson.ObjectId, len(ids))
|
||||||
|
for i, id := range ids {
|
||||||
|
idsO[i] = bson.ObjectIdHex(id)
|
||||||
|
}
|
||||||
|
db.DeleteAll(db.EmailLogs, bson.M{"_id": bson.M{"$in": idsO}})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (this *EmailService) ListEmailLogs(pageNumber, pageSize int, sortField string, isAsc bool, email string) (page info.Page, emailLogs []info.EmailLog) {
|
||||||
|
emailLogs = []info.EmailLog{}
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
query := bson.M{}
|
||||||
|
if email != "" {
|
||||||
|
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
|
||||||
|
}
|
||||||
|
q := db.EmailLogs.Find(query);
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
// 列表
|
||||||
|
q.Sort(sortFieldR).
|
||||||
|
Skip(skipNum).
|
||||||
|
Limit(pageSize).
|
||||||
|
All(&emailLogs)
|
||||||
|
page = info.NewPage(pageNumber, pageSize, count, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
// "fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||||
|
|
||||||
|
type FileService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Image
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
image.AlbumId = bson.ObjectIdHex(DEFAULT_ALBUM_ID)
|
||||||
|
image.IsDefaultAlbum = true
|
||||||
|
}
|
||||||
|
image.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Files, image)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// list images
|
||||||
|
// if albumId == "" get default album images
|
||||||
|
func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNumber, pageSize int) info.Page {
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
|
||||||
|
files := []info.File{}
|
||||||
|
|
||||||
|
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
|
||||||
|
if albumId != "" {
|
||||||
|
q["AlbumId"] = bson.ObjectIdHex(albumId);
|
||||||
|
} else {
|
||||||
|
q["IsDefaultAlbum"] = true
|
||||||
|
}
|
||||||
|
if key != "" {
|
||||||
|
q["Title"] = bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogJ(q)
|
||||||
|
|
||||||
|
count := db.Count(db.Files, q);
|
||||||
|
|
||||||
|
db.Files.
|
||||||
|
Find(q).
|
||||||
|
Sort(sortFieldR).
|
||||||
|
Skip(skipNum).
|
||||||
|
Limit(pageSize).
|
||||||
|
All(&files)
|
||||||
|
|
||||||
|
return info.Page{Count: count, List: files}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *FileService) UpdateImageTitle(userId, fileId, title string) bool {
|
||||||
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all images names
|
||||||
|
// for upgrade
|
||||||
|
func (this *FileService) GetAllImageNamesMap(userId string) (m map[string]bool) {
|
||||||
|
q := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
||||||
|
files := []info.File{}
|
||||||
|
db.ListByQWithFields(db.Files, q, []string{"Name"}, &files)
|
||||||
|
|
||||||
|
m = make(map[string]bool)
|
||||||
|
if len(files) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
m[file.Name] = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete image
|
||||||
|
func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
|
||||||
|
file := info.File{}
|
||||||
|
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
|
||||||
|
|
||||||
|
if(file.FileId != "") {
|
||||||
|
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
|
||||||
|
// delete image
|
||||||
|
// TODO
|
||||||
|
file.Path = strings.TrimLeft(file.Path, "/")
|
||||||
|
var err error
|
||||||
|
if strings.HasPrefix(file.Path, "upload") {
|
||||||
|
Log(file.Path)
|
||||||
|
err = os.Remove(revel.BasePath + "/public/" + file.Path)
|
||||||
|
} else {
|
||||||
|
err = os.Remove(revel.BasePath + "/" + file.Path)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
return false, "delete file error!"
|
||||||
|
}
|
||||||
|
return false, "db error"
|
||||||
|
}
|
||||||
|
return false, "no such item"
|
||||||
|
}
|
||||||
|
|
||||||
|
// update image title
|
||||||
|
func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
||||||
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件路径
|
||||||
|
// 要判断是否具有权限
|
||||||
|
// userId是否具有fileId的访问权限
|
||||||
|
|
||||||
|
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
|
||||||
|
if fileId == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
file := info.File{}
|
||||||
|
db.Get(db.Files, fileId, &file)
|
||||||
|
path := file.Path
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 判断权限
|
||||||
|
//未登录用户,判断token
|
||||||
|
noteIds := noteImageService.GetNoteIds(fileId)
|
||||||
|
// 是否是我的文件
|
||||||
|
if userId != "" && file.UserId.Hex() == userId {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到使用过该fileId的所有笔记NoteId
|
||||||
|
// 这些笔记是否有public的, 若有则ok
|
||||||
|
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 笔记本是否共享给我?
|
||||||
|
// 通过笔记得到笔记本
|
||||||
|
notes := []info.Note{}
|
||||||
|
db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, ¬es)
|
||||||
|
if notes != nil && len(notes) > 0 {
|
||||||
|
notebookIds := make([]bson.ObjectId, len(notes))
|
||||||
|
for i := 0; i < len(notes); i++ {
|
||||||
|
notebookIds[i] = notes[i].NotebookId
|
||||||
|
}
|
||||||
|
|
||||||
|
if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
|
||||||
|
if file.FromFileId != "" {
|
||||||
|
fromFile := info.File{}
|
||||||
|
db.Get2(db.Files, file.FromFileId, &fromFile)
|
||||||
|
if fromFile.UserId.Hex() == userId {
|
||||||
|
return fromFile.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 复制图片
|
||||||
|
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
|
||||||
|
// 是否已经复制过了
|
||||||
|
file2 := info.File{}
|
||||||
|
db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
|
||||||
|
if file2.FileId != "" {
|
||||||
|
return true, file2.FileId.Hex();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制之
|
||||||
|
|
||||||
|
file := info.File{}
|
||||||
|
db.GetByIdAndUserId(db.Files, fileId, userId, &file)
|
||||||
|
|
||||||
|
if file.FileId == "" || file.UserId.Hex() != userId {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ext := SplitFilename(file.Name)
|
||||||
|
newFilename := NewGuid() + ext
|
||||||
|
|
||||||
|
dir := "files/" + toUserId + "/images"
|
||||||
|
filePath := dir + "/" + newFilename
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
|
||||||
|
if err != nil {
|
||||||
|
Log(err)
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo := info.File{Name: newFilename,
|
||||||
|
Title: file.Title,
|
||||||
|
Path: filePath,
|
||||||
|
Size: file.Size,
|
||||||
|
FromFileId: file.FileId}
|
||||||
|
id := bson.NewObjectId();
|
||||||
|
fileInfo.FileId = id
|
||||||
|
fileId = id.Hex()
|
||||||
|
Ok, _ := this.AddImage(fileInfo, "", toUserId, false)
|
||||||
|
|
||||||
|
if Ok {
|
||||||
|
return Ok, id.Hex()
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否是我的文件
|
||||||
|
func (this *FileService) IsMyFile(userId, fileId string) bool {
|
||||||
|
return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
|
||||||
|
}
|
||||||
@@ -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)}), ""
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,7 +33,8 @@ func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHis
|
|||||||
// TODO
|
// TODO
|
||||||
l := len(history.Histories)
|
l := len(history.Histories)
|
||||||
if l >= maxSize {
|
if l >= maxSize {
|
||||||
history.Histories = history.Histories[l-maxSize:]
|
// history.Histories = history.Histories[l-maxSize:] // BUG, 致使都是以前的
|
||||||
|
history.Histories = history.Histories[:maxSize]
|
||||||
}
|
}
|
||||||
newHistory := []info.EachHistory{eachHistory}
|
newHistory := []info.EachHistory{eachHistory}
|
||||||
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
|
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
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"
|
||||||
|
"regexp"
|
||||||
|
// "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NoteImageService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过id, userId得到noteIds
|
||||||
|
func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
||||||
|
noteImages := []info.NoteImage{}
|
||||||
|
db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, ¬eImages)
|
||||||
|
|
||||||
|
if noteImages != nil && len(noteImages) > 0 {
|
||||||
|
noteIds := make([]bson.ObjectId, len(noteImages))
|
||||||
|
cnt := len(noteImages)
|
||||||
|
for i := 0; i < cnt; i++ {
|
||||||
|
noteIds[i] = noteImages[i].NoteId
|
||||||
|
}
|
||||||
|
return noteIds
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析内容中的图片, 建立图片与note的关系
|
||||||
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
|
// 图片必须是我的, 不然不添加
|
||||||
|
// 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) // 查找所有的
|
||||||
|
|
||||||
|
// 删除旧的
|
||||||
|
db.DeleteAll(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(noteId)})
|
||||||
|
|
||||||
|
// 添加新的
|
||||||
|
var fileId string
|
||||||
|
noteImage := info.NoteImage{NoteId: bson.ObjectIdHex(noteId)}
|
||||||
|
hasAdded := make(map[string]bool)
|
||||||
|
if find != nil && len(find) > 0 {
|
||||||
|
for _, each := range find {
|
||||||
|
if each != nil && len(each) == 2 {
|
||||||
|
fileId = each[1]
|
||||||
|
// 之前没能添加过的
|
||||||
|
if _, ok := hasAdded[fileId]; !ok {
|
||||||
|
Log(fileId)
|
||||||
|
// 判断是否是我的文件
|
||||||
|
if fileService.IsMyFile(userId, fileId) {
|
||||||
|
noteImage.ImageId = bson.ObjectIdHex(fileId)
|
||||||
|
db.Insert(db.NoteImages, noteImage)
|
||||||
|
}
|
||||||
|
hasAdded[fileId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
|
||||||
|
func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
|
||||||
|
// 得到fromNoteId的noteImages, 如果为空, 则直接返回content
|
||||||
|
noteImages := []info.NoteImage{}
|
||||||
|
db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, ¬eImages)
|
||||||
|
|
||||||
|
if len(noteImages) == 0 {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
|
// 把fileId=1232替换成新的
|
||||||
|
replaceMap := map[string]string{}
|
||||||
|
for _, noteImage := range noteImages {
|
||||||
|
imageId := noteImage.ImageId.Hex()
|
||||||
|
ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
|
||||||
|
if ok {
|
||||||
|
replaceMap[imageId] = newImageId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(replaceMap) > 0 {
|
||||||
|
// 替换之
|
||||||
|
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||||
|
content = reg.ReplaceAllStringFunc(content, func(each string) string {
|
||||||
|
// each=outputImage?fileId=541bd2f599c37b4f3r000003
|
||||||
|
fileId := each[len(each)-24:] // 得到后24位, 也即id
|
||||||
|
if replaceFileId, ok := replaceMap[fileId]; ok {
|
||||||
|
return "outputImage?fileId=" + replaceFileId
|
||||||
|
}
|
||||||
|
return each
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
+160
-19
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,6 +17,23 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
|||||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//通过附件id得到note
|
||||||
|
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
|
||||||
|
attach := info.Attach{}
|
||||||
|
db.Get(db.Attachs, attachId, &attach)
|
||||||
|
note = info.Note{}
|
||||||
|
noteId := attach.NoteId
|
||||||
|
db.Get(db.Notes, noteId.Hex(), ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileService调用
|
||||||
|
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||||
|
note = info.Note{}
|
||||||
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 得到blog, blogService用
|
// 得到blog, blogService用
|
||||||
// 不要传userId, 因为是公开的
|
// 不要传userId, 因为是公开的
|
||||||
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
||||||
@@ -105,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)
|
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
||||||
return
|
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
|
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||||
// [ok]
|
// [ok]
|
||||||
|
|
||||||
func (this *NoteService) AddNote(note info.Note) info.Note {
|
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId();
|
noteId := bson.NewObjectId();
|
||||||
@@ -118,15 +141,24 @@ func (this *NoteService) AddNote(note info.Note) info.Note {
|
|||||||
note.UpdatedTime = note.CreatedTime
|
note.UpdatedTime = note.CreatedTime
|
||||||
note.IsTrash = false
|
note.IsTrash = false
|
||||||
note.UpdatedUserId = note.UserId
|
note.UpdatedUserId = note.UserId
|
||||||
|
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||||
|
|
||||||
// 设为blog
|
// 设为blog
|
||||||
note.IsBlog = notebookService.IsBlog(note.NotebookId.Hex())
|
notebookId := note.NotebookId.Hex()
|
||||||
|
note.IsBlog = notebookService.IsBlog(notebookId)
|
||||||
|
|
||||||
|
if note.IsBlog {
|
||||||
|
note.PublicTime = note.UpdatedTime
|
||||||
|
}
|
||||||
|
|
||||||
db.Insert(db.Notes, note)
|
db.Insert(db.Notes, note)
|
||||||
|
|
||||||
// tag1
|
// tag1
|
||||||
tagService.AddTags(note.UserId.Hex(), note.Tags)
|
tagService.AddTags(note.UserId.Hex(), note.Tags)
|
||||||
|
|
||||||
|
// recount notebooks' notes number
|
||||||
|
notebookService.ReCountNotebookNumberNotes(notebookId)
|
||||||
|
|
||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,11 +180,26 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
|||||||
noteContent.UpdatedTime = noteContent.CreatedTime
|
noteContent.UpdatedTime = noteContent.CreatedTime
|
||||||
noteContent.UpdatedUserId = noteContent.UserId
|
noteContent.UpdatedUserId = noteContent.UserId
|
||||||
db.Insert(db.NoteContents, noteContent)
|
db.Insert(db.NoteContents, noteContent)
|
||||||
|
|
||||||
|
// 更新笔记图片
|
||||||
|
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), "", noteContent.Content)
|
||||||
|
|
||||||
return noteContent;
|
return noteContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加笔记和内容
|
// 添加笔记和内容
|
||||||
// 这里使用 info.NoteAndContent 接收?
|
// 这里使用 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 {
|
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId()
|
noteId := bson.NewObjectId()
|
||||||
@@ -171,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 {
|
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH")
|
Log("NO AUTH2")
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
Log("HAS AUTH -----------")
|
Log("HAS AUTH -----------")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
|
delete(needUpdate, "ImgSrc")
|
||||||
|
delete(needUpdate, "Desc")
|
||||||
|
}
|
||||||
|
|
||||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
|
|
||||||
@@ -226,34 +279,78 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId,
|
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
|
||||||
"Content": content,
|
"Content": content,
|
||||||
"Abstract": abstract,
|
"Abstract": abstract,
|
||||||
"UpdatedTime": time.Now()}) {
|
"UpdatedTime": time.Now()}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
|
delete(data, "Abstract")
|
||||||
|
}
|
||||||
|
|
||||||
|
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
||||||
// 这里, 添加历史记录
|
// 这里, 添加历史记录
|
||||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||||
Content: content,
|
Content: content,
|
||||||
UpdatedTime: time.Now(),
|
UpdatedTime: time.Now(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 更新笔记图片
|
||||||
|
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ?????
|
||||||
|
// 这种方式太恶心, 改动很大
|
||||||
|
// 通过content修改笔记的imageIds列表
|
||||||
|
// src="http://localhost:9000/file/outputImage?fileId=541ae75499c37b6b79000005¬eId=541ae63c19807a4bb9000000"
|
||||||
|
func (this *NoteService) updateNoteImages(noteId string, content string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 更新tags
|
// 更新tags
|
||||||
// [ok] [del]
|
// [ok] [del]
|
||||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||||
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
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
|
// 移动note
|
||||||
// trash, 正常的都可以用
|
// trash, 正常的都可以用
|
||||||
// 1. 要检查下notebookId是否是自己的
|
// 1. 要检查下notebookId是否是自己的
|
||||||
// 2. 要判断之前是否是blog, 如果不是, 那么notebook是否是blog?
|
// 2. 要判断之前是否是blog, 如果不是, 那么notebook是否是blog?
|
||||||
func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
||||||
if notebookService.IsMyNotebook(notebookId, userId) {
|
if notebookService.IsMyNotebook(notebookId, userId) {
|
||||||
|
note := this.GetNote(noteId, userId)
|
||||||
|
preNotebookId := note.NotebookId.Hex()
|
||||||
|
|
||||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||||
bson.M{"$set": bson.M{"IsTrash": false,
|
bson.M{"$set": bson.M{"IsTrash": false,
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||||
@@ -261,6 +358,13 @@ func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
|||||||
if re {
|
if re {
|
||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
this.updateToNotebookBlog(noteId, notebookId, userId)
|
this.updateToNotebookBlog(noteId, notebookId, userId)
|
||||||
|
|
||||||
|
// recount notebooks' notes number
|
||||||
|
notebookService.ReCountNotebookNumberNotes(notebookId)
|
||||||
|
// 之前不是trash才统计, trash本不在统计中的
|
||||||
|
if !note.IsTrash && preNotebookId != notebookId {
|
||||||
|
notebookService.ReCountNotebookNumberNotes(preNotebookId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.GetNote(noteId, userId);
|
return this.GetNote(noteId, userId);
|
||||||
@@ -308,7 +412,11 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
|||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
|
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
|
||||||
|
|
||||||
|
// recount
|
||||||
|
notebookService.ReCountNotebookNumberNotes(notebookId)
|
||||||
|
|
||||||
note.IsBlog = isBlog
|
note.IsBlog = isBlog
|
||||||
|
|
||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,9 +424,12 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 复制别人的共享笔记给我
|
// 复制别人的共享笔记给我
|
||||||
// TODO 判断是否共享了给我
|
// 将别人可用的图片转为我的图片, 复制图片
|
||||||
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
|
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
|
||||||
if notebookService.IsMyNotebook(notebookId, myUserId) {
|
// Log(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId))
|
||||||
|
// 判断是否共享了给我
|
||||||
|
if notebookService.IsMyNotebook(notebookId, myUserId) &&
|
||||||
|
(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId)) {
|
||||||
note := this.GetNote(noteId, fromUserId)
|
note := this.GetNote(noteId, fromUserId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
return info.Note{}
|
return info.Note{}
|
||||||
@@ -332,16 +443,27 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
|
|||||||
note.IsTop = false
|
note.IsTop = false
|
||||||
note.IsBlog = false // 别人的可能是blog
|
note.IsBlog = false // 别人的可能是blog
|
||||||
|
|
||||||
|
note.ImgSrc = "" // 为什么清空, 因为图片需要复制, 先清空
|
||||||
|
|
||||||
// content
|
// content
|
||||||
noteContent.NoteId = note.NoteId
|
noteContent.NoteId = note.NoteId
|
||||||
noteContent.UserId = note.UserId
|
noteContent.UserId = note.UserId
|
||||||
|
|
||||||
|
// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
|
||||||
|
noteContent.Content = noteImageService.CopyNoteImages(noteId, fromUserId, note.NoteId.Hex(), noteContent.Content, myUserId)
|
||||||
|
|
||||||
|
// 复制附件
|
||||||
|
attachService.CopyAttachs(noteId, note.NoteId.Hex(), myUserId)
|
||||||
|
|
||||||
// 添加之
|
// 添加之
|
||||||
note = this.AddNoteAndContent(note, noteContent, note.UserId);
|
note = this.AddNoteAndContent(note, noteContent, note.UserId);
|
||||||
|
|
||||||
// 更新blog状态
|
// 更新blog状态
|
||||||
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, myUserId)
|
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, myUserId)
|
||||||
|
|
||||||
|
// recount
|
||||||
|
notebookService.ReCountNotebookNumberNotes(notebookId)
|
||||||
|
|
||||||
note.IsBlog = isBlog
|
note.IsBlog = isBlog
|
||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
@@ -353,21 +475,28 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
|
|||||||
// shareService call
|
// shareService call
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
||||||
note := &info.Note{}
|
note := info.Note{}
|
||||||
db.Get(db.Notes, noteId, note)
|
// db.Get(db.Notes, noteId, ¬e)
|
||||||
|
// LogJ(note)
|
||||||
|
db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"NotebookId"}, ¬e)
|
||||||
return note.NotebookId
|
return note.NotebookId
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------
|
//------------------
|
||||||
// 搜索Note
|
// 搜索Note, 博客使用了
|
||||||
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
||||||
notes = []info.Note{}
|
notes = []info.Note{}
|
||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
|
// 利用标题和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的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
"$or": orQ,
|
||||||
}
|
}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
query["IsBlog"] = true
|
query["IsBlog"] = true
|
||||||
@@ -396,7 +525,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
|||||||
for i, note := range notes {
|
for i, note := range notes {
|
||||||
noteIds[i] = note.NoteId
|
noteIds[i] = note.NoteId
|
||||||
}
|
}
|
||||||
LogJ(noteIds)
|
|
||||||
noteContents := []info.NoteContent{}
|
noteContents := []info.NoteContent{}
|
||||||
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
@@ -419,9 +547,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
|||||||
noteIds2[i] = content.NoteId
|
noteIds2[i] = content.NoteId
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log(" content search ")
|
|
||||||
// Log(lenContent)
|
|
||||||
|
|
||||||
// 得到notes
|
// 得到notes
|
||||||
notes2 := this.ListNotesByNoteIds(noteIds2)
|
notes2 := this.ListNotesByNoteIds(noteIds2)
|
||||||
|
|
||||||
@@ -446,11 +571,27 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
// 总记录数
|
// 总记录数
|
||||||
count, _ = q.Count()
|
count, _ = q.Count()
|
||||||
|
|
||||||
Log(count)
|
|
||||||
|
|
||||||
q.Sort(sortFieldR).
|
q.Sort(sortFieldR).
|
||||||
Skip(skipNum).
|
Skip(skipNum).
|
||||||
Limit(pageSize).
|
Limit(pageSize).
|
||||||
All(¬es)
|
All(¬es)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// 统计
|
||||||
|
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(userId string) int {
|
||||||
|
q := bson.M{"IsBlog": true, "IsTrash": false}
|
||||||
|
if userId != "" {
|
||||||
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
}
|
||||||
|
return db.Count(db.Notes, q)
|
||||||
|
}
|
||||||
+129
-38
@@ -2,10 +2,10 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
// "fmt"
|
// "fmt"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -47,31 +47,40 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
|
|||||||
newNotebooks.NumberNotes = each.NumberNotes
|
newNotebooks.NumberNotes = each.NumberNotes
|
||||||
newNotebooks.IsTrash = each.IsTrash
|
newNotebooks.IsTrash = each.IsTrash
|
||||||
newNotebooks.IsBlog = each.IsBlog
|
newNotebooks.IsBlog = each.IsBlog
|
||||||
|
|
||||||
|
// 存地址
|
||||||
userNotebooksMap[each.NotebookId] = &newNotebooks
|
userNotebooksMap[each.NotebookId] = &newNotebooks
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第二遍, 追加到父下
|
// 第二遍, 追加到父下
|
||||||
// nilObjectId := bson.ObjectIdHex("")
|
|
||||||
|
// 需要删除的id
|
||||||
|
needDeleteNotebookId := map[bson.ObjectId]bool{}
|
||||||
for id, each := range userNotebooksMap {
|
for id, each := range userNotebooksMap {
|
||||||
// 如果有父, 那么追加到父下, 并剪掉当前, 那么最后就只有根的元素
|
// 如果有父, 那么追加到父下, 并剪掉当前, 那么最后就只有根的元素
|
||||||
if each.ParentNotebookId.Hex() != "" {
|
if each.ParentNotebookId.Hex() != "" {
|
||||||
if userNotebooksMap[each.ParentNotebookId] != nil {
|
if userNotebooksMap[each.ParentNotebookId] != nil {
|
||||||
userNotebooksMap[each.ParentNotebookId].Subs = append(userNotebooksMap[each.ParentNotebookId].Subs, *each)
|
userNotebooksMap[each.ParentNotebookId].Subs = append(userNotebooksMap[each.ParentNotebookId].Subs, each) // Subs是存地址
|
||||||
// 并剪掉
|
// 并剪掉
|
||||||
delete(userNotebooksMap, id)
|
// bug
|
||||||
|
needDeleteNotebookId[id] = true
|
||||||
|
// delete(userNotebooksMap, id)
|
||||||
} else if noParentDelete {
|
} else if noParentDelete {
|
||||||
// 没有父, 且设置了要删除
|
// 没有父, 且设置了要删除
|
||||||
delete(userNotebooksMap, id)
|
needDeleteNotebookId[id] = true
|
||||||
|
// delete(userNotebooksMap, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第三遍, 得到所有根
|
// 第三遍, 得到所有根
|
||||||
final := make(info.SubNotebooks, len(userNotebooksMap))
|
final := make(info.SubNotebooks, len(userNotebooksMap)-len(needDeleteNotebookId))
|
||||||
i := 0
|
i := 0
|
||||||
for _, each := range userNotebooksMap {
|
for id, each := range userNotebooksMap {
|
||||||
final[i] = *each
|
if !needDeleteNotebookId[id] {
|
||||||
i++
|
final[i] = each
|
||||||
|
i++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 最后排序
|
// 最后排序
|
||||||
@@ -87,6 +96,20 @@ func (this *NotebookService) GetNotebook(notebookId, userId string) info.Noteboo
|
|||||||
db.GetByIdAndUserId(db.Notebooks, notebookId, userId, ¬ebook)
|
db.GetByIdAndUserId(db.Notebooks, notebookId, userId, ¬ebook)
|
||||||
return notebook
|
return notebook
|
||||||
}
|
}
|
||||||
|
func (this *NotebookService) GetNotebookById(notebookId string) info.Notebook {
|
||||||
|
notebook := 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
|
// 得到用户下所有的notebook
|
||||||
// 排序好之后返回
|
// 排序好之后返回
|
||||||
@@ -119,6 +142,7 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
|||||||
// 添加
|
// 添加
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||||
|
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||||
err := db.Notebooks.Insert(notebook)
|
err := db.Notebooks.Insert(notebook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -156,40 +180,59 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin
|
|||||||
// 更新notebook
|
// 更新notebook
|
||||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
|
|
||||||
// 如果有IsBlog之类的, 需要特殊处理
|
|
||||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
|
||||||
// 设为blog/取消
|
|
||||||
if is, ok2 := isBlog.(bool); ok2 {
|
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
|
||||||
db.UpdateByQMap(db.Notes, q, bson.M{"IsBlog": is})
|
|
||||||
|
|
||||||
// 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)
|
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})
|
||||||
|
|
||||||
|
// 更新笔记
|
||||||
|
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新计算tags
|
||||||
|
go (func() {
|
||||||
|
blogService.ReCountBlogTags(userId)
|
||||||
|
})()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看是否有子notebook
|
||||||
// 先查看该notebookId下是否有notes, 没有则删除
|
// 先查看该notebookId下是否有notes, 没有则删除
|
||||||
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
||||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
"UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
|
||||||
"IsTrash": false}) == 0 { // 不包含trash
|
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"IsTrash": false}) == 0 { // 不包含trash
|
||||||
|
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||||
|
}
|
||||||
|
return false, "笔记本下有笔记"
|
||||||
|
} else {
|
||||||
|
return false, "笔记本下有子笔记本"
|
||||||
}
|
}
|
||||||
return false, "笔记本下有笔记"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
@@ -209,3 +252,51 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok := false
|
||||||
|
// 如果没parentNotebookId, 则parentNotebookId设空
|
||||||
|
if(parentNotebookId == "") {
|
||||||
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", "");
|
||||||
|
} else {
|
||||||
|
ok = db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(curNotebookId), userIdO, "ParentNotebookId", bson.ObjectIdHex(parentNotebookId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
for seq, notebookId := range siblings {
|
||||||
|
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), userIdO, "Seq", seq) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新统计笔记本下的笔记数目
|
||||||
|
// noteSevice: AddNote, CopyNote, CopySharedNote, MoveNote
|
||||||
|
// trashService: DeleteNote (recove不用, 都统一在MoveNote里了)
|
||||||
|
func (this *NotebookService) ReCountNotebookNumberNotes(notebookId string) bool {
|
||||||
|
notebookIdO := bson.ObjectIdHex(notebookId)
|
||||||
|
count := db.Count(db.Notes, bson.M{"NotebookId": notebookIdO, "IsTrash": false})
|
||||||
|
Log(count)
|
||||||
|
Log(notebookId)
|
||||||
|
return db.UpdateByQField(db.Notebooks, bson.M{"_id": notebookIdO}, "NumberNotes", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NotebookService) ReCountAll() {
|
||||||
|
/*
|
||||||
|
// 得到所有笔记本
|
||||||
|
notebooks := []info.Notebook{}
|
||||||
|
db.ListByQWithFields(db.Notebooks, bson.M{}, []string{"NotebookId"}, ¬ebooks)
|
||||||
|
|
||||||
|
for _, each := range notebooks {
|
||||||
|
this.ReCountNotebookNumberNotes(each.NotebookId.Hex())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 找回密码
|
// 找回密码
|
||||||
@@ -31,13 +30,7 @@ func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送邮件
|
// 发送邮件
|
||||||
url := "http://leanote.com/findPassword/" + token
|
ok, msg = emailService.FindPwdSendEmail(token, email)
|
||||||
body := fmt.Sprintf("请点击链接修改密码: <a href='%v'>%v</a>. %v小时后过期.", url, url, int(overHours));
|
|
||||||
if !SendEmail(email, "leanote-找回密码", "找回密码", body) {
|
|
||||||
return false, "邮箱发送失败"
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Session存储到mongodb中
|
||||||
|
type SessionService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *SessionService) Update(sessionId, key string, value interface{}) bool {
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
func (this *SessionService) Get(sessionId string) info.Session {
|
||||||
|
session := info.Session{}
|
||||||
|
db.GetByQ(db.Sessions, bson.M{"SessionId": sessionId}, &session)
|
||||||
|
|
||||||
|
// 如果没有session, 那么插入一条之
|
||||||
|
if session.Id == "" {
|
||||||
|
session.Id = bson.NewObjectId()
|
||||||
|
session.SessionId = sessionId
|
||||||
|
session.CreatedTime = time.Now()
|
||||||
|
session.UpdatedTime = session.CreatedTime
|
||||||
|
db.Insert(db.Sessions, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------
|
||||||
|
// 错误次数处理
|
||||||
|
|
||||||
|
// 登录错误时间是否已超过了
|
||||||
|
func (this *SessionService) LoginTimesIsOver(sessionId string) bool {
|
||||||
|
session := this.Get(sessionId)
|
||||||
|
return session.LoginTimes > 5
|
||||||
|
}
|
||||||
|
// 登录成功后清空错误次数
|
||||||
|
func (this *SessionService) ClearLoginTimes(sessionId string) bool {
|
||||||
|
return this.Update(sessionId, "LoginTimes", 0)
|
||||||
|
}
|
||||||
|
// 增加错误次数
|
||||||
|
func (this *SessionService) IncrLoginTimes(sessionId string) bool {
|
||||||
|
session := this.Get(sessionId)
|
||||||
|
return this.Update(sessionId, "LoginTimes", session.LoginTimes + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------
|
||||||
|
// 验证码
|
||||||
|
func (this *SessionService) GetCaptcha(sessionId string) string {
|
||||||
|
session := this.Get(sessionId)
|
||||||
|
return session.Captcha
|
||||||
|
}
|
||||||
|
func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
|
||||||
|
this.Get(sessionId)
|
||||||
|
Log(sessionId)
|
||||||
|
Log(captcha)
|
||||||
|
ok := this.Update(sessionId, "Captcha", captcha)
|
||||||
|
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
|
||||||
|
}
|
||||||
+397
-67
@@ -3,17 +3,23 @@ package service
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"sort"
|
"sort"
|
||||||
|
"math/rand"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 共享Notebook, Note服务
|
// 共享Notebook, Note服务
|
||||||
type ShareService struct {
|
type ShareService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------
|
//-----------------------------------
|
||||||
|
// 返回shareNotebooks, sharedUserInfos
|
||||||
|
// info.ShareNotebooksByUser, []info.User
|
||||||
|
|
||||||
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
||||||
|
|
||||||
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
||||||
@@ -27,23 +33,49 @@ type ShareService struct {
|
|||||||
// 3 每个层按seq进行排序
|
// 3 每个层按seq进行排序
|
||||||
// 4 按用户分组
|
// 4 按用户分组
|
||||||
// [ok]
|
// [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))
|
// 谁共享给了我的Query
|
||||||
for i, each := range hasShareNotes {
|
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||||
userIds[i] = each.UserId
|
// 得到我参与的组织
|
||||||
|
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);
|
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// 得到他们共享给我的notebooks
|
// 得到他们共享给我的notebooks
|
||||||
|
|
||||||
|
// 这里可能会得到重复的记录
|
||||||
|
// 权限: 笔记本分享给个人 > 笔记本分享给组织
|
||||||
shareNotebooks := []info.ShareNotebook{}
|
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 {
|
if len(shareNotebooks) == 0 {
|
||||||
return nil, userInfos
|
return nil, userInfos
|
||||||
@@ -52,12 +84,15 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
shareNotebooksLen := len(shareNotebooks)
|
shareNotebooksLen := len(shareNotebooks)
|
||||||
|
|
||||||
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
||||||
notebookIds := make([]bson.ObjectId, shareNotebooksLen)
|
notebookIds := []bson.ObjectId{}
|
||||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
||||||
for i, each := range shareNotebooks {
|
for _, each := range shareNotebooks {
|
||||||
// 默认的是没有notebookId的
|
// 之后的就不要了, 只留权限高的
|
||||||
notebookIds[i] = each.NotebookId
|
if _, ok := shareNotebooksMap[each.NotebookId]; !ok {
|
||||||
shareNotebooksMap[each.NotebookId] = each
|
// 默认的是没有notebookId的
|
||||||
|
notebookIds = append(notebookIds, each.NotebookId)
|
||||||
|
shareNotebooksMap[each.NotebookId] = each
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1, 2
|
// 1, 2
|
||||||
@@ -127,9 +162,13 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
|
|||||||
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
||||||
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||||
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
||||||
|
q := this.getOrQ(myUserId)
|
||||||
|
q["NotebookId"] = bson.ObjectIdHex(notebookId);
|
||||||
|
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||||
shareNotebook := info.ShareNotebook{}
|
shareNotebook := info.ShareNotebook{}
|
||||||
db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
db.GetByQ(db.ShareNotebooks,
|
||||||
"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
|
q,
|
||||||
|
&shareNotebook)
|
||||||
|
|
||||||
if shareNotebook.NotebookId == "" {
|
if shareNotebook.NotebookId == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -146,7 +185,19 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
|||||||
for i, note := range notes {
|
for i, note := range notes {
|
||||||
noteIds[i] = note.NoteId
|
noteIds[i] = note.NoteId
|
||||||
}
|
}
|
||||||
notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId);
|
// 笔记的权限
|
||||||
|
shareNotes := []info.ShareNote{}
|
||||||
|
delete(q, "NotebookId")
|
||||||
|
q["NoteId"] = bson.M{"$in": noteIds}
|
||||||
|
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限
|
||||||
|
notePerms := map[bson.ObjectId]int{}
|
||||||
|
for _, each := range shareNotes {
|
||||||
|
if _, ok := notePerms[each.NoteId]; !ok {
|
||||||
|
notePerms[each.NoteId] = each.Perm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log("笔记权限")
|
||||||
|
LogJ(notePerms);
|
||||||
|
|
||||||
// 3.2 组合
|
// 3.2 组合
|
||||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
||||||
@@ -162,17 +213,21 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到note的perm信息
|
// 得到note的perm信息
|
||||||
func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||||
shareNotes := []info.ShareNote{}
|
// shareNotes := []info.ShareNote{}
|
||||||
db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
// db.ListByQ(db.ShareNotes,
|
||||||
|
// bson.M{
|
||||||
notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
// "NoteId": bson.M{"$in": noteIds},
|
||||||
for _, each := range shareNotes {
|
// "UserId": bson.ObjectIdHex(sharedUserId),
|
||||||
notesPerm[each.NoteId] = each.Perm
|
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||||
}
|
//
|
||||||
|
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||||
return notesPerm
|
// for _, each := range shareNotes {
|
||||||
}
|
// notesPerm[each.NoteId] = each.Perm
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return notesPerm
|
||||||
|
//}
|
||||||
|
|
||||||
// 得到默认的单个的notes 共享集
|
// 得到默认的单个的notes 共享集
|
||||||
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
||||||
@@ -184,9 +239,12 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
|||||||
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
shareNotes := []info.ShareNote{}
|
shareNotes := []info.ShareNote{}
|
||||||
|
|
||||||
|
q := this.getOrQ(myUserId)
|
||||||
|
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||||
|
|
||||||
db.ShareNotes.
|
db.ShareNotes.
|
||||||
Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
|
Find(q).
|
||||||
// Sort(sortFieldR).
|
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限
|
||||||
Skip(skipNum).
|
Skip(skipNum).
|
||||||
Limit(pageSize).
|
Limit(pageSize).
|
||||||
All(&shareNotes)
|
All(&shareNotes)
|
||||||
@@ -200,15 +258,20 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
|||||||
noteIds[i] = each.NoteId
|
noteIds[i] = each.NoteId
|
||||||
}
|
}
|
||||||
notes := noteService.ListNotesByNoteIds(noteIds)
|
notes := noteService.ListNotesByNoteIds(noteIds)
|
||||||
notesMap := make(map[bson.ObjectId]info.Note, len(notes))
|
notesMap := map[bson.ObjectId]info.Note{}
|
||||||
for _, each := range notes {
|
for _, each := range notes {
|
||||||
notesMap[each.NoteId] = each
|
notesMap[each.NoteId] = each
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将shareNotes与notes结合起来
|
// 将shareNotes与notes结合起来
|
||||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
|
notesWithPerm := []info.ShareNoteWithPerm{}
|
||||||
for i, each := range shareNotes {
|
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的
|
||||||
notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
|
for _, each := range shareNotes {
|
||||||
|
if !hasAdded[each.NoteId] {
|
||||||
|
// 待优化
|
||||||
|
notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm})
|
||||||
|
hasAdded[each.NoteId] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return notesWithPerm
|
return notesWithPerm
|
||||||
}
|
}
|
||||||
@@ -277,36 +340,36 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
|||||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||||
UserId: bson.ObjectIdHex(userId),
|
UserId: bson.ObjectIdHex(userId),
|
||||||
ToUserId: bson.ObjectIdHex(toUserId),
|
ToUserId: bson.ObjectIdHex(toUserId),
|
||||||
Perm: perm,
|
Perm: perm,
|
||||||
CreatedTime: time.Now(),
|
CreatedTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
// updatedUserId是否有修改userId noteId的权限?
|
|
||||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
// updatedUserId是否有查看userId noteId的权限?
|
||||||
// 1. noteId是否被共享了?
|
// userId是所有者
|
||||||
// 得到该note share的信息
|
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
||||||
/*
|
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||||
NoteId bson.ObjectId `bson:"NoteId"`
|
if !db.Has(db.ShareNotes, q) {
|
||||||
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是否被共享了?
|
// noteId的notebookId是否被共享了?
|
||||||
notebookId := noteService.GetNotebookId(noteId)
|
notebookId := noteService.GetNotebookId(noteId)
|
||||||
if notebookId.Hex() == "" {
|
if notebookId.Hex() == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(q, "NoteId")
|
||||||
|
q["NotebookId"] = notebookId
|
||||||
|
|
||||||
// 判断notebook是否被共享
|
// 判断notebook是否被共享
|
||||||
if !db.Has(db.ShareNotebooks,
|
if !db.Has(db.ShareNotebooks, q) {
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) {
|
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
@@ -316,15 +379,46 @@ func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updatedUserId是否有修改userId noteId的权限?
|
||||||
|
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||||
|
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的权限?
|
// updatedUserId是否有修改userId notebookId的权限?
|
||||||
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
||||||
// 判断notebook是否被共享
|
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||||
if !db.Has(db.ShareNotebooks,
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
|
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||||
return false
|
shares2 := []info.ShareNotebook{}
|
||||||
} else {
|
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||||
return true
|
for _, share := range shares2 {
|
||||||
}
|
return share.Perm == 1 // 第1个权限最大
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 共享note, notebook时使用
|
// 共享note, notebook时使用
|
||||||
@@ -334,14 +428,14 @@ func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// userId是否被共享了noteId
|
// userId是否被共享了noteId
|
||||||
func (this *ShareService) hasSharedNote(noteId, myUserId string) bool {
|
func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
|
||||||
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
|
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
|
||||||
}
|
}
|
||||||
// noteId的notebook是否共享了给我
|
// noteId的notebook是否共享了给我
|
||||||
func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
|
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
|
||||||
note := noteService.GetNote(noteId, sharedUserId)
|
notebookId := noteService.GetNotebookId(noteId)
|
||||||
if note.NoteId != "" {
|
if notebookId != "" {
|
||||||
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": note.NotebookId,
|
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": notebookId,
|
||||||
"UserId": bson.ObjectIdHex(sharedUserId),
|
"UserId": bson.ObjectIdHex(sharedUserId),
|
||||||
"ToUserId": bson.ObjectIdHex(myUserId),
|
"ToUserId": bson.ObjectIdHex(myUserId),
|
||||||
})
|
})
|
||||||
@@ -350,12 +444,16 @@ func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到共享的笔记内容
|
// 得到共享的笔记内容
|
||||||
// 首先要判断这个note是否我被共享了
|
// 并返回笔记的权限!!!
|
||||||
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
||||||
noteContent = info.NoteContent{}
|
noteContent = info.NoteContent{}
|
||||||
// 是否单独共享了该notebook
|
// 是否单独共享了该notebook
|
||||||
// 或者, 其notebook共享了我
|
// 或者, 其notebook共享了我
|
||||||
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)
|
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
@@ -369,7 +467,15 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
|||||||
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
||||||
// 得到shareNote信息, 得到所有的ToUserId
|
// 得到shareNote信息, 得到所有的ToUserId
|
||||||
shareNotes := []info.ShareNote{}
|
shareNotes := []info.ShareNote{}
|
||||||
db.ListByQLimit(db.ShareNotes, 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 {
|
if len(shareNotes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -428,7 +534,11 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
|
|||||||
shareNotebooks := []info.ShareNotebook{}
|
shareNotebooks := []info.ShareNotebook{}
|
||||||
|
|
||||||
db.ListByQLimit(db.ShareNotebooks,
|
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)
|
&shareNotebooks, 100)
|
||||||
|
|
||||||
if len(shareNotebooks) == 0 {
|
if len(shareNotebooks) == 0 {
|
||||||
@@ -508,3 +618,223 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户userId是否有修改noteId的权限
|
||||||
|
func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
|
||||||
|
if noteId == "" || userId == "" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
LogJ(note);
|
||||||
|
if note.UserId != "" {
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
if noteUserId != userId {
|
||||||
|
// 是否是有权限协作的
|
||||||
|
if this.HasUpdatePerm(noteUserId, userId, noteId) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户userId是否有查看noteId的权限
|
||||||
|
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
||||||
|
if noteId == "" || userId == "" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.UserId != "" {
|
||||||
|
noteUserId := note.UserId.Hex()
|
||||||
|
if noteUserId != userId {
|
||||||
|
// 是否是有权限协作的
|
||||||
|
if this.HasReadPerm(noteUserId, userId, noteId) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "time"
|
// "time"
|
||||||
// "sort"
|
// "sort"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "time"
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
)
|
)
|
||||||
@@ -28,7 +28,13 @@ func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
|||||||
// 首先删除其共享
|
// 首先删除其共享
|
||||||
if shareService.DeleteShareNoteAll(noteId, userId) {
|
if shareService.DeleteShareNoteAll(noteId, userId) {
|
||||||
// 更新note isTrash = true
|
// 更新note isTrash = true
|
||||||
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}})
|
if db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}}) {
|
||||||
|
// recount notebooks' notes number
|
||||||
|
notebookIdO := noteService.GetNotebookId(noteId)
|
||||||
|
notebookId := notebookIdO.Hex()
|
||||||
|
notebookService.ReCountNotebookNumberNotes(notebookId)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -53,7 +59,15 @@ func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
|||||||
|
|
||||||
// 删除trash
|
// 删除trash
|
||||||
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
||||||
return db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
// delete note's attachs
|
||||||
|
ok := attachService.DeleteAllAttachs(noteId, userId)
|
||||||
|
|
||||||
|
// delete note
|
||||||
|
ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
||||||
|
// delete content
|
||||||
|
ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
|
||||||
|
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列出note, 排序规则, 还有分页
|
// 列出note, 排序规则, 还有分页
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
// "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type UpgradeService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加了PublicTime, RecommendTime
|
||||||
|
func (this *UpgradeService) UpgradeBlog() bool {
|
||||||
|
notes := []info.Note{}
|
||||||
|
db.ListByQ(db.Notes, bson.M{"IsBlog": true}, ¬es)
|
||||||
|
|
||||||
|
// PublicTime, RecommendTime = UpdatedTime
|
||||||
|
for _, note := range notes {
|
||||||
|
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
|
||||||
|
}
|
||||||
+222
-63
@@ -4,16 +4,14 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
"strings"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserService struct {
|
type UserService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 添加用户
|
// 添加用户
|
||||||
func (this *UserService) AddUser(user info.User) bool {
|
func (this *UserService) AddUser(user info.User) bool {
|
||||||
if user.UserId == "" {
|
if user.UserId == "" {
|
||||||
@@ -26,7 +24,9 @@ func (this *UserService) AddUser(user info.User) bool {
|
|||||||
|
|
||||||
// 发送验证邮箱
|
// 发送验证邮箱
|
||||||
go func() {
|
go func() {
|
||||||
this.RegisterSendActiveEmail(user.UserId.Hex(), user.Email)
|
emailService.RegisterSendActiveEmail(user, user.Email)
|
||||||
|
// 发送给我 life@leanote.com
|
||||||
|
emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,20 @@ func (this *UserService) GetUserId(email string) string {
|
|||||||
return user.UserId.Hex()
|
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
|
// 是否存在该用户 email
|
||||||
func (this *UserService) IsExistsUser(email string) bool {
|
func (this *UserService) IsExistsUser(email string) bool {
|
||||||
if this.GetUserId(email) == "" {
|
if this.GetUserId(email) == "" {
|
||||||
@@ -64,13 +78,27 @@ func (this *UserService) GetUserInfoByAny(idEmailUsername string) info.User {
|
|||||||
return this.GetUserInfoByEmail(idEmailUsername)
|
return this.GetUserInfoByEmail(idEmailUsername)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// username
|
||||||
return this.GetUserInfoByUsername(idEmailUsername)
|
return this.GetUserInfoByUsername(idEmailUsername)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *UserService) setUserLogo(user *info.User) {
|
||||||
|
// Logo路径问题, 有些有http: 有些没有
|
||||||
|
if user.Logo == "" {
|
||||||
|
user.Logo = "images/blog/default_avatar.png"
|
||||||
|
}
|
||||||
|
if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") {
|
||||||
|
user.Logo = strings.Trim(user.Logo, "/")
|
||||||
|
user.Logo = configService.GetSiteUrl() + "/" + user.Logo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 得到用户信息 userId
|
// 得到用户信息 userId
|
||||||
func (this *UserService) GetUserInfo(userId string) info.User {
|
func (this *UserService) GetUserInfo(userId string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
db.Get(db.Users, userId, &user)
|
db.Get(db.Users, userId, &user)
|
||||||
|
// Logo路径问题, 有些有http: 有些没有
|
||||||
|
this.setUserLogo(&user)
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
// 得到用户信息 email
|
// 得到用户信息 email
|
||||||
@@ -82,6 +110,7 @@ func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
|||||||
// 得到用户信息 username
|
// 得到用户信息 username
|
||||||
func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
||||||
user := info.User{}
|
user := info.User{}
|
||||||
|
username = strings.ToLower(username)
|
||||||
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
@@ -96,6 +125,79 @@ func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.
|
|||||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
func (this *UserService) ListUserInfosByEmails(emails []string) []info.User {
|
||||||
|
users := []info.User{}
|
||||||
|
db.ListByQ(db.Users, bson.M{"Email": bson.M{"$in": emails}}, &users)
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
// 用户信息即可
|
||||||
|
func (this *UserService) MapUserInfoByUserIds(userIds []bson.ObjectId) map[bson.ObjectId]info.User {
|
||||||
|
users := []info.User{}
|
||||||
|
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||||
|
|
||||||
|
userMap := make(map[bson.ObjectId]info.User, len(users))
|
||||||
|
for _, user := range users {
|
||||||
|
this.setUserLogo(&user)
|
||||||
|
userMap[user.UserId] = user
|
||||||
|
}
|
||||||
|
return userMap
|
||||||
|
}
|
||||||
|
// 用户信息和博客设置信息
|
||||||
|
func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectId) map[bson.ObjectId]info.User {
|
||||||
|
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
|
// 通过ids得到users, 按id的顺序组织users
|
||||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||||
@@ -107,9 +209,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
|||||||
usersMap[user.UserId] = user
|
usersMap[user.UserId] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的
|
||||||
users2 := []info.User{};
|
users2 := []info.User{};
|
||||||
for _, userId := range userIds {
|
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)
|
users2 = append(users2, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,8 +236,8 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
|||||||
|
|
||||||
// 更新username
|
// 更新username
|
||||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||||
if userId == "" || username == "" {
|
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||||
return false, "用户已存在"
|
return false, "usernameIsExisted"
|
||||||
}
|
}
|
||||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
@@ -141,84 +245,63 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
|||||||
// 先判断是否存在
|
// 先判断是否存在
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
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})
|
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
||||||
return ok, ""
|
return ok, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改头像
|
||||||
|
func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
return db.UpdateByQField(db.Users, bson.M{"_id": userIdO}, "Logo", avatarPath)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
// 已经登录了的用户修改密码
|
// 已经登录了的用户修改密码
|
||||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||||
userInfo := this.GetUserInfo(userId)
|
userInfo := this.GetUserInfo(userId)
|
||||||
if userInfo.Pwd != Md5(oldPwd) {
|
if userInfo.Pwd != Md5(oldPwd) {
|
||||||
return false, "旧密码错误"
|
return false, "oldPasswordError"
|
||||||
}
|
}
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
return ok, ""
|
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) {
|
func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
||||||
return ok
|
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
|
// 修改email
|
||||||
|
|
||||||
// 发送激活邮件
|
|
||||||
|
|
||||||
// AddUser调用
|
|
||||||
// 可以使用一个goroutine
|
|
||||||
func (this *UserService) RegisterSendActiveEmail(userId string, email string) bool {
|
|
||||||
token := tokenService.NewToken(userId, email, info.TokenActiveEmail)
|
|
||||||
|
|
||||||
if token == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送邮件
|
|
||||||
url := "http://leanote.com/user/activeEmail?token=" + token
|
|
||||||
body := fmt.Sprintf("请点击链接验证邮箱: <a href='%v'>%v</a>. %v小时后过期.", url, url, tokenService.GetOverHours(info.TokenActiveEmail));
|
|
||||||
if !SendEmail(email, "leanote-验证邮箱", "验证邮箱", body) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送给我 life@leanote.com
|
|
||||||
SendEmail("life@leanote.com", "新增用户", "新增用户", "用户名" + email);
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改邮箱
|
|
||||||
func (this *UserService) UpdateEmailSendActiveEmail(userId, email string) (ok bool, msg string) {
|
|
||||||
// 先验证该email是否被注册了
|
|
||||||
if userService.IsExistsUser(email) {
|
|
||||||
ok = false
|
|
||||||
msg = "该邮箱已注册"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token := tokenService.NewToken(userId, email, info.TokenUpdateEmail)
|
|
||||||
|
|
||||||
if token == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送邮件
|
|
||||||
url := "http://leanote.com/user/updateEmail?token=" + token
|
|
||||||
body := "邮箱验证后您的登录邮箱为: <b>" + email + "</b><br />";
|
|
||||||
body += fmt.Sprintf("请点击链接验证邮箱: <a href='%v'>%v</a>. %v小时后过期.", url, url, tokenService.GetOverHours(info.TokenUpdateEmail));
|
|
||||||
if !SendEmail(email, "leanote-验证邮箱", "验证邮箱", body) {
|
|
||||||
msg = "发送失败, 该邮箱存在?"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册后验证邮箱
|
// 注册后验证邮箱
|
||||||
func (this *UserService) ActiveEmail(token string) (ok bool, msg, email string) {
|
func (this *UserService) ActiveEmail(token string) (ok bool, msg, email string) {
|
||||||
tokenInfo := info.Token{}
|
tokenInfo := info.Token{}
|
||||||
@@ -270,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) {
|
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
||||||
|
// 判断该用户是否已有了帐户
|
||||||
|
userInfo := this.GetUserInfo(userId)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
msg = "你已有帐户"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 判断email是否存在
|
// 判断email是否存在
|
||||||
if this.IsExistsUser(email) {
|
if this.IsExistsUser(email) {
|
||||||
msg = "该用户已存在"
|
msg = "该用户已存在"
|
||||||
@@ -280,15 +370,84 @@ func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
// 偏好设置
|
// 偏好设置
|
||||||
|
|
||||||
// 宽度
|
// 宽度
|
||||||
func (this *UserService)UpdateColumnWidth(userId string, notebookWidth, noteListWidth int) bool {
|
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})
|
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||||
|
bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth, "MdEditorWidth": mdEditorWidth})
|
||||||
}
|
}
|
||||||
// 左侧是否隐藏
|
// 左侧是否隐藏
|
||||||
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
|
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
|
||||||
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"LeftIsMin": leftIsMin})
|
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"LeftIsMin": leftIsMin})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------
|
||||||
|
// user admin
|
||||||
|
func (this *UserService) ListUsers(pageNumber, pageSize int, sortField string, isAsc bool, email string) (page info.Page, users []info.User) {
|
||||||
|
users = []info.User{}
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
query := bson.M{}
|
||||||
|
if email != "" {
|
||||||
|
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);
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
// 列表
|
||||||
|
q.Sort(sortFieldR).
|
||||||
|
Skip(skipNum).
|
||||||
|
Limit(pageSize).
|
||||||
|
All(&users)
|
||||||
|
page = info.NewPage(pageNumber, pageSize, count, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UserService) GetAllUserByFilter(userFilterEmail, userFilterWhiteList, userFilterBlackList string, verified bool) []info.User {
|
||||||
|
query := bson.M{}
|
||||||
|
|
||||||
|
if verified {
|
||||||
|
query["Verified"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
orQ := []bson.M{}
|
||||||
|
if userFilterEmail != "" {
|
||||||
|
orQ = append(orQ, bson.M{"Email": bson.M{"$regex": bson.RegEx{".*?" + userFilterEmail + ".*", "i"}}},
|
||||||
|
bson.M{"Username": bson.M{"$regex": bson.RegEx{".*?" + userFilterEmail + ".*", "i"}}},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(userFilterWhiteList != "") {
|
||||||
|
userFilterWhiteList = strings.Replace(userFilterWhiteList, "\r", "", -1)
|
||||||
|
emails := strings.Split(userFilterWhiteList, "\n");
|
||||||
|
orQ = append(orQ, bson.M{"Email": bson.M{"$in": emails}})
|
||||||
|
}
|
||||||
|
if len(orQ) > 0 {
|
||||||
|
query["$or"] = orQ
|
||||||
|
}
|
||||||
|
|
||||||
|
emailQ := bson.M{}
|
||||||
|
if(userFilterBlackList != "") {
|
||||||
|
userFilterWhiteList = strings.Replace(userFilterBlackList, "\r", "", -1)
|
||||||
|
bEmails := strings.Split(userFilterBlackList, "\n");
|
||||||
|
emailQ["$nin"] = bEmails
|
||||||
|
query["Email"] = emailQ
|
||||||
|
}
|
||||||
|
|
||||||
|
LogJ(query)
|
||||||
|
users := []info.User{}
|
||||||
|
q := db.Users.Find(query);
|
||||||
|
q.All(&users)
|
||||||
|
Log(len(users))
|
||||||
|
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计
|
||||||
|
func (this *UserService) CountUser() int {
|
||||||
|
return db.Count(db.Users, bson.M{})
|
||||||
|
}
|
||||||
+139
-20
@@ -1,31 +1,150 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"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
|
// init service, for share service bettween services
|
||||||
// 初始化, 实例service
|
// 初始化, 实例service
|
||||||
// 为了共享service
|
// 为了共享service
|
||||||
|
|
||||||
var notebookService *NotebookService
|
var notebookService, NotebookS *NotebookService
|
||||||
var noteService *NoteService
|
var noteService, NoteS *NoteService
|
||||||
var noteContentHistoryService *NoteContentHistoryService
|
var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService
|
||||||
var trashService *TrashService
|
var trashService, TrashS *TrashService
|
||||||
var shareService *ShareService
|
var shareService, ShareS *ShareService
|
||||||
var userService *UserService
|
var userService, UserS *UserService
|
||||||
var tagService *TagService
|
var groupService, GroupS *GroupService
|
||||||
var blogService *BlogService
|
var tagService, TagS *TagService
|
||||||
var tokenService *TokenService
|
var blogService, BlogS *BlogService
|
||||||
|
var tokenService, TokenS *TokenService
|
||||||
|
var noteImageService, NoteImageS *NoteImageService
|
||||||
|
var fileService, FileS *FileService
|
||||||
|
var albumService, AlbumS *AlbumService
|
||||||
|
var attachService, AttachS *AttachService
|
||||||
|
var configService, ConfigS *ConfigService
|
||||||
|
var PwdS *PwdService
|
||||||
|
var SuggestionS *SuggestionService
|
||||||
|
var emailService, EmailS *EmailService
|
||||||
|
var AuthS *AuthService
|
||||||
|
var UpgradeS *UpgradeService
|
||||||
|
var SessionS, sessionService *SessionService
|
||||||
|
var ThemeS, themeService *ThemeService
|
||||||
|
|
||||||
func init() {
|
// onAppStart调用
|
||||||
notebookService = &NotebookService{}
|
func InitService() {
|
||||||
noteService = &NoteService{}
|
NotebookS = &NotebookService{}
|
||||||
noteContentHistoryService = &NoteContentHistoryService{}
|
NoteS = &NoteService{}
|
||||||
trashService = &TrashService{}
|
NoteContentHistoryS = &NoteContentHistoryService{}
|
||||||
shareService = &ShareService{}
|
TrashS = &TrashService{}
|
||||||
userService = &UserService{}
|
ShareS = &ShareService{}
|
||||||
tagService = &TagService{}
|
UserS = &UserService{}
|
||||||
blogService = &BlogService{}
|
GroupS = &GroupService{}
|
||||||
tokenService = &TokenService{}
|
TagS = &TagService{}
|
||||||
|
BlogS = &BlogService{}
|
||||||
|
TokenS = &TokenService{}
|
||||||
|
NoteImageS = &NoteImageService{}
|
||||||
|
FileS = &FileService{}
|
||||||
|
AlbumS = &AlbumService{}
|
||||||
|
AttachS = &AttachService{}
|
||||||
|
ConfigS = &ConfigService{}
|
||||||
|
PwdS = &PwdService{}
|
||||||
|
SuggestionS = &SuggestionService{}
|
||||||
|
AuthS = &AuthService{}
|
||||||
|
EmailS = NewEmailService()
|
||||||
|
UpgradeS = &UpgradeService{}
|
||||||
|
SessionS = &SessionService{}
|
||||||
|
ThemeS = &ThemeService{}
|
||||||
|
|
||||||
|
notebookService = NotebookS
|
||||||
|
noteService = NoteS
|
||||||
|
noteContentHistoryService = NoteContentHistoryS
|
||||||
|
trashService = TrashS
|
||||||
|
shareService = ShareS
|
||||||
|
userService = UserS
|
||||||
|
groupService = GroupS
|
||||||
|
tagService = TagS
|
||||||
|
blogService = BlogS
|
||||||
|
tokenService = TokenS
|
||||||
|
noteImageService = NoteImageS
|
||||||
|
fileService = FileS
|
||||||
|
albumService = AlbumS
|
||||||
|
attachService = AttachS
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
Loaded 100 of 2701 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user