Compare commits
140
Commits
0.2
...
feature-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c26d25deab | ||
|
|
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 | ||
|
|
910b079c55 | ||
|
|
b1b36cec23 | ||
|
|
8eab8c7310 | ||
|
|
ddd0c13d34 |
No files matched your search
@@ -15,3 +15,6 @@ app/routes/routes.go
|
|||||||
app/tmp/main.go
|
app/tmp/main.go
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.settings
|
.settings
|
||||||
|
.project
|
||||||
|
public/config.codekit
|
||||||
|
files
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<projectDescription>
|
<projectDescription>
|
||||||
<name>leanote-public</name>
|
<name>leanote2</name>
|
||||||
<comment>leanote, your own cloud note!</comment>
|
<comment>leanote, your own cloud note!</comment>
|
||||||
<projects>
|
<projects>
|
||||||
</projects>
|
</projects>
|
||||||
|
|||||||
@@ -1,4 +1,24 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
leanote - you own cloud note!
|
||||||
|
|
||||||
|
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
|
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/>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
[中文](https://github.com/leanote/leanote#1-介绍)
|
||||||
|
|
||||||
## 1. Introduction
|
## 1. Introduction
|
||||||
|
|
||||||
Leanote, your own cloud note.
|
Leanote, note just a notebook!
|
||||||
|
|
||||||
**Some Features**
|
**Some Features**
|
||||||
|
|
||||||
@@ -20,10 +22,10 @@ To be honest, our inspiration comes from Evernote. We use Evernote to manage our
|
|||||||
|
|
||||||
### 3.1. Download leanote
|
### 3.1. Download leanote
|
||||||
|
|
||||||
Leanote v0.1 has been released. Binaries:
|
Leanote V1.0-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.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
|
||||||
* MacOS X: [leanote-mac-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.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
|
||||||
|
|
||||||
### 3.2. Install MongoDB
|
### 3.2. Install MongoDB
|
||||||
|
|
||||||
@@ -42,8 +44,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 +62,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 +78,117 @@ $> 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
|
|
||||||
|
|
||||||
```
|
|
||||||
$> go get github.com/leanote/leanote/app
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 1. 介绍
|
||||||
|
|
||||||
|
Leanote, 不只是笔记!
|
||||||
|
|
||||||
|
**特性**
|
||||||
|
|
||||||
|
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||||
|
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||||
|
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||||
|
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||||
|
|
||||||
|
## 2. 为什么我们要创建leanote?
|
||||||
|
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||||
|
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||||
|
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||||
|
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||||
|
* 还有...
|
||||||
|
|
||||||
|
## 3.安装leanote
|
||||||
|
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||||
|
|
||||||
|
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||||
|
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||||
|
|
||||||
|
### 3.1. 下载leanote
|
||||||
|
|
||||||
|
Leanote V1.0-beta 已发布, 二进制文件(暂时没有windows版的):
|
||||||
|
|
||||||
|
* Linux: [leanote-linux-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-linux-x86_64.v1.0-beta.bin.tar.gz)
|
||||||
|
* MacOS X: [leanote-mac-x86_64.v1.0-beta.bin.tar.gz](https://github.com/leanote/leanote/releases/download/1.0-beta/leanote-mac-x86_64.v1.0-beta.bin.tar.gz)
|
||||||
|
|
||||||
|
### 3.2. 安装 MongodbDB
|
||||||
|
|
||||||
|
Leanote是由golang(使用[revel](https://revel.github.io/)框架 和 [MongoDB](https://www.mongodb.org)数据库), 你需要先安装Mongodb.
|
||||||
|
|
||||||
|
安装MongodbDB, 导入数据更多细节请查看: [wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||||
|
|
||||||
|
### 3.3. 导入初始数据
|
||||||
|
|
||||||
|
MongodbDB初始数据在 `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||||
|
|
||||||
|
```
|
||||||
|
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||||
|
```
|
||||||
|
|
||||||
|
初始数据包含两个用户:
|
||||||
|
|
||||||
|
```
|
||||||
|
user2 username: admin, password: abc123 (管理员, 重要!)
|
||||||
|
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4. 配置
|
||||||
|
|
||||||
|
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||||
|
|
||||||
|
``mongodb`` **必须配置!**
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
db.host=localhost
|
||||||
|
db.port=27017
|
||||||
|
db.dbname=leanote
|
||||||
|
db.username=
|
||||||
|
db.password=
|
||||||
|
```
|
||||||
|
|
||||||
|
``app.secret`` **重要**
|
||||||
|
请随意修改一个, app的密钥, 不能使用默认的, 不然会有安全问题
|
||||||
|
|
||||||
|
更多配置请查看 `app/app.conf` 和 [revel 手册](https://revel.github.io/)
|
||||||
|
|
||||||
|
### 3.5. 运行leanote
|
||||||
|
|
||||||
|
```
|
||||||
|
$> cd PATH_TO_LEANOTE/bin
|
||||||
|
$> sudo sh run.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 如何对leanote进行二次开发
|
||||||
|
|
||||||
|
请查看 [How-to-develop-leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91leanote)
|
||||||
|
|
||||||
|
## 5. 贡献者
|
||||||
|
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
||||||
|
|
||||||
|
## 6. 加入我们
|
||||||
|
|
||||||
|
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
||||||
|
|
||||||
|
leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
||||||
|
|
||||||
|
## 讨论
|
||||||
|
* [leanote 社区](http://bbs.leanote.com)
|
||||||
|
* QQ群: 158716820
|
||||||
|
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
@@ -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,210 @@
|
|||||||
|
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"
|
||||||
|
"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?
|
||||||
|
if(len(data) > 5 * 1024 * 1024) {
|
||||||
|
resultMsg = "File is bigger than 5M"
|
||||||
|
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 = attachService.AddAttach(fileInfo)
|
||||||
|
|
||||||
|
fileInfo.Path = ""; // 不要返回
|
||||||
|
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 string) revel.Result {
|
||||||
|
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
|
||||||
|
path := attach.Path
|
||||||
|
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,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 用户登录/注销/找回密码
|
// 用户登录/注销/找回密码
|
||||||
@@ -14,11 +15,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,62 +35,85 @@ 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 = ""
|
||||||
|
|
||||||
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 string) revel.Result {
|
||||||
if !openRegister {
|
if !configService.IsOpenRegister() {
|
||||||
return c.Redirect("/index")
|
return c.Redirect("/index")
|
||||||
}
|
}
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["from"] = from
|
||||||
|
|
||||||
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 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
@@ -89,10 +121,10 @@ func (c Auth) DoRegister(email, pwd string) revel.Result {
|
|||||||
|
|
||||||
// 注册成功, 则立即登录之
|
// 注册成功, 则立即登录之
|
||||||
if re.Ok {
|
if re.Ok {
|
||||||
c.DoLogin(email, pwd)
|
c.doLogin(email, pwd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderRe(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
@@ -130,12 +162,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,6 +183,13 @@ func (c BaseController) SetLocale() {
|
|||||||
lang = "en";
|
lang = "en";
|
||||||
}
|
}
|
||||||
c.RenderArgs["locale"] = lang;
|
c.RenderArgs["locale"] = lang;
|
||||||
|
c.RenderArgs["siteUrl"] = siteUrl;
|
||||||
|
|
||||||
|
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||||
|
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||||
|
c.RenderArgs["noteUrl"] = configService.GetNoteUrl()
|
||||||
|
|
||||||
|
return lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置userInfo
|
// 设置userInfo
|
||||||
@@ -172,3 +197,46 @@ func (c BaseController) SetUserInfo() {
|
|||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = 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 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
+375
-106
@@ -1,10 +1,12 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// . "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"
|
||||||
@@ -17,143 +19,283 @@ type Blog struct {
|
|||||||
BaseController
|
BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------
|
|
||||||
// 后台 note<->blog
|
|
||||||
|
|
||||||
// 设置/取消Blog; 置顶
|
|
||||||
func (c Blog) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
|
||||||
if isTop {
|
|
||||||
isBlog = true
|
|
||||||
}
|
|
||||||
if !isBlog {
|
|
||||||
isTop = false
|
|
||||||
}
|
|
||||||
noteUpdate := bson.M{"IsBlog": isBlog, "IsTop": isTop}
|
|
||||||
re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(),
|
|
||||||
noteId, noteUpdate)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置notebook <-> blog
|
|
||||||
func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
|
||||||
noteUpdate := bson.M{"IsBlog": isBlog}
|
|
||||||
re := notebookService.UpdateNotebook(c.GetUserId(),
|
|
||||||
notebookId, noteUpdate)
|
|
||||||
return c.RenderJson(re)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
// 前台
|
// 前台
|
||||||
|
|
||||||
// 默认是admin用户的博客
|
// 域名, 没用
|
||||||
// 列表
|
func (c Blog) domain() (ok bool, userBlog info.UserBlog) {
|
||||||
// 这里还需要得到其它博客配置信息...
|
return
|
||||||
// 配置信息可以放在users表中, 或添加一个user_options表(用户配置表)
|
}
|
||||||
var blogPageSize = 5
|
|
||||||
var searchBlogPageSize = 30
|
// 各种地址设置
|
||||||
func (c Blog) Index(userId string, notebookId string) revel.Result {
|
func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
|
||||||
if userId == "" {
|
// 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com
|
||||||
userId = leanoteUserId
|
var indexUrl, viewUrl, searchUrl, cateUrl, aboutMeUrl, staticUrl string
|
||||||
|
host := c.Request.Request.Host
|
||||||
|
staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
|
||||||
|
// staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com
|
||||||
|
// life.leanote.com, lealife.com
|
||||||
|
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||||
|
// ok
|
||||||
|
indexUrl = configService.GetUserUrl(userBlog.Domain)
|
||||||
|
cateUrl = indexUrl + "/cate" // /xxxxx
|
||||||
|
viewUrl = indexUrl + "/view" // /xxxxx
|
||||||
|
searchUrl = indexUrl + "/search" // /xxxxx
|
||||||
|
aboutMeUrl = indexUrl + "/aboutMe"
|
||||||
|
} else if userBlog.SubDomain != "" {
|
||||||
|
indexUrl = configService.GetUserSubUrl(userBlog.SubDomain)
|
||||||
|
cateUrl = indexUrl + "/cate" // /xxxxx
|
||||||
|
viewUrl = indexUrl + "/view" // /xxxxx
|
||||||
|
searchUrl = indexUrl + "/search" // /xxxxx
|
||||||
|
aboutMeUrl = indexUrl + "/aboutMe"
|
||||||
|
} else {
|
||||||
|
// ok
|
||||||
|
blogUrl := configService.GetBlogUrl()
|
||||||
|
userIdOrEmail := ""
|
||||||
|
if userInfo.Username != "" {
|
||||||
|
userIdOrEmail = userInfo.Username
|
||||||
|
} else if userInfo.Email != "" {
|
||||||
|
userIdOrEmail = userInfo.Email
|
||||||
|
} else {
|
||||||
|
userIdOrEmail = userInfo.UserId.Hex()
|
||||||
|
}
|
||||||
|
indexUrl = blogUrl + "/" + userIdOrEmail
|
||||||
|
cateUrl = blogUrl + "/cate" // /notebookId
|
||||||
|
viewUrl = blogUrl + "/view" // /xxxxx
|
||||||
|
searchUrl = blogUrl + "/search/" + userIdOrEmail // /xxxxx
|
||||||
|
aboutMeUrl = blogUrl + "/aboutMe/" + userIdOrEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
// userId可能是 username, email
|
// 分类
|
||||||
userInfo := userService.GetUserInfoByAny(userId)
|
// 搜索
|
||||||
|
// 查看
|
||||||
|
c.RenderArgs["indexUrl"] = indexUrl
|
||||||
|
c.RenderArgs["cateUrl"] = cateUrl
|
||||||
|
c.RenderArgs["viewUrl"] = viewUrl
|
||||||
|
c.RenderArgs["searchUrl"] = searchUrl
|
||||||
|
c.RenderArgs["aboutMeUrl"] = aboutMeUrl
|
||||||
|
c.RenderArgs["staticUrl"] = staticUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共
|
||||||
|
func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.User) (ok bool) {
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
return c.E404()
|
userInfo = userService.GetUserInfoByAny(userId)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userId = userInfo.UserId.Hex()
|
|
||||||
c.isMe(userId)
|
|
||||||
|
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
|
// 分类导航
|
||||||
|
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||||
|
// 最新笔记
|
||||||
|
c.getRecentBlogs(userId)
|
||||||
|
// 语言, url地址
|
||||||
|
c.SetLocale();
|
||||||
|
c.RenderArgs["isMe"] = userId == c.GetUserId()
|
||||||
|
|
||||||
// 得到博客设置信息
|
// 得到博客设置信息
|
||||||
userBlog := blogService.GetUserBlog(userId)
|
if userBlog.UserId == "" {
|
||||||
|
userBlog = blogService.GetUserBlog(userId)
|
||||||
|
}
|
||||||
c.RenderArgs["userBlog"] = userBlog
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
c.setUrl(userBlog, userInfo)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跨域判断是否是我的博客
|
||||||
|
func (c Blog) IsMe(userId string) revel.Result {
|
||||||
|
var js = ""
|
||||||
|
if c.GetUserId() == userId {
|
||||||
|
js = "$('.is-me').removeClass('hide');"
|
||||||
|
}
|
||||||
|
return c.RenderText(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进入某个用户的博客
|
||||||
|
var blogPageSize = 5
|
||||||
|
var searchBlogPageSize = 30
|
||||||
|
|
||||||
|
// 分类 /cate/xxxxxxxx?notebookId=1212
|
||||||
|
func (c Blog) Cate(notebookId string) revel.Result {
|
||||||
|
if notebookId == "" {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
var notebook info.Notebook
|
var notebook info.Notebook
|
||||||
if notebookId != "" {
|
notebook = notebookService.GetNotebookById(notebookId)
|
||||||
notebook = notebookService.GetNotebook(notebookId, userId)
|
|
||||||
if !notebook.IsBlog {
|
if !notebook.IsBlog {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
|
if userId != "" && userId != notebook.UserId.Hex() {
|
||||||
c.RenderArgs["title"] = userBlog.Title + " - 分类: " + notebook.Title
|
return c.E404()
|
||||||
} else {
|
|
||||||
c.RenderArgs["title"] = userBlog.Title
|
|
||||||
}
|
}
|
||||||
|
userId = notebook.UserId.Hex()
|
||||||
|
|
||||||
|
if !c.blogCommon(userId, userBlog, info.User{}) {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
|
||||||
// 分页的话, 需要分页信息, totalPage, curPage
|
// 分页的话, 需要分页信息, totalPage, curPage
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
count, blogs := blogService.ListBlogs(userId, notebookId, page, blogPageSize, "UpdatedTime", false)
|
count, blogs := blogService.ListBlogs(userId, notebookId, page, blogPageSize, "PublicTime", false)
|
||||||
|
|
||||||
|
c.RenderArgs["notebookId"] = notebookId
|
||||||
|
c.RenderArgs["notebook"] = notebook
|
||||||
|
c.RenderArgs["title"] = c.Message("blogClass") + " - " + notebook.Title
|
||||||
c.RenderArgs["blogs"] = blogs
|
c.RenderArgs["blogs"] = blogs
|
||||||
c.RenderArgs["page"] = page
|
c.RenderArgs["page"] = page
|
||||||
c.RenderArgs["pageSize"] = blogPageSize
|
c.RenderArgs["pageSize"] = blogPageSize
|
||||||
c.RenderArgs["count"] = count
|
c.RenderArgs["count"] = count
|
||||||
|
|
||||||
// 当前notebook
|
return c.RenderTemplate("blog/index.html")
|
||||||
c.RenderArgs["notebookId"] = notebookId
|
}
|
||||||
c.RenderArgs["notebook"] = notebook
|
|
||||||
|
|
||||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
|
||||||
|
|
||||||
|
|
||||||
|
// 显示分类的最近博客, json
|
||||||
|
func (c Blog) ListCateLatest(notebookId, callback string) revel.Result {
|
||||||
if notebookId == "" {
|
if notebookId == "" {
|
||||||
c.RenderArgs["index"] = true
|
return c.E404()
|
||||||
|
}
|
||||||
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
c.getRecentBlogs(userId)
|
var notebook info.Notebook
|
||||||
|
notebook = notebookService.GetNotebookById(notebookId)
|
||||||
|
if !notebook.IsBlog {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
if userId != "" && userId != notebook.UserId.Hex() {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
userId = notebook.UserId.Hex()
|
||||||
|
|
||||||
|
if !c.blogCommon(userId, userBlog, info.User{}) {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页的话, 需要分页信息, totalPage, curPage
|
||||||
|
page := 1
|
||||||
|
_, blogs := blogService.ListBlogs(userId, notebookId, page, 5, "PublicTime", false)
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
re.List = blogs
|
||||||
|
return c.RenderJsonP(callback, re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Blog) Index(userIdOrEmail string) revel.Result {
|
||||||
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户id为空, 转至博客平台
|
||||||
|
if userIdOrEmail == "" {
|
||||||
|
userIdOrEmail = leanoteUserId;
|
||||||
|
}
|
||||||
|
var userInfo info.User
|
||||||
|
if userId != "" {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userId)
|
||||||
|
} else {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
|
||||||
|
}
|
||||||
|
userId = userInfo.UserId.Hex()
|
||||||
|
|
||||||
|
if !c.blogCommon(userId, userBlog, userInfo) {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页的话, 需要分页信息, totalPage, curPage
|
||||||
|
page := c.GetPage()
|
||||||
|
count, blogs := blogService.ListBlogs(userId, "", page, blogPageSize, "PublicTime", false)
|
||||||
|
|
||||||
|
c.RenderArgs["blogs"] = blogs
|
||||||
|
c.RenderArgs["page"] = page
|
||||||
|
c.RenderArgs["pageSize"] = blogPageSize
|
||||||
|
c.RenderArgs["count"] = count
|
||||||
|
c.RenderArgs["index"] = true
|
||||||
|
c.RenderArgs["notebookId"] = ""
|
||||||
|
c.RenderArgs["title"] = userBlog.Title
|
||||||
|
|
||||||
return c.RenderTemplate("blog/index.html")
|
return c.RenderTemplate("blog/index.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 详情
|
// 详情
|
||||||
func (c Blog) View(noteId string) revel.Result {
|
func (c Blog) View(noteId string) revel.Result {
|
||||||
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
blog := blogService.GetBlog(noteId)
|
blog := blogService.GetBlog(noteId)
|
||||||
c.RenderArgs["blog"] = blog
|
|
||||||
|
|
||||||
userInfo := userService.GetUserInfo(blog.UserId.Hex())
|
userInfo := userService.GetUserInfo(blog.UserId.Hex())
|
||||||
|
if userId != "" && userInfo.UserId.Hex() != userId {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
c.RenderArgs["blog"] = blog
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
c.RenderArgs["title"] = blog.Title + " - " + userInfo.Username
|
||||||
|
|
||||||
c.RenderArgs["title"] = blog.Title + " - " + userInfo.Email
|
userId = userInfo.UserId.Hex()
|
||||||
|
c.blogCommon(userId, userBlog, info.User{})
|
||||||
|
|
||||||
userId := userInfo.UserId.Hex()
|
// 得到访问者id
|
||||||
c.isMe(userId)
|
visitUserId := c.GetUserId()
|
||||||
|
if(visitUserId != "") {
|
||||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
visitUserInfo := userService.GetUserInfo(visitUserId)
|
||||||
|
c.RenderArgs["visitUserInfoJson"] = c.Json(visitUserInfo)
|
||||||
// 得到博客设置信息
|
c.RenderArgs["visitUserInfo"] = visitUserInfo
|
||||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
} else {
|
||||||
|
c.RenderArgs["visitUserInfoJson"] = "{}";
|
||||||
c.getRecentBlogs(userId)
|
}
|
||||||
|
|
||||||
return c.RenderTemplate("blog/view.html")
|
return c.RenderTemplate("blog/view.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索
|
// 搜索
|
||||||
func (c Blog) SearchBlog(userId, key string) revel.Result {
|
func (c Blog) Search(userIdOrEmail, key string) revel.Result {
|
||||||
c.RenderArgs["title"] = "搜索 " + key
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = c.Message("search") + " - " + key
|
||||||
c.RenderArgs["key"] = key
|
c.RenderArgs["key"] = key
|
||||||
|
|
||||||
userInfo := userService.GetUserInfoByAny(userId)
|
var userInfo info.User
|
||||||
|
if userId != "" {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userId)
|
||||||
|
} else {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
|
||||||
|
}
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
userId = userInfo.UserId.Hex()
|
userId = userInfo.UserId.Hex()
|
||||||
|
c.blogCommon(userId, userBlog, userInfo)
|
||||||
|
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
_, blogs := blogService.SearchBlog(key, userId, page, searchBlogPageSize, "UpdatedTime", false)
|
_, blogs := blogService.SearchBlog(key, userId, page, searchBlogPageSize, "PublicTime", false)
|
||||||
|
|
||||||
c.RenderArgs["blogs"] = blogs
|
c.RenderArgs["blogs"] = blogs
|
||||||
c.RenderArgs["key"] = key
|
c.RenderArgs["key"] = key
|
||||||
|
|
||||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
|
||||||
// 得到博客设置信息
|
|
||||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
|
||||||
|
|
||||||
c.getRecentBlogs(userId)
|
|
||||||
|
|
||||||
c.isMe(userId)
|
|
||||||
|
|
||||||
return c.RenderTemplate("blog/search.html")
|
return c.RenderTemplate("blog/search.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,15 +305,15 @@ func (c Blog) Set() revel.Result {
|
|||||||
userInfo := userService.GetUserInfo(userId)
|
userInfo := userService.GetUserInfo(userId)
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
|
||||||
|
|
||||||
// 得到博客设置信息
|
// 得到博客设置信息
|
||||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
c.RenderArgs["title"] = c.Message("blogSet")
|
||||||
c.RenderArgs["title"] = "博客设置"
|
|
||||||
c.RenderArgs["isMe"] = true
|
c.RenderArgs["isMe"] = true
|
||||||
c.RenderArgs["set"] = true
|
c.RenderArgs["set"] = true
|
||||||
|
|
||||||
c.getRecentBlogs(userId)
|
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
||||||
|
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
c.blogCommon(userId, userBlog, info.User{})
|
||||||
|
|
||||||
return c.RenderTemplate("blog/set.html")
|
return c.RenderTemplate("blog/set.html")
|
||||||
}
|
}
|
||||||
@@ -193,37 +335,38 @@ func (c Blog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// userId可能是其它的
|
// userId可能是其它的
|
||||||
func (c Blog) AboutMe(userId string) revel.Result {
|
func (c Blog) AboutMe(userIdOrEmail string) revel.Result {
|
||||||
userInfo := userService.GetUserInfoByAny(userId)
|
// 自定义域名
|
||||||
|
hasDomain, userBlog := c.domain()
|
||||||
|
userId := ""
|
||||||
|
if hasDomain {
|
||||||
|
userId = userBlog.UserId.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
var userInfo info.User
|
||||||
|
if userId != "" {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userId)
|
||||||
|
} else {
|
||||||
|
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
|
||||||
|
}
|
||||||
|
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
userId = userInfo.UserId.Hex()
|
userId = userInfo.UserId.Hex()
|
||||||
|
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
|
||||||
|
|
||||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
|
||||||
c.RenderArgs["aboutMe"] = true
|
c.RenderArgs["aboutMe"] = true
|
||||||
|
|
||||||
c.RenderArgs["title"] = "关于我"
|
c.RenderArgs["title"] = c.Message("aboutMe")
|
||||||
|
c.blogCommon(userId, userBlog, info.User{})
|
||||||
c.isMe(userId)
|
|
||||||
|
|
||||||
c.getRecentBlogs(userId)
|
|
||||||
|
|
||||||
return c.RenderTemplate("blog/about_me.html")
|
return c.RenderTemplate("blog/about_me.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前的博客是否是我的
|
|
||||||
func (c Blog) isMe(userId string) {
|
|
||||||
c.RenderArgs["isMe"] = userId == c.GetUserId()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 优化, 这里不要得到count
|
// 优化, 这里不要得到count
|
||||||
func (c Blog) getRecentBlogs(userId string) {
|
func (c Blog) getRecentBlogs(userId string) {
|
||||||
_, c.RenderArgs["recentBlogs"] = blogService.ListBlogs(userId, "", 1, 5, "UpdatedTime", false)
|
_, c.RenderArgs["recentBlogs"] = blogService.ListBlogs(userId, "", 1, 5, "PublicTime", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可以不要, 因为注册的时候已经把username设为email了
|
// 可以不要, 因为注册的时候已经把username设为email了
|
||||||
@@ -233,3 +376,129 @@ func (c Blog) setRenderUserInfo(userInfo info.User) {
|
|||||||
}
|
}
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
// 后台 note<->blog
|
||||||
|
|
||||||
|
// 设置/取消Blog; 置顶
|
||||||
|
func (c Blog) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||||
|
noteUpdate := bson.M{}
|
||||||
|
if isTop {
|
||||||
|
isBlog = true
|
||||||
|
}
|
||||||
|
if !isBlog {
|
||||||
|
isTop = false
|
||||||
|
}
|
||||||
|
noteUpdate["IsBlog"] = isBlog
|
||||||
|
noteUpdate["IsTop"] = isTop
|
||||||
|
if isBlog {
|
||||||
|
noteUpdate["PublicTime"] = time.Now()
|
||||||
|
}
|
||||||
|
re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(),
|
||||||
|
noteId, noteUpdate)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置notebook <-> blog
|
||||||
|
func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||||
|
noteUpdate := bson.M{"IsBlog": isBlog}
|
||||||
|
re := notebookService.UpdateNotebook(c.GetUserId(),
|
||||||
|
notebookId, noteUpdate)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
// 社交, 点赞, 评论
|
||||||
|
|
||||||
|
// 我是否点过赞?
|
||||||
|
// 所有点赞的用户列表
|
||||||
|
// 各个评论中是否我也点过赞?
|
||||||
|
func (c Blog) GetLike(noteId string) revel.Result {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
|
||||||
|
// 我也点过?
|
||||||
|
isILikeIt := blogService.IsILikeIt(noteId, userId)
|
||||||
|
// 点赞用户列表
|
||||||
|
likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false)
|
||||||
|
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
result["isILikeIt"] = isILikeIt
|
||||||
|
result["likedUsers"] = likedUsers
|
||||||
|
result["hasMoreLikedUser"] = hasMoreLikedUser
|
||||||
|
|
||||||
|
return c.RenderJson(result)
|
||||||
|
}
|
||||||
|
func (c Blog) GetLikeAndComments(noteId string) revel.Result {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
|
||||||
|
// 我也点过?
|
||||||
|
isILikeIt := blogService.IsILikeIt(noteId, userId)
|
||||||
|
// 点赞用户列表
|
||||||
|
likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false)
|
||||||
|
// 评论
|
||||||
|
page := c.GetPage()
|
||||||
|
pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15)
|
||||||
|
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
result["isILikeIt"] = isILikeIt
|
||||||
|
result["likedUsers"] = likedUsers
|
||||||
|
result["hasMoreLikedUser"] = hasMoreLikedUser
|
||||||
|
result["pageInfo"] = pageInfo
|
||||||
|
result["comments"] = comments
|
||||||
|
result["commentUserInfo"] = commentUserInfo
|
||||||
|
|
||||||
|
return c.RenderJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Blog) IncReadNum(noteId string) revel.Result {
|
||||||
|
blogService.IncReadNum(noteId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// 点赞
|
||||||
|
func (c Blog) LikeBlog(noteId string) revel.Result {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c Blog) ListLikes(noteId string) revel.Result {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Blog) ListComments(noteId string) revel.Result {
|
||||||
|
// 评论
|
||||||
|
userId := c.GetUserId()
|
||||||
|
page := c.GetPage()
|
||||||
|
pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15)
|
||||||
|
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
result["pageInfo"] = pageInfo
|
||||||
|
result["comments"] = comments
|
||||||
|
result["commentUserInfo"] = commentUserInfo
|
||||||
|
|
||||||
|
return c.RenderJson(result)
|
||||||
|
}
|
||||||
|
func (c Blog) DeleteComment(noteId, commentId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId())
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c Blog) Comment(noteId, content, toCommentId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content);
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c Blog) LikeComment(commentId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId())
|
||||||
|
re.Ok = ok
|
||||||
|
re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num}
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Blog) Report(noteId, commentId, reason string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.Report(noteId, commentId, reason, c.GetUserId());
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -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,14 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -14,44 +18,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("logo", "");
|
||||||
}
|
|
||||||
|
|
||||||
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 = "内部错误" // 错误信息
|
||||||
|
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 +100,30 @@ func (c File) uploadImage() (re info.Re) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
// 生成上传路径
|
// 生成上传路径
|
||||||
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
|
if(from == "logo") {
|
||||||
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)
|
|
||||||
|
var ext string;
|
||||||
|
if from == "pasteImage" {
|
||||||
|
ext = ".png"; // TODO 可能不是png类型
|
||||||
|
} else {
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||||
resultMsg = "不是图片"
|
resultMsg = "不是图片"
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
filename = NewGuid() + ext
|
filename = NewGuid() + ext
|
||||||
data, err := ioutil.ReadAll(file)
|
data, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,10 +146,172 @@ 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 = "上传成功!"
|
||||||
|
|
||||||
|
// 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") {
|
||||||
|
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update image uploader to leaui image,
|
||||||
|
// scan all user's images and insert into db
|
||||||
|
func (c File) UpgradeLeauiImage() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
if ok, _ := revel.Config.Bool("upgradeLeauiImage"); !ok {
|
||||||
|
re.Msg = "Not allowed"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadPath := revel.BasePath + "/public/upload";
|
||||||
|
userIds := ListDir(uploadPath)
|
||||||
|
if userIds == nil {
|
||||||
|
re.Msg = "no user"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := "";
|
||||||
|
|
||||||
|
for _, userId := range userIds {
|
||||||
|
dirPath := uploadPath + "/" + userId + "/images"
|
||||||
|
images := ListDir(dirPath)
|
||||||
|
if images == nil {
|
||||||
|
msg += userId + " no images "
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hadImages := fileService.GetAllImageNamesMap(userId)
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for _, filename := range images {
|
||||||
|
if _, ok := hadImages[filename]; !ok {
|
||||||
|
fileUrlPath := "/upload/" + userId + "/images/" + filename
|
||||||
|
fileInfo := info.File{Name: filename,
|
||||||
|
Title: filename,
|
||||||
|
Path: fileUrlPath,
|
||||||
|
Size: GetFilesize(dirPath + "/" + filename)}
|
||||||
|
fileService.AddImage(fileInfo, "", userId)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg += userId + ": " + strconv.Itoa(len(images)) + " -- " + strconv.Itoa(i) + " images "
|
||||||
|
}
|
||||||
|
|
||||||
|
re.Msg = msg
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
// 输出image
|
||||||
|
// 权限判断
|
||||||
|
func (c File) OutputImage(noteId, fileId string) revel.Result {
|
||||||
|
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
|
||||||
|
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 = fileService.AddImage(fileInfo, "", c.GetUserId())
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------
|
||||||
|
// 过时 已弃用!
|
||||||
|
func (c File) UploadImage(renderHtml string) revel.Result {
|
||||||
|
if renderHtml == "" {
|
||||||
|
renderHtml = "file/image.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
re := c.uploadImage("", "");
|
||||||
|
|
||||||
|
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
||||||
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
|
return c.RenderTemplate(renderHtml)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已弃用
|
||||||
|
func (c File) UploadImageJson(from, noteId string) revel.Result {
|
||||||
|
re := c.uploadImage(from, "");
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@@ -16,10 +16,10 @@ type Index struct {
|
|||||||
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 +29,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)
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ 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"
|
||||||
// "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 {
|
||||||
@@ -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)
|
||||||
@@ -52,6 +53,7 @@ func (c Note) Index() revel.Result {
|
|||||||
// 当然, 还需要得到第一个notes的content
|
// 当然, 还需要得到第一个notes的content
|
||||||
//...
|
//...
|
||||||
|
|
||||||
|
c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||||
@@ -117,7 +119,6 @@ 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
|
||||||
@@ -222,31 +223,131 @@ 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:]
|
||||||
|
}
|
||||||
|
|
||||||
|
appKey, _ := revel.Config.String("app.secret")
|
||||||
|
cookieDomain, _ := revel.Config.String("cookie.domain")
|
||||||
|
// 生成之
|
||||||
|
url := siteUrl + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
||||||
|
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
|
||||||
|
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
|
if binPath == "" {
|
||||||
|
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.Ok = true
|
||||||
re.Id = fileUrlPath + "/" + filename
|
re.Id = fileUrlPath + "/" + filename
|
||||||
|
} else {
|
||||||
|
re.Msg = string(b)
|
||||||
|
Log("error:......")
|
||||||
|
Log(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
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))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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,23 @@ 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))
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ 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"
|
||||||
|
|||||||
@@ -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,38 @@
|
|||||||
|
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
|
||||||
|
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,119 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) 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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "encoding/json"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
// "io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upgrade controller
|
||||||
|
type AdminUpgrade struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
||||||
|
upgradeService.UpgradeBlog()
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type AdminUser struct {
|
||||||
|
AdminBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
var userPageSize = 10
|
||||||
|
func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
||||||
|
pageNumber := c.GetPage()
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
|
||||||
|
pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
||||||
|
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");
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
var adminUsername = "admin"
|
||||||
|
// 拦截器
|
||||||
|
// 不需要拦截的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 == adminUsername {
|
||||||
|
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,155 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 用户登录后生成一个token, 将这个token保存到session中
|
||||||
|
// 以后每次的请求必须带这个token, 并从session中获取userId
|
||||||
|
|
||||||
|
// 用户登录/注销/找回密码
|
||||||
|
|
||||||
|
type ApiAuth struct {
|
||||||
|
ApiBaseContrller
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为了demo和register
|
||||||
|
func (c ApiAuth) doLogin(email, pwd string) revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
var msg = ""
|
||||||
|
|
||||||
|
userInfo := authService.Login(email, pwd)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
c.SetSession(userInfo)
|
||||||
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
||||||
|
}
|
||||||
|
func (c ApiAuth) Login(email, pwd string, captcha string) revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
var msg = ""
|
||||||
|
|
||||||
|
// > 5次需要验证码, 直到登录成功
|
||||||
|
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
|
||||||
|
msg = "captchaError"
|
||||||
|
} else {
|
||||||
|
userInfo := authService.Login(email, pwd)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
c.SetSession(userInfo)
|
||||||
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
|
return c.RenderJson(info.Re{Ok: true})
|
||||||
|
} else {
|
||||||
|
// 登录错误, 则错误次数++
|
||||||
|
msg = "wrongUsernameOrPassword"
|
||||||
|
sessionService.IncrLoginTimes(sessionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId) , Msg: c.Message(msg)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注销
|
||||||
|
func (c ApiAuth) Logout() revel.Result {
|
||||||
|
sessionId := c.Session.Id()
|
||||||
|
sessionService.Clear(sessionId)
|
||||||
|
c.ClearSession()
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 体验一下
|
||||||
|
func (c ApiAuth) Demo() revel.Result {
|
||||||
|
c.doLogin(configService.GetGlobalStringConfig("demoUsername"), configService.GetGlobalStringConfig("demoPassword"))
|
||||||
|
return c.Redirect("/note")
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------
|
||||||
|
// 注册
|
||||||
|
func (c ApiAuth) Register(from string) revel.Result {
|
||||||
|
if !configService.IsOpenRegister() {
|
||||||
|
return c.Redirect("/index")
|
||||||
|
}
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["from"] = from
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = c.Message("register")
|
||||||
|
c.RenderArgs["subTitle"] = c.Message("register")
|
||||||
|
return c.RenderTemplate("home/register.html")
|
||||||
|
}
|
||||||
|
func (c ApiAuth) DoRegister(email, pwd string) revel.Result {
|
||||||
|
if !configService.IsOpenRegister() {
|
||||||
|
return c.Redirect("/index")
|
||||||
|
}
|
||||||
|
|
||||||
|
re := info.NewRe();
|
||||||
|
|
||||||
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
|
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)
|
||||||
|
|
||||||
|
// 注册成功, 则立即登录之
|
||||||
|
if re.Ok {
|
||||||
|
c.doLogin(email, pwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------
|
||||||
|
// 找回密码
|
||||||
|
func (c ApiAuth) FindPassword() revel.Result {
|
||||||
|
c.RenderArgs["title"] = c.Message("findPassword")
|
||||||
|
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||||
|
return c.RenderTemplate("home/find_password.html")
|
||||||
|
}
|
||||||
|
func (c ApiAuth) DoFindPassword(email string) revel.Result {
|
||||||
|
pwdService.FindPwd(email)
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 点击链接后, 先验证之
|
||||||
|
func (c ApiAuth) FindPassword2(token string) revel.Result {
|
||||||
|
c.RenderArgs["title"] = c.Message("findPassword")
|
||||||
|
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||||
|
if token == "" {
|
||||||
|
return c.RenderTemplate("find_password2_timeout.html")
|
||||||
|
}
|
||||||
|
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
|
||||||
|
if !ok {
|
||||||
|
return c.RenderTemplate("home/find_password2_timeout.html")
|
||||||
|
}
|
||||||
|
c.RenderArgs["findPwd"] = findPwd
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = c.Message("updatePassword")
|
||||||
|
c.RenderArgs["subTitle"] = c.Message("updatePassword")
|
||||||
|
|
||||||
|
return c.RenderTemplate("home/find_password2.html")
|
||||||
|
}
|
||||||
|
// 找回密码修改密码
|
||||||
|
func (c ApiAuth) FindPasswordUpdate(token, pwd string) revel.Result {
|
||||||
|
re := info.NewRe();
|
||||||
|
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改之
|
||||||
|
re.Ok, re.Msg = pwdService.UpdatePwd(token, pwd)
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "github.com/revel/revel"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
// "encoding/json"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/controllers"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "strconv"
|
||||||
|
// "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 公用Controller, 其它Controller继承它
|
||||||
|
type ApiBaseContrller struct {
|
||||||
|
controllers.BaseController // 不能用*BaseController
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
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 {
|
||||||
|
ApiBaseContrller
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户名, 需要重置session
|
||||||
|
func (c ApiUser) Info() revel.Result {
|
||||||
|
Log("APIUser");
|
||||||
|
return c.RenderTemplate("home/index.html");
|
||||||
|
// return nil;
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
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 sessionService *service.SessionService
|
||||||
|
|
||||||
|
var pageSize = 1000
|
||||||
|
var defaultSortField = "UpdatedTime"
|
||||||
|
var leanoteUserId = "admin" // 不能更改
|
||||||
|
var siteUrl = "http://leanote.com"
|
||||||
|
|
||||||
|
// 拦截器
|
||||||
|
// 不需要拦截的url
|
||||||
|
// Index 除了Note之外都不需要
|
||||||
|
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||||
|
"Login": true,
|
||||||
|
"DoLogin": true,
|
||||||
|
"Logout": true,
|
||||||
|
"Register": true,
|
||||||
|
"DoRegister": true,
|
||||||
|
"FindPasswword": true,
|
||||||
|
"DoFindPassword": true,
|
||||||
|
"FindPassword2": true,
|
||||||
|
"FindPasswordUpdate": true,
|
||||||
|
"Suggestion": true,
|
||||||
|
},
|
||||||
|
"Note": map[string]bool{"ToImage": true},
|
||||||
|
"Blog": map[string]bool{"Index": true,
|
||||||
|
"View": true,
|
||||||
|
"AboutMe": true,
|
||||||
|
"Cate": true,
|
||||||
|
"Search": true,
|
||||||
|
"GetLikeAndComments": true,
|
||||||
|
"IncReadNum": true,
|
||||||
|
"ListComments": true,
|
||||||
|
},
|
||||||
|
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||||
|
"User": map[string]bool{"UpdateEmail": true,
|
||||||
|
"ActiveEmail":true,
|
||||||
|
},
|
||||||
|
"Oauth": map[string]bool{"GithubCallback": true},
|
||||||
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
|
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||||
|
}
|
||||||
|
func needValidate(controller, method string) bool {
|
||||||
|
// 在里面
|
||||||
|
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 userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||||
|
return nil // 已登录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有登录, 判断是否是ajax操作
|
||||||
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Msg = "NOTLOGIN"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect("/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最外层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
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// interceptors
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiAuth{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &ApiUser{})
|
||||||
|
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
siteUrl, _ = revel.Config.String("site.url")
|
||||||
|
})
|
||||||
|
}
|
||||||
+44
-27
@@ -3,18 +3,16 @@ 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"
|
||||||
"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,12 +20,18 @@ 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 pageSize = 1000
|
var pageSize = 1000
|
||||||
var defaultSortField = "UpdatedTime"
|
var defaultSortField = "UpdatedTime"
|
||||||
var leanoteUserId = "52d26b4e99c37b609a000001"
|
var leanoteUserId = "admin" // 不能更改
|
||||||
var siteUrl = "http://leanote.com"
|
var siteUrl = "http://leanote.com"
|
||||||
var openRegister = true
|
|
||||||
|
|
||||||
// 拦截器
|
// 拦截器
|
||||||
// 不需要拦截的url
|
// 不需要拦截的url
|
||||||
@@ -44,21 +48,28 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
|||||||
"FindPasswordUpdate": true,
|
"FindPasswordUpdate": true,
|
||||||
"Suggestion": true,
|
"Suggestion": true,
|
||||||
},
|
},
|
||||||
|
"Note": map[string]bool{"ToImage": 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,
|
||||||
|
"Search": true,
|
||||||
|
"GetLikeAndComments": true,
|
||||||
|
"IncReadNum": true,
|
||||||
|
"ListComments": 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
|
||||||
}
|
}
|
||||||
@@ -73,13 +84,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 +104,30 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// interceptor
|
// interceptor
|
||||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
||||||
@@ -103,27 +136,11 @@ 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, &Attach{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||||
|
|
||||||
// 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")
|
siteUrl, _ = revel.Config.String("site.url")
|
||||||
openRegister, _ = revel.Config.Bool("register.open")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+39
-8
@@ -2,8 +2,8 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"labix.org/v2/mgo"
|
"gopkg.in/mgo.v2"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +33,23 @@ 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
|
||||||
|
|
||||||
|
// session
|
||||||
|
var Sessions *mgo.Collection
|
||||||
|
|
||||||
// 初始化时连接数据库
|
// 初始化时连接数据库
|
||||||
func Init() {
|
func Init() {
|
||||||
var url string
|
var url string
|
||||||
@@ -94,14 +111,28 @@ func Init() {
|
|||||||
// 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() {
|
||||||
|
|||||||
+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
|
||||||
|
}
|
||||||
+44
-1
@@ -1,7 +1,8 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 只为blog, 不为note
|
// 只为blog, 不为note
|
||||||
@@ -10,6 +11,7 @@ type BlogItem struct {
|
|||||||
Note
|
Note
|
||||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||||
HasMore bool // 是否是否还有
|
HasMore bool // 是否是否还有
|
||||||
|
User User // 用户信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogBase struct {
|
type UserBlogBase struct {
|
||||||
@@ -21,11 +23,13 @@ type UserBlogBase struct {
|
|||||||
|
|
||||||
type UserBlogComment struct {
|
type UserBlogComment struct {
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogStyle struct {
|
type UserBlogStyle struct {
|
||||||
Style string `Style` // 风格
|
Style string `Style` // 风格
|
||||||
|
Css string `Css` // 自定义css
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每个用户一份博客设置信息
|
// 每个用户一份博客设置信息
|
||||||
@@ -37,7 +41,46 @@ type UserBlog struct {
|
|||||||
AboutMe string `AboutMe` // 关于我
|
AboutMe string `AboutMe` // 关于我
|
||||||
|
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
|
|
||||||
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
|
|
||||||
Style string `Style` // 风格
|
Style string `Style` // 风格
|
||||||
|
Css string `Css` // 自定义css
|
||||||
|
|
||||||
|
SubDomain string `SubDomain` // 二级域名
|
||||||
|
Domain string `Domain` // 自定义域名
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// 社交功能, 点赞, 分享, 评论
|
||||||
|
|
||||||
|
// 点赞记录
|
||||||
|
type BlogLike struct {
|
||||||
|
LikeId bson.ObjectId `bson:"_id"`
|
||||||
|
NoteId bson.ObjectId `NoteId`
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 评论
|
||||||
|
type BlogComment struct {
|
||||||
|
CommentId bson.ObjectId `bson:"_id"`
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@@ -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,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
|
||||||
|
}
|
||||||
+12
-1
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,15 +17,26 @@ type Note struct {
|
|||||||
|
|
||||||
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
||||||
Tags []string `Tags,omitempty`
|
Tags []string `Tags,omitempty`
|
||||||
|
|
||||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||||
|
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||||
|
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||||
|
|
||||||
|
// 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`
|
||||||
|
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||||
|
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,7 +21,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 +32,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,19 @@
|
|||||||
|
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` // 验证码
|
||||||
|
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 建议
|
// 建议
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 这里主要是为了统计每个tag的note数目
|
// 这里主要是为了统计每个tag的note数目
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,12 +20,14 @@ 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` // 左侧是否是隐藏的, 默认是打开的
|
||||||
|
|
||||||
// 这里 第三方登录
|
// 这里 第三方登录
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package info
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -8,5 +9,14 @@ import (
|
|||||||
type Page struct {
|
type Page struct {
|
||||||
CurPage int // 当前页码
|
CurPage int // 当前页码
|
||||||
TotalPage int // 总页
|
TotalPage 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, count, list}
|
||||||
|
}
|
||||||
+199
-11
@@ -3,26 +3,39 @@ 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/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"
|
||||||
)
|
)
|
||||||
|
|
||||||
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 +48,42 @@ 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["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["json"] = func(i interface{}) string {
|
||||||
|
b, _ := json.Marshal(i)
|
||||||
|
return 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["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 +93,26 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
|
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)
|
||||||
|
for i, tag := range tags {
|
||||||
|
str := revel.Message(locale, tag)
|
||||||
|
if strings.HasPrefix(str, "???") {
|
||||||
|
str = tag
|
||||||
|
}
|
||||||
|
tagStr += str
|
||||||
|
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 +133,88 @@ func init() {
|
|||||||
}
|
}
|
||||||
return template.HTML(tagStr)
|
return template.HTML(tagStr)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
revel.TemplateFuncs["li"] = func(a string) string {
|
||||||
|
Log(a)
|
||||||
|
Log("life==")
|
||||||
|
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 +229,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 +244,64 @@ 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()
|
||||||
|
service.ConfigS.InitGlobalConfigs()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+10
-10
@@ -22,14 +22,14 @@ 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;">
|
||||||
<a href="http://leanote.com" style="font-size: 24px">leanote</a>
|
<a href="http://leanote.com" style="font-size: 24px">leanote</a>
|
||||||
</div>
|
</div>
|
||||||
<div style="float:left; height:40px; line-height:16px;">
|
<div style="float:left; height:40px; line-height:40px;">
|
||||||
| <span style="font-size:24px">$title</span>
|
| <span style="font-size:14px">$title</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="clear:both"></div>
|
<div style="clear:both"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,13 +50,13 @@ var bodyTpl = `
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<a href="http://leanote.com">leanote</a>, your own cloud note
|
<a href="http://leanote.com">leanote</a>, your own cloud note!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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,21 +69,21 @@ 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, ";")
|
||||||
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
|
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Log(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"os"
|
"os"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 分离文件名与扩展名(包含.)
|
// 分离文件名与扩展名(包含.)
|
||||||
@@ -30,6 +31,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 +54,37 @@ 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 IsDirExists(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return os.IsExist(err)
|
||||||
|
}else{
|
||||||
|
return fi.IsDir()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
+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
|
||||||
|
}
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
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"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
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
|
||||||
|
},
|
||||||
|
|
||||||
|
"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,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")
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,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 +22,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 +31,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 +51,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 +63,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
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
|
||||||
|
if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") {
|
||||||
|
route.ControllerName = "Api" + 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}
|
||||||
|
}
|
||||||
+195
-18
@@ -1,31 +1,208 @@
|
|||||||
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))
|
||||||
}
|
}
|
||||||
c.Session = cache
|
|
||||||
|
cookieDomain, _ = revel.Config.String("cookie.domain")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Id retrieves from the cookie or creates a time-based UUID identifying this
|
||||||
|
// session.
|
||||||
|
func (s Session) Id() string {
|
||||||
|
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
|
||||||
|
return sessionIdStr
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(buffer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s[SESSION_ID_KEY] = hex.EncodeToString(buffer)
|
||||||
|
return s[SESSION_ID_KEY]
|
||||||
|
}
|
||||||
|
|
||||||
|
// getExpiration return a time.Time with the session's expiration date.
|
||||||
|
// If previous session has set to "session", remain it
|
||||||
|
func (s Session) getExpiration() time.Time {
|
||||||
|
if expireAfterDuration == 0 || s[TIMESTAMP_KEY] == "session" {
|
||||||
|
// Expire after closing browser
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
return time.Now().Add(expireAfterDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cookie returns an http.Cookie containing the signed session.
|
||||||
|
func (s Session) cookie() *http.Cookie {
|
||||||
|
var sessionValue string
|
||||||
|
ts := s.getExpiration()
|
||||||
|
s[TIMESTAMP_KEY] = getSessionExpirationCookie(ts)
|
||||||
|
for key, value := range s {
|
||||||
|
if strings.ContainsAny(key, ":\x00") {
|
||||||
|
panic("Session keys may not have colons or null bytes")
|
||||||
|
}
|
||||||
|
if strings.Contains(value, "\x00") {
|
||||||
|
panic("Session values may not have null bytes")
|
||||||
|
}
|
||||||
|
sessionValue += "\x00" + key + ":" + value + "\x00"
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionData := url.QueryEscape(sessionValue)
|
||||||
|
cookie := http.Cookie{
|
||||||
|
Name: revel.CookiePrefix + "_SESSION",
|
||||||
|
Value: revel.Sign(sessionData) + "-" + sessionData,
|
||||||
|
Path: "/",
|
||||||
|
HttpOnly: revel.CookieHttpOnly,
|
||||||
|
Secure: revel.CookieSecure,
|
||||||
|
Expires: ts.UTC(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cookieDomain != "" {
|
||||||
|
cookie.Domain = cookieDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionTimeoutExpiredOrMissing returns a boolean of whether the session
|
||||||
|
// cookie is either not present or present but beyond its time to live; i.e.,
|
||||||
|
// whether there is not a valid session.
|
||||||
|
func sessionTimeoutExpiredOrMissing(session Session) bool {
|
||||||
|
if exp, present := session[TIMESTAMP_KEY]; !present {
|
||||||
|
return true
|
||||||
|
} else if exp == "session" {
|
||||||
|
return false
|
||||||
|
} else if expInt, _ := strconv.Atoi(exp); int64(expInt) < time.Now().Unix() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSessionFromCookie returns a Session struct pulled from the signed
|
||||||
|
// session cookie.
|
||||||
|
func getSessionFromCookie(cookie *http.Cookie) Session {
|
||||||
|
session := make(Session)
|
||||||
|
|
||||||
|
// Separate the data from the signature.
|
||||||
|
hyphen := strings.Index(cookie.Value, "-")
|
||||||
|
if hyphen == -1 || hyphen >= len(cookie.Value)-1 {
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
|
||||||
|
|
||||||
|
// Verify the signature.
|
||||||
|
if !revel.Verify(data, sig) {
|
||||||
|
revel.INFO.Println("Session cookie signature failed")
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
revel.ParseKeyValueCookie(data, func(key, val string) {
|
||||||
|
session[key] = val
|
||||||
|
})
|
||||||
|
|
||||||
|
if sessionTimeoutExpiredOrMissing(session) {
|
||||||
|
session = make(Session)
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionFilter is a Revel Filter that retrieves and sets the session cookie.
|
||||||
|
// Within Revel, it is available as a Session attribute on Controller instances.
|
||||||
|
// The name of the Session cookie is set as CookiePrefix + "_SESSION".
|
||||||
|
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
session := restoreSession(c.Request.Request)
|
||||||
|
// c.Session, 重新生成一个revel.Session给controller!!!
|
||||||
|
// Log("sessoin--------")
|
||||||
|
// LogJ(session)
|
||||||
|
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
|
||||||
|
c.Session = revelSession
|
||||||
|
// 生成sessionId
|
||||||
|
c.Session.Id()
|
||||||
|
sessionWasEmpty := len(c.Session) == 0
|
||||||
|
|
||||||
|
// Make session vars available in templates as {{.session.xyz}}
|
||||||
|
c.RenderArgs["session"] = c.Session
|
||||||
|
|
||||||
fc[0](c, fc[1:])
|
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)
|
||||||
}
|
}
|
||||||
+11
-5
@@ -33,11 +33,13 @@ 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", "js/ZeroClipboard/ZeroClipboard"}
|
||||||
|
|
||||||
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")
|
||||||
@@ -62,6 +64,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)
|
||||||
|
|
||||||
// 每个压缩后的文件放入之
|
// 每个压缩后的文件放入之
|
||||||
@@ -84,13 +87,14 @@ func dev() {
|
|||||||
"notebook.js": "notebook-min.js",
|
"notebook.js": "notebook-min.js",
|
||||||
"share.js": "share-min.js",
|
"share.js": "share-min.js",
|
||||||
"tag.js": "tag-min.js",
|
"tag.js": "tag-min.js",
|
||||||
|
"main.js": "main-min.js",
|
||||||
"jquery.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,7 +111,8 @@ 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()
|
c, err := cmd.CombinedOutput()
|
||||||
|
fmt.Println(string(c))
|
||||||
cmdError(err)
|
cmdError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,11 +120,12 @@ func main() {
|
|||||||
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",
|
||||||
|
|||||||
@@ -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,175 @@
|
|||||||
|
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) bool {
|
||||||
|
attach.CreatedTime = time.Now()
|
||||||
|
ok := db.Insert(db.Attachs, attach)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
// 更新笔记的attachs num
|
||||||
|
this.updateNoteAttachNum(attach.NoteId, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新笔记的附件个数
|
||||||
|
// 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{}
|
||||||
|
// 判断是否有权限为笔记添加附件
|
||||||
|
if !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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
+24
-12
@@ -1,12 +1,13 @@
|
|||||||
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"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 登录与权限
|
// 登录与权限
|
||||||
@@ -16,7 +17,8 @@ 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))
|
userInfo := userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||||
|
return userInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
@@ -56,21 +58,31 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
// 公开为博客
|
// 复制笔记
|
||||||
|
for _, noteId := range registerCopyNoteIds {
|
||||||
|
note := noteService.CopySharedNote(noteId, title2Id["life"].Hex(), registerSharedUserId, user.UserId.Hex());
|
||||||
noteUpdate := bson.M{"IsBlog": true}
|
noteUpdate := bson.M{"IsBlog": true}
|
||||||
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
// 添加一条userBlog
|
// 添加一条userBlog
|
||||||
|
|||||||
+428
-12
@@ -3,10 +3,12 @@ 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"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
@@ -40,7 +42,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
|||||||
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
||||||
|
|
||||||
// 组装成blogItem
|
// 组装成blogItem
|
||||||
blog = info.BlogItem{note, noteContent.Content, false}
|
blog = info.BlogItem{note, noteContent.Content, false, info.User{}}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,7 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
|||||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||||
content = noteContent.Abstract
|
content = noteContent.Abstract
|
||||||
}
|
}
|
||||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||||
}
|
}
|
||||||
return count, blogs
|
return count, blogs
|
||||||
}
|
}
|
||||||
@@ -119,23 +121,113 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort
|
|||||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||||
content = noteContent.Abstract
|
content = noteContent.Abstract
|
||||||
}
|
}
|
||||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||||
}
|
}
|
||||||
return count, blogs
|
return count, blogs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------
|
||||||
|
// p
|
||||||
|
// 平台 lea+
|
||||||
|
// 博客列表
|
||||||
|
func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend bool, page, pageSize int, sorterField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||||
|
pageInfo := info.Page{CurPage: page}
|
||||||
|
notes := []info.Note{}
|
||||||
|
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
|
||||||
|
|
||||||
|
// 不是trash的
|
||||||
|
query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne":"欢迎来到leanote!"}}
|
||||||
|
if tag != "" {
|
||||||
|
query["Tags"] = bson.M{"$in": []string{tag}}
|
||||||
|
}
|
||||||
|
// 不是demo的博客
|
||||||
|
demoUserId := configService.GetGlobalStringConfig("demoUserId")
|
||||||
|
if demoUserId != "" {
|
||||||
|
query["UserId"] = bson.M{"$ne": bson.ObjectIdHex(demoUserId)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isRecommend {
|
||||||
|
query["IsRecommend"] = isRecommend
|
||||||
|
}
|
||||||
|
if keywords != "" {
|
||||||
|
query["Title"] = bson.M{"$regex": bson.RegEx{".*?" + keywords + ".*", "i"}}
|
||||||
|
}
|
||||||
|
q := db.Notes.Find(query);
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
|
||||||
|
q.Sort(sortFieldR).
|
||||||
|
Skip(skipNum).
|
||||||
|
Limit(pageSize).
|
||||||
|
All(¬es)
|
||||||
|
|
||||||
|
if(notes == nil || len(notes) == 0) {
|
||||||
|
return pageInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到content, 并且每个都要substring
|
||||||
|
noteIds := make([]bson.ObjectId, len(notes))
|
||||||
|
userIds := make([]bson.ObjectId, len(notes))
|
||||||
|
for i, note := range notes {
|
||||||
|
noteIds[i] = note.NoteId
|
||||||
|
userIds[i] = note.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可以不要的
|
||||||
|
// 直接得到noteContents表的abstract
|
||||||
|
// 这里可能是乱序的
|
||||||
|
/*
|
||||||
|
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||||
|
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
||||||
|
for _, noteContent := range noteContents {
|
||||||
|
noteContentsMap[noteContent.NoteId] = noteContent
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 得到用户信息
|
||||||
|
userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
|
||||||
|
|
||||||
|
// 组装成blogItem
|
||||||
|
// 按照notes的顺序
|
||||||
|
blogs := make([]info.BlogItem, len(noteIds))
|
||||||
|
for i, note := range notes {
|
||||||
|
hasMore := true
|
||||||
|
var content string
|
||||||
|
/*
|
||||||
|
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||||
|
content = noteContent.Abstract
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
blogs[i] = info.BlogItem{note, content, hasMore, userMap[note.UserId]}
|
||||||
|
}
|
||||||
|
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||||
|
|
||||||
|
return pageInfo, blogs
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------
|
//------------------------
|
||||||
// 博客设置
|
// 博客设置
|
||||||
|
func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
|
||||||
|
/*
|
||||||
|
if userBlog.Title == "" {
|
||||||
|
userInfo := userService.GetUserInfo(userBlog)
|
||||||
|
userBlog.Title = userInfo.Username + " 's Blog"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Logo路径问题, 有些有http: 有些没有
|
||||||
|
Log(userBlog.Logo)
|
||||||
|
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
|
||||||
|
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
|
||||||
|
userBlog.Logo = siteUrl + "/" + userBlog.Logo
|
||||||
|
}
|
||||||
|
}
|
||||||
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
||||||
userBlog := info.UserBlog{}
|
userBlog := info.UserBlog{}
|
||||||
db.Get(db.UserBlogs, userId, &userBlog)
|
db.Get(db.UserBlogs, userId, &userBlog)
|
||||||
|
this.fixUserBlog(&userBlog)
|
||||||
if userBlog.Title == "" {
|
|
||||||
userInfo := userService.GetUserInfo(userId)
|
|
||||||
userBlog.Title = userInfo.Username + " 的博客"
|
|
||||||
}
|
|
||||||
|
|
||||||
return userBlog
|
return userBlog
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +237,8 @@ func (this *BlogService) UpdateUserBlog(userBlog info.UserBlog) bool {
|
|||||||
}
|
}
|
||||||
// 修改之UserBlogBase
|
// 修改之UserBlogBase
|
||||||
func (this *BlogService) UpdateUserBlogBase(userId string, userBlog info.UserBlogBase) bool {
|
func (this *BlogService) UpdateUserBlogBase(userId string, userBlog info.UserBlogBase) bool {
|
||||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
ok := db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.UserBlogComment) bool {
|
func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.UserBlogComment) bool {
|
||||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||||
@@ -153,3 +246,326 @@ func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.User
|
|||||||
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
||||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------
|
||||||
|
// 后台管理
|
||||||
|
|
||||||
|
// 推荐博客
|
||||||
|
func (this *BlogService) SetRecommend(noteId string, isRecommend bool) bool {
|
||||||
|
data := bson.M{"IsRecommend": isRecommend}
|
||||||
|
if isRecommend {
|
||||||
|
data["RecommendTime"] = time.Now()
|
||||||
|
}
|
||||||
|
return db.UpdateByQMap(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsBlog": true}, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------
|
||||||
|
// 博客社交, 评论
|
||||||
|
|
||||||
|
// 返回所有liked用户, bool是否还有
|
||||||
|
func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User, bool) {
|
||||||
|
// 默认前5
|
||||||
|
pageSize := 5
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false)
|
||||||
|
|
||||||
|
likes := []info.BlogLike{}
|
||||||
|
query := bson.M{"NoteId": bson.ObjectIdHex(noteId)}
|
||||||
|
q := db.BlogLikes.Find(query);
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
if count == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if isAll {
|
||||||
|
q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&likes)
|
||||||
|
} else {
|
||||||
|
q.Sort(sortFieldR).All(&likes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到所有userIds
|
||||||
|
userIds := make([]bson.ObjectId, len(likes))
|
||||||
|
for i, like := range likes {
|
||||||
|
userIds[i] = like.UserId
|
||||||
|
}
|
||||||
|
// 得到用户信息
|
||||||
|
userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
|
||||||
|
|
||||||
|
users := make([]info.User, len(likes));
|
||||||
|
for i, like := range likes {
|
||||||
|
users[i] = userMap[like.UserId]
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, count > pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogService) IsILikeIt(noteId, userId string) bool {
|
||||||
|
if userId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if db.Has(db.BlogLikes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阅读次数统计+1
|
||||||
|
func (this *BlogService) IncReadNum(noteId string) bool {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if note.IsBlog {
|
||||||
|
return db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"ReadNum": 1}})
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点赞
|
||||||
|
// retun ok , isLike
|
||||||
|
func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool) {
|
||||||
|
ok = false
|
||||||
|
isLike = false
|
||||||
|
if noteId == "" || userId == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 判断是否点过赞, 如果点过那么取消点赞
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if !note.IsBlog /*|| note.UserId.Hex() == userId */{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
noteIdO := bson.ObjectIdHex(noteId)
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
var n int
|
||||||
|
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
|
||||||
|
n = 1
|
||||||
|
// 添加之
|
||||||
|
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
|
||||||
|
isLike = true
|
||||||
|
} else {
|
||||||
|
// 已点过, 那么删除之
|
||||||
|
n = -1
|
||||||
|
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
|
||||||
|
isLike = false
|
||||||
|
}
|
||||||
|
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 评论
|
||||||
|
// 在noteId博客下userId 给toUserId评论content
|
||||||
|
// commentId可为空(针对某条评论评论)
|
||||||
|
func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (bool, info.BlogComment) {
|
||||||
|
var comment info.BlogComment
|
||||||
|
if content == "" {
|
||||||
|
return false, comment
|
||||||
|
}
|
||||||
|
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if !note.IsBlog {
|
||||||
|
return false, comment
|
||||||
|
}
|
||||||
|
|
||||||
|
comment = info.BlogComment{CommentId: bson.NewObjectId(),
|
||||||
|
NoteId: bson.ObjectIdHex(noteId),
|
||||||
|
UserId: bson.ObjectIdHex(userId),
|
||||||
|
Content: content,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
var comment2 = info.BlogComment{}
|
||||||
|
if toCommentId != "" {
|
||||||
|
comment2 = info.BlogComment{}
|
||||||
|
db.Get(db.BlogComments, toCommentId, &comment2)
|
||||||
|
if comment2.CommentId != "" {
|
||||||
|
comment.ToCommentId = comment2.CommentId
|
||||||
|
comment.ToUserId = comment2.UserId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// comment.ToUserId = note.UserId
|
||||||
|
}
|
||||||
|
ok := db.Insert(db.BlogComments, comment)
|
||||||
|
if ok {
|
||||||
|
// 评论+1
|
||||||
|
db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": 1}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId != note.UserId.Hex() || toCommentId != "" {
|
||||||
|
go func() {
|
||||||
|
this.sendEmail(note, comment2, userId, content);
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok, comment
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送email
|
||||||
|
func (this *BlogService) sendEmail(note info.Note, comment info.BlogComment, userId, content string) {
|
||||||
|
emailService.SendCommentEmail(note, comment, userId, content);
|
||||||
|
/*
|
||||||
|
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 += " 的评论";
|
||||||
|
}
|
||||||
|
|
||||||
|
body := "{header}<b>评论内容</b>: <br /><blockquote>" + content + "</blockquote>";
|
||||||
|
href := "http://"+ configService.GetBlogDomain() + "/view/" + note.NoteId.Hex()
|
||||||
|
body += "<br /><b>博客链接</b>: <a href='" + href + "'>" + href + "</a>{footer}";
|
||||||
|
|
||||||
|
emailService.SendEmail(toUserInfo.Email, subject, body)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// 作者(或管理员)可以删除所有评论
|
||||||
|
// 自己可以删除评论
|
||||||
|
func (this *BlogService) DeleteComment(noteId, commentId, userId string) bool {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if !note.IsBlog {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := info.BlogComment{}
|
||||||
|
db.Get(db.BlogComments, commentId, &comment)
|
||||||
|
|
||||||
|
if comment.CommentId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if userId == adminUserId || note.UserId.Hex() == userId || comment.UserId.Hex() == userId {
|
||||||
|
if db.Delete(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}) {
|
||||||
|
// 评论-1
|
||||||
|
db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": -1}})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点赞/取消赞
|
||||||
|
func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike bool, num int) {
|
||||||
|
ok = false
|
||||||
|
isILike = false
|
||||||
|
num = 0
|
||||||
|
comment := info.BlogComment{}
|
||||||
|
|
||||||
|
db.Get(db.BlogComments, commentId, &comment)
|
||||||
|
|
||||||
|
var n int
|
||||||
|
if comment.LikeUserIds != nil && len(comment.LikeUserIds) > 0 && InArray(comment.LikeUserIds, userId) {
|
||||||
|
n = -1
|
||||||
|
// 从点赞名单删除
|
||||||
|
db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)},
|
||||||
|
bson.M{"$pull": bson.M{"LikeUserIds": userId}})
|
||||||
|
isILike = false
|
||||||
|
} else {
|
||||||
|
n = 1
|
||||||
|
// 添加之
|
||||||
|
db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)},
|
||||||
|
bson.M{"$push": bson.M{"LikeUserIds": userId}})
|
||||||
|
isILike = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.LikeUserIds == nil {
|
||||||
|
num = 0
|
||||||
|
} else {
|
||||||
|
num = len(comment.LikeUserIds) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = db.Update(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)},
|
||||||
|
bson.M{"$set": bson.M{"LikeNum": num}})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 评论列表
|
||||||
|
// userId主要是显示userId是否点过某评论的赞
|
||||||
|
// 还要获取用户信息
|
||||||
|
func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.User) {
|
||||||
|
pageInfo := info.Page{CurPage: page}
|
||||||
|
|
||||||
|
comments2 := []info.BlogComment{}
|
||||||
|
|
||||||
|
skipNum, sortFieldR := parsePageAndSort(page, pageSize, "CreatedTime", false)
|
||||||
|
|
||||||
|
query := bson.M{"NoteId": bson.ObjectIdHex(noteId)}
|
||||||
|
q := db.BlogComments.Find(query);
|
||||||
|
|
||||||
|
// 总记录数
|
||||||
|
count, _ := q.Count()
|
||||||
|
q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&comments2)
|
||||||
|
|
||||||
|
if(len(comments2) == 0) {
|
||||||
|
return pageInfo, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
comments := make([]info.BlogCommentPublic, len(comments2))
|
||||||
|
// 我是否点过赞呢?
|
||||||
|
for i, comment := range comments2 {
|
||||||
|
comments[i].BlogComment = comment
|
||||||
|
if comment.LikeNum > 0 && comment.LikeUserIds != nil && len(comment.LikeUserIds) > 0 && InArray(comment.LikeUserIds, userId) {
|
||||||
|
comments[i].IsILikeIt = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
note := noteService.GetNoteById(noteId);
|
||||||
|
|
||||||
|
// 得到用户信息
|
||||||
|
userIdsMap := map[bson.ObjectId]bool{note.UserId: true}
|
||||||
|
for _, comment := range comments {
|
||||||
|
userIdsMap[comment.UserId] = true
|
||||||
|
if comment.ToUserId != "" { // 可能为空
|
||||||
|
userIdsMap[comment.ToUserId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userIds := make([]bson.ObjectId, len(userIdsMap))
|
||||||
|
i := 0
|
||||||
|
for userId, _ := range userIdsMap {
|
||||||
|
userIds[i] = userId
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户信息
|
||||||
|
userMap := userService.MapUserInfoByUserIds(userIds)
|
||||||
|
userMap2 := make(map[string]info.User, len(userMap))
|
||||||
|
for userId, v := range userMap {
|
||||||
|
userMap2[userId.Hex()] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||||
|
|
||||||
|
return pageInfo, comments, userMap2
|
||||||
|
}
|
||||||
|
|
||||||
|
// 举报
|
||||||
|
func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool) {
|
||||||
|
note := noteService.GetNoteById(noteId)
|
||||||
|
if !note.IsBlog {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
report := info.Report{ReportId: bson.NewObjectId(),
|
||||||
|
NoteId: bson.ObjectIdHex(noteId),
|
||||||
|
UserId: bson.ObjectIdHex(userId),
|
||||||
|
Reason: reason,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
if commentId != "" {
|
||||||
|
report.CommentId = bson.ObjectIdHex(commentId)
|
||||||
|
}
|
||||||
|
return db.Insert(db.Reports, report)
|
||||||
|
}
|
||||||
@@ -0,0 +1,541 @@
|
|||||||
|
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 {
|
||||||
|
// 全局的
|
||||||
|
GlobalAllConfigs map[string]interface{}
|
||||||
|
GlobalStringConfigs map[string]string
|
||||||
|
GlobalArrayConfigs map[string][]string
|
||||||
|
GlobalMapConfigs map[string]map[string]string
|
||||||
|
GlobalArrMapConfigs map[string][]map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
var adminUserId = ""
|
||||||
|
|
||||||
|
// appStart时 将全局的配置从数据库中得到作为全局
|
||||||
|
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||||
|
this.GlobalAllConfigs = map[string]interface{}{}
|
||||||
|
this.GlobalStringConfigs = map[string]string{}
|
||||||
|
this.GlobalArrayConfigs = map[string][]string{}
|
||||||
|
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||||
|
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||||
|
|
||||||
|
adminUsername, _ := revel.Config.String("adminUsername")
|
||||||
|
if adminUsername == "" {
|
||||||
|
adminUsername = "admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo := userService.GetUserInfoByAny(adminUsername)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
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) 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(adminUserId, "registerSharedUserId", "")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
user := userService.GetUserInfo(registerSharedUserId)
|
||||||
|
if user.UserId == "" {
|
||||||
|
ok = false
|
||||||
|
msg = "no such user: " + registerSharedUserId
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.UpdateGlobalStringConfig(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(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(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(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(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-10-25/ -u leanote -p xx
|
||||||
|
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(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(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
|
||||||
|
}
|
||||||
@@ -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 := siteUrl + "/user/activeEmail?token=" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
|
"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 := siteUrl + "/user/updateEmail?token=" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
|
"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 := siteUrl + "/findPassword/" + token
|
||||||
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
|
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl,
|
||||||
|
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
||||||
|
|
||||||
|
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": siteUrl,
|
||||||
|
"registerUrl": siteUrl + "/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": siteUrl, "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"] = siteUrl;
|
||||||
|
|
||||||
|
// 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,236 @@
|
|||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
|
||||||
|
|
||||||
|
type FileService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// add Image
|
||||||
|
func (this *FileService) AddImage(image info.File, albumId, userId string) bool {
|
||||||
|
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)
|
||||||
|
|
||||||
|
return db.Insert(db.Files, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 string) string {
|
||||||
|
if fileId == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
file := info.File{}
|
||||||
|
db.Get(db.Files, fileId, &file)
|
||||||
|
path := file.Path
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 判断权限
|
||||||
|
|
||||||
|
// 是否是我的文件
|
||||||
|
if userId != "" && file.UserId.Hex() == userId {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到使用过该fileId的所有笔记NoteId
|
||||||
|
// 这些笔记是否有public的, 若有则ok
|
||||||
|
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
|
||||||
|
|
||||||
|
noteIds := noteImageService.GetNoteIds(fileId)
|
||||||
|
if noteIds != nil && len(noteIds) > 0 {
|
||||||
|
// 这些笔记是否有public的
|
||||||
|
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若有共享给我的笔记?
|
||||||
|
if 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)
|
||||||
|
|
||||||
|
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)})
|
||||||
|
}
|
||||||
@@ -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,102 @@
|
|||||||
|
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" />
|
||||||
|
// 图片必须是我的, 不然不添加
|
||||||
|
func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
|
||||||
|
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;
|
||||||
|
}
|
||||||
+75
-12
@@ -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,12 @@ 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
|
||||||
}
|
}
|
||||||
|
// 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) {
|
||||||
@@ -120,13 +126,21 @@ func (this *NoteService) AddNote(note info.Note) info.Note {
|
|||||||
note.UpdatedUserId = note.UserId
|
note.UpdatedUserId = note.UserId
|
||||||
|
|
||||||
// 设为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,6 +162,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,11 +255,23 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
|||||||
Content: content,
|
Content: content,
|
||||||
UpdatedTime: time.Now(),
|
UpdatedTime: time.Now(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 更新笔记图片
|
||||||
|
noteImageService.UpdateNoteImages(userId, noteId, 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 {
|
||||||
@@ -254,6 +284,9 @@ func (this *NoteService) UpdateTags(noteId string, userId string, tags []string)
|
|||||||
// 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 +294,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 +348,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 +360,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 +379,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,8 +411,10 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +456,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 +478,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 +502,18 @@ 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() int {
|
||||||
|
return db.Count(db.Notes, bson.M{"IsTrash": false})
|
||||||
|
}
|
||||||
|
func (this *NoteService) CountBlog() int {
|
||||||
|
return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false})
|
||||||
|
}
|
||||||
@@ -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,32 +47,41 @@ 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] {
|
||||||
|
final[i] = each
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 最后排序
|
// 最后排序
|
||||||
if needSort {
|
if needSort {
|
||||||
@@ -87,6 +96,11 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
// 得到用户下所有的notebook
|
// 得到用户下所有的notebook
|
||||||
// 排序好之后返回
|
// 排序好之后返回
|
||||||
@@ -159,11 +173,15 @@ func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdat
|
|||||||
|
|
||||||
// 如果有IsBlog之类的, 需要特殊处理
|
// 如果有IsBlog之类的, 需要特殊处理
|
||||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||||
// 设为blog/取消
|
// 设为blog/取消, 把它下面所有的note都设为isBlog
|
||||||
if is, ok2 := isBlog.(bool); ok2 {
|
if is, ok2 := isBlog.(bool); ok2 {
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||||
db.UpdateByQMap(db.Notes, q, bson.M{"IsBlog": is})
|
data := bson.M{"IsBlog": is}
|
||||||
|
if is {
|
||||||
|
data["PublicTime"] = time.Now()
|
||||||
|
}
|
||||||
|
db.UpdateByQMap(db.Notes, q, data)
|
||||||
|
|
||||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||||
// 先查该notebook下所有notes, 得到id
|
// 先查该notebook下所有notes, 得到id
|
||||||
@@ -182,14 +200,20 @@ func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdat
|
|||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查看是否有子notebook
|
||||||
// 先查看该notebookId下是否有notes, 没有则删除
|
// 先查看该notebookId下是否有notes, 没有则删除
|
||||||
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
||||||
|
if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
|
||||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
"UserId": bson.ObjectIdHex(userId),
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false}) == 0 { // 不包含trash
|
"IsTrash": false}) == 0 { // 不包含trash
|
||||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||||
}
|
}
|
||||||
return false, "笔记本下有笔记"
|
return false, "笔记本下有笔记"
|
||||||
|
} else {
|
||||||
|
return false, "笔记本下有子笔记本"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
@@ -209,3 +233,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,71 @@
|
|||||||
|
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()})
|
||||||
|
}
|
||||||
|
// 注销时清空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
|
||||||
|
}
|
||||||
@@ -3,8 +3,8 @@ 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"
|
||||||
)
|
)
|
||||||
@@ -286,6 +286,28 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
|||||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updatedUserId是否有查看userId noteId的权限?
|
||||||
|
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
||||||
|
if !db.Has(db.ShareNotes,
|
||||||
|
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
|
||||||
|
// noteId的notebookId是否被共享了?
|
||||||
|
notebookId := noteService.GetNotebookId(noteId)
|
||||||
|
if notebookId.Hex() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断notebook是否被共享
|
||||||
|
if !db.Has(db.ShareNotebooks,
|
||||||
|
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// updatedUserId是否有修改userId noteId的权限?
|
// updatedUserId是否有修改userId noteId的权限?
|
||||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||||
// 1. noteId是否被共享了?
|
// 1. noteId是否被共享了?
|
||||||
@@ -334,14 +356,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),
|
||||||
})
|
})
|
||||||
@@ -355,7 +377,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
|||||||
noteContent = info.NoteContent{}
|
noteContent = info.NoteContent{}
|
||||||
// 是否单独共享了该notebook
|
// 是否单独共享了该notebook
|
||||||
// 或者, 其notebook共享了我
|
// 或者, 其notebook共享了我
|
||||||
if this.hasSharedNote(noteId, myUserId) || this.hasSharedNotebook(noteId, myUserId, sharedUserId) {
|
if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
|
||||||
db.Get(db.NoteContents, noteId, ¬eContent)
|
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
@@ -508,3 +530,50 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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,27 @@
|
|||||||
|
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 {
|
||||||
|
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||||
|
Log(note.NoteId.Hex())
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
+115
-59
@@ -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}");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,13 +64,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 = siteUrl + "/" + 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 +96,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 +111,27 @@ 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)
|
||||||
|
}
|
||||||
|
|
||||||
// 通过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 {
|
||||||
@@ -132,7 +168,7 @@ 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, "用户已存在"
|
||||||
}
|
}
|
||||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||||
@@ -148,6 +184,12 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
|||||||
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) {
|
||||||
@@ -168,57 +210,6 @@ func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
|||||||
//---------------
|
//---------------
|
||||||
// 修改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://115.28.133.226/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{}
|
||||||
@@ -280,15 +271,80 @@ 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 != "" {
|
||||||
|
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
|
||||||
|
}
|
||||||
|
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{})
|
||||||
|
}
|
||||||
+65
-20
@@ -1,31 +1,76 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 tagService, TagS *TagService
|
||||||
var blogService *BlogService
|
var blogService, BlogS *BlogService
|
||||||
var tokenService *TokenService
|
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
|
||||||
|
|
||||||
func init() {
|
var siteUrl string
|
||||||
notebookService = &NotebookService{}
|
|
||||||
noteService = &NoteService{}
|
// onAppStart调用
|
||||||
noteContentHistoryService = &NoteContentHistoryService{}
|
func InitService() {
|
||||||
trashService = &TrashService{}
|
NotebookS = &NotebookService{}
|
||||||
shareService = &ShareService{}
|
NoteS = &NoteService{}
|
||||||
userService = &UserService{}
|
NoteContentHistoryS = &NoteContentHistoryService{}
|
||||||
tagService = &TagService{}
|
TrashS = &TrashService{}
|
||||||
blogService = &BlogService{}
|
ShareS = &ShareService{}
|
||||||
tokenService = &TokenService{}
|
UserS = &UserService{}
|
||||||
|
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{}
|
||||||
|
|
||||||
|
notebookService = NotebookS
|
||||||
|
noteService = NoteS
|
||||||
|
noteContentHistoryService = NoteContentHistoryS
|
||||||
|
trashService = TrashS
|
||||||
|
shareService = ShareS
|
||||||
|
userService = UserS
|
||||||
|
tagService = TagS
|
||||||
|
blogService = BlogS
|
||||||
|
tokenService = TokenS
|
||||||
|
noteImageService = NoteImageS
|
||||||
|
fileService = FileS
|
||||||
|
albumService = AlbumS
|
||||||
|
attachService = AttachS
|
||||||
|
configService = ConfigS
|
||||||
|
emailService = EmailS
|
||||||
|
sessionService = SessionS
|
||||||
|
|
||||||
|
//
|
||||||
|
siteUrl, _ = revel.Config.String("site.url")
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
"github.com/leanote/leanote/app/lea/html2image"
|
"github.com/leanote/leanote/app/lea/html2image"
|
||||||
"time"
|
"time"
|
||||||
"fmt"
|
"fmt"
|
||||||
"labix.org/v2/mgo/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
// "labix.org/v2/mgo"
|
// "gopkg.in/mgo.v2"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
// "strings"
|
// "strings"
|
||||||
)
|
)
|
||||||
@@ -181,8 +181,16 @@ make<br>make --- install</pre>
|
|||||||
`, "/Users/life/Desktop/a.png")
|
`, "/Users/life/Desktop/a.png")
|
||||||
fmt.Printf("time cost %v\n", time.Now().Sub(start))
|
fmt.Printf("time cost %v\n", time.Now().Sub(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testLea() {
|
||||||
|
names := ListDir("/Users/life/Documents/Go/package/src/leanote")
|
||||||
|
fmt.Println(names);
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
revel.BasePath = "/Users/life/Documents/Go/package/src/leanote"
|
revel.BasePath = "/Users/life/Documents/Go/package/src/leanote"
|
||||||
|
// testLea();
|
||||||
|
|
||||||
// a, b := SplitFilename("http://ab/c/a.gif#??")
|
// a, b := SplitFilename("http://ab/c/a.gif#??")
|
||||||
// println(a)
|
// println(a)
|
||||||
// println(b)
|
// println(b)
|
||||||
@@ -199,7 +207,7 @@ func main() {
|
|||||||
//_, err := mgo.Dial("mongodb://leanote:nKFAkxKnWkEQy8Vv2LlM@115.28.133.226:27017/leanote")
|
//_, err := mgo.Dial("mongodb://leanote:nKFAkxKnWkEQy8Vv2LlM@115.28.133.226:27017/leanote")
|
||||||
|
|
||||||
// testNotebookService();
|
// testNotebookService();
|
||||||
testNoteService();
|
// testNoteService();
|
||||||
// testShareService()
|
// testShareService()
|
||||||
// testAuthService()
|
// testAuthService()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Blog</h3></div>
|
||||||
|
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="row wrapper">
|
||||||
|
<div class="col-sm-5 m-b-xs">
|
||||||
|
<button class="btn btn-sm btn-default">
|
||||||
|
Action1
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-default">
|
||||||
|
Action2
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 m-b-xs">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="input-group search-group">
|
||||||
|
<input type="text" class="input-sm form-control" placeholder="Title" id="keywords" value="{{.keywords}}" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-sm btn-default" type="button" data-url="/adminBlog/index">Search</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped b-t b-light">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="20">
|
||||||
|
<input type="checkbox">
|
||||||
|
</th>
|
||||||
|
{{$url := urlConcat "/adminBlog/index" "keywords" .keywords}}
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "title" .sorter}}
|
||||||
|
>
|
||||||
|
Title
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "userId" .sorter}}
|
||||||
|
>
|
||||||
|
Username
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "createdTime" .sorter}}
|
||||||
|
>
|
||||||
|
Create Date
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .blogs}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="post[]" value="2">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/blog/view/{{.NoteId.Hex}}" target="_blank">{{.Title|raw}}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/blog/{{.UserId.Hex}}" target="_blank">
|
||||||
|
{{.User.Username}}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.CreatedTime|datetime}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4 hidden-xs">
|
||||||
|
<button class="btn btn-sm btn-default">
|
||||||
|
Action1
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-default">
|
||||||
|
Action2
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 text-center">
|
||||||
|
<small class="text-muted inline m-t-sm m-b-sm">
|
||||||
|
showing 20-30 of 50 items
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 text-right text-center-xs">
|
||||||
|
{{set . "url" (urlConcat "/adminBlog/index" "sorter" .sorter "keywords" .keywords)}}
|
||||||
|
{{template "admin/user/page.html" .}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$(".change-recommend").click(function() {
|
||||||
|
var isRecommend = +$(this).data("recommend");
|
||||||
|
var noteId = $(this).data("id");
|
||||||
|
var t = this;
|
||||||
|
$(t).button("loading");
|
||||||
|
ajaxGet("/adminBlog/setRecommend", {noteId: noteId, recommend: !isRecommend}, function() {
|
||||||
|
$(t).button("reset");
|
||||||
|
$(t).text(isRecommend ? "N" : "Y");
|
||||||
|
$(t).data("recommend", !isRecommend);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{{if gt .pageInfo.TotalPage 1}}
|
||||||
|
<ul class="pagination pagination-sm m-t-none m-b-none">
|
||||||
|
<li class="{{if eq $.pageInfo.CurPage 1}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq $.pageInfo.CurPage 1}}javascript:;{{else}}{{sub $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-left">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{{range $i := N 1 .pageInfo.TotalPage}}
|
||||||
|
{{if eq $i $.pageInfo.CurPage}}
|
||||||
|
<li class="active">
|
||||||
|
<a href="javascript:;">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="">
|
||||||
|
<a href="{{urlConcat $.url "page" $i}}">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<li class="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}javascript:;{{else}}{{add $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-right">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Mongodb Tool Configuration</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="data_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>mongodump path</label>
|
||||||
|
<input type="text" class="form-control" name="mongodumpPath" value="{{.str.mongodumpPath}}" placeholder="">
|
||||||
|
Please input the bin mongodump's absolute path
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>mongorestore path</label>
|
||||||
|
<input type="text" class="form-control" name="mongorestorePath" value="{{.str.mongorestorePath}}" placeholder="">
|
||||||
|
Please input the bin mongorestore's absolute path
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#data_form");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#data_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/mongodb", getFormJsonData("data_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Backup & Restore</h3></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.break-all {
|
||||||
|
word-break:break-all; /*支持IE,chrome,FF不支持*/
|
||||||
|
word-wrap:break-word;/*支持IE,chrome,FF*/
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section class="panel panel-default">
|
||||||
|
|
||||||
|
<div class="row wrapper">
|
||||||
|
<div class="col-sm-5 m-b-xs">
|
||||||
|
<button class="btn btn-primary backup-btn">Backup</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped b-t b-light">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="136px">
|
||||||
|
Date
|
||||||
|
</th>
|
||||||
|
<th width="">
|
||||||
|
Remark
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Path
|
||||||
|
</th>
|
||||||
|
<th width="170px">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $each := .backups}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{$each.createdTime|unixDatetime}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<textarea class="remark" data-id="{{$each.createdTime}}">{{$each.remark}}</textarea>
|
||||||
|
</td>
|
||||||
|
<td class="break-all">
|
||||||
|
{{$each.path}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button href="#" class="btn btn-sm btn-danger restore-btn" data-id="{{$each.createdTime}}">Restore</button>
|
||||||
|
<a class="btn btn-sm btn-default download-attach" href="/adminData/download?createdTime={{$each.createdTime}}" target="_blank" title="Download" data-id=""><i class="fa fa-download"></i></a>
|
||||||
|
<button class="btn btn-sm btn-warning delete-btn" title="Delete" data-id="{{$each.createdTime}}"><i class="fa fa-trash-o"></i></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$(".backup-btn").click(function(){
|
||||||
|
ajaxGet("/adminData/backup", {}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 还原
|
||||||
|
$(".restore-btn").click(function() {
|
||||||
|
var createdTime = $(this).data("id");
|
||||||
|
art.confirm("Are you sure? <br />Note. Leanote will do the following steps: <br />1)Backup the current database first. <br />2) And then delete the database. <br />3) Restore database from the selected version.", function() {
|
||||||
|
ajaxGet("/adminData/restore", {createdTime: createdTime}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(".delete-btn").click(function() {
|
||||||
|
var createdTime = $(this).data("id");
|
||||||
|
art.confirm("Are you sure?", function() {
|
||||||
|
ajaxGet("/adminData/delete", {createdTime: createdTime}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(".remark").change(function() {
|
||||||
|
var createdTime = $(this).data("id");
|
||||||
|
var remark = $(this).val();
|
||||||
|
ajaxPost("/adminData/updateRemark", {createdTime: createdTime, remark: remark}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
art.tips("Update Remark Success");
|
||||||
|
} else {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<div class="row" style="width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
overflow-y: scroll;">
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<form id="sendEmailForm">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading font-bold">Email</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email List</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emails">{{.emailsNl}}</textarea>
|
||||||
|
input email line by line
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Select Old Email</label>
|
||||||
|
<select class="form-control old-emails">
|
||||||
|
<option value="">---Select---</option>
|
||||||
|
{{range $subject, $body := .map.oldEmails}}
|
||||||
|
<option>
|
||||||
|
{{$subject}}
|
||||||
|
</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" id="latestEmailSubject" name="latestEmailSubject" value="{{$.str.latestEmailSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" id="latestEmailBody" class="form-control" name="latestEmailBody">{{$.str.latestEmailBody}}</textarea>
|
||||||
|
</div>
|
||||||
|
<label class="checkbox-inline"> <input type="checkbox" id="saveAsOldEmail" name="saveAsOldEmail" value="1"> Save As Old Email </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submitEmail" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var oldEmails = eval("(" + {{json .map.oldEmails}} + ")");
|
||||||
|
$(function() {
|
||||||
|
$(".old-emails").change(function() {
|
||||||
|
var subject = $(this).val();
|
||||||
|
var body = oldEmails[subject];
|
||||||
|
if(subject) {
|
||||||
|
$("#latestEmailSubject").val(subject);
|
||||||
|
$("#latestEmailBody").val(body);
|
||||||
|
$("#saveAsOldEmail").prop("checked", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#submitEmail").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminEmail/sendToUsers2", getFormJsonData("sendEmailForm"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Email Logs</h3></div>
|
||||||
|
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="row wrapper">
|
||||||
|
<div class="col-sm-5 m-b-xs">
|
||||||
|
<button class="btn btn-sm btn-default bulk-send">
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-default bulk-delete">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 m-b-xs">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="input-group search-group">
|
||||||
|
<input type="text" class="input-sm form-control" placeholder="Email" id="keywords" value="{{.keywords}}" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-sm btn-default" type="button" data-url="/adminEmail/list">Search</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped b-t b-light">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="20">
|
||||||
|
<input type="checkbox">
|
||||||
|
</th>
|
||||||
|
{{$url := urlConcat "/adminEmail/list" "keywords" .keywords}}
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "email" .sorter}}
|
||||||
|
>
|
||||||
|
Email
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "subject" .sorter}}
|
||||||
|
>
|
||||||
|
Subject
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "ok" .sorter}}
|
||||||
|
>
|
||||||
|
Ok
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "msg" .sorter}}
|
||||||
|
>
|
||||||
|
Msg
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "createdTime" .sorter}}
|
||||||
|
>
|
||||||
|
Date
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .emails}}
|
||||||
|
<tr id="tr_{{.LogId.Hex}}">
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" class="ck" data-email="{{.Email}}" data-id="{{.LogId.Hex}}">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.Email}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.Subject}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.Ok}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.Msg}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.CreatedTime|datetime}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="btn btn-default send-email" data-email="{{.Email}}">Send</a>
|
||||||
|
<a href="#" class="btn btn-default delete-email" data-id="{{.LogId.Hex}}">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4 hidden-xs">
|
||||||
|
<button class="btn btn-sm btn-default bulk-send">
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-default bulk-delete">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 text-right text-center-xs">
|
||||||
|
{{set . "url" (urlConcat "/adminEmail/list" "sorter" .sorter "keywords" .keywords)}}
|
||||||
|
{{template "admin/user/page.html" .}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$(".send-email").click(function() {
|
||||||
|
openSendEmailDialog($(this).data("email"));
|
||||||
|
});
|
||||||
|
$(".bulk-send").click(function() {
|
||||||
|
var emails = [];
|
||||||
|
$(".ck:checked").each(function() {
|
||||||
|
emails.push($(this).data("email"));
|
||||||
|
});
|
||||||
|
if(emails.length == 0) {
|
||||||
|
art.alert("No user");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openSendEmailDialog(emails.join(","));
|
||||||
|
});
|
||||||
|
|
||||||
|
function deleteEmails(ids) {
|
||||||
|
if(!isArray(ids)) {
|
||||||
|
ids = [ids];
|
||||||
|
}
|
||||||
|
ajaxPost("/adminEmail/deleteEmails", {ids: ids.join(",")}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
if(ids.length > 8) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
for(var i in ids) {
|
||||||
|
$("#tr_" + ids[i]).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".delete-email").click(function() {
|
||||||
|
var id = $(this).data('id');
|
||||||
|
deleteEmails(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".bulk-delete").click(function() {
|
||||||
|
var ids = [];
|
||||||
|
$(".ck:checked").each(function() {
|
||||||
|
ids.push($(this).data("id"));
|
||||||
|
});
|
||||||
|
if(ids.length == 0) {
|
||||||
|
art.alert("No email");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deleteEmails(ids);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{{if gt .pageInfo.TotalPage 1}}
|
||||||
|
<ul class="pagination pagination-sm m-t-none m-b-none">
|
||||||
|
<li class="{{if eq $.pageInfo.CurPage 1}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq $.pageInfo.CurPage 1}}javascript:;{{else}}{{sub $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-left">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{{range $i := N 1 .pageInfo.TotalPage}}
|
||||||
|
{{if eq $i $.pageInfo.CurPage}}
|
||||||
|
<li class="active">
|
||||||
|
<a href="javascript:;">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="">
|
||||||
|
<a href="{{urlConcat $.url "page" $i}}">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<li class="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}javascript:;{{else}}{{add $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-right">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Send Email</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<form id="formContainer">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading font-bold">Email</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email List</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="sendEmails">{{.str.sendEmails}}</textarea>
|
||||||
|
input email line by line
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Select Old Email</label>
|
||||||
|
<select class="form-control old-emails">
|
||||||
|
<option value="">---Select---</option>
|
||||||
|
{{range $subject, $body := .map.oldEmails}}
|
||||||
|
<option>
|
||||||
|
{{$subject}}
|
||||||
|
</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" id="latestEmailSubject" name="latestEmailSubject" value="{{$.str.latestEmailSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" id="latestEmailBody" class="form-control" name="latestEmailBody">{{$.str.latestEmailBody}}</textarea>
|
||||||
|
</div>
|
||||||
|
<label class="checkbox-inline"> <input type="checkbox" id="saveAsOldEmail" name="saveAsOldEmail" value="1"> Save As Old Email </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
var oldEmails = eval("(" + {{json .map.oldEmails}} + ")");
|
||||||
|
$(function() {
|
||||||
|
init_validator("#formContainer");
|
||||||
|
|
||||||
|
$(".old-emails").change(function() {
|
||||||
|
var subject = $(this).val();
|
||||||
|
var body = oldEmails[subject];
|
||||||
|
if(subject) {
|
||||||
|
$("#latestEmailSubject").val(subject);
|
||||||
|
$("#latestEmailBody").val(body);
|
||||||
|
$("#saveAsOldEmail").prop("checked", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#formContainer").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminEmail/sendEmailToEmails", getFormJsonData("formContainer"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Send Email to Users</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<form id="formContainer">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading font-bold">User filter</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Search Email/Username</label>
|
||||||
|
<input type="text" class="form-control" name="userFilterEmail" value="{{.str.userFilterEmail}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="checkbox-inline"> <input type="checkbox" name="verified" value="1"> Verfied </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>White List</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="userFilterWhiteList">{{.str.userFilterWhiteList}}</textarea>
|
||||||
|
input email line by line
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Black List</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="userFilterBlackList">{{.str.userFilterBlackList}}</textarea>
|
||||||
|
input email line by line
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading font-bold">Email</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Select Old Email</label>
|
||||||
|
<select class="form-control old-emails">
|
||||||
|
<option value="">---Select---</option>
|
||||||
|
{{range $subject, $body := .map.oldEmails}}
|
||||||
|
<option>
|
||||||
|
{{$subject}}
|
||||||
|
</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" id="latestEmailSubject" name="latestEmailSubject" value="{{$.str.latestEmailSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" id="latestEmailBody" class="form-control" name="latestEmailBody">{{$.str.latestEmailBody}}</textarea>
|
||||||
|
</div>
|
||||||
|
<label class="checkbox-inline"> <input type="checkbox" id="saveAsOldEmail" name="saveAsOldEmail" value="1"> Save As Old Email </label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
var oldEmails = eval("(" + {{json .map.oldEmails}} + ")");
|
||||||
|
$(function() {
|
||||||
|
init_validator("#formContainer");
|
||||||
|
|
||||||
|
$(".old-emails").change(function() {
|
||||||
|
var subject = $(this).val();
|
||||||
|
var body = oldEmails[subject];
|
||||||
|
if(subject) {
|
||||||
|
$("#latestEmailSubject").val(subject);
|
||||||
|
$("#latestEmailBody").val(body);
|
||||||
|
$("#saveAsOldEmail").prop("checked", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#formContainer").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminEmail/sendToUsers", getFormJsonData("formContainer"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Email Configuration</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Host</label>
|
||||||
|
<input type="text" class="form-control" name="emailHost" value="{{.str.emailHost}}" placeholder="eg. smtp.ym.163.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Port</label>
|
||||||
|
<input type="text" class="form-control" name="emailPort" value="{{.str.emailPort}}" placeholder="eg. 25">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Username</label>
|
||||||
|
<input type="text" class="form-control" name="emailUsername" value="{{.str.emailUsername}}" placeholder="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<input type="text" class="form-control" name="emailPassword" value="{{.str.emailPassword}}" placeholder="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#add_user_form");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#add_user_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminEmail/set", getFormJsonData("add_user_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Email Template</h3></div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.preview {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading bg-light">
|
||||||
|
<ul class="nav nav-tabs nav-justified">
|
||||||
|
<li class="active"><a href="#tab1" data-toggle="tab">Layout</a></li>
|
||||||
|
<li class=""><a href="#tab2" data-toggle="tab">Register</a></li>
|
||||||
|
<li class=""><a href="#tab3" data-toggle="tab">Update Email</a></li>
|
||||||
|
<li ><a href="#tab4" data-toggle="tab">Find Passord</a></li>
|
||||||
|
<li ><a href="#tab5" data-toggle="tab">Invite Register</a></li>
|
||||||
|
<li ><a href="#tab6" data-toggle="tab">Blog Comment</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="tab1">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Layout</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>$.subject</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Header</label>
|
||||||
|
<textarea type="text" id="emailHeader" rows="10" class="form-control" name="emailTemplateHeader">{{.str.emailTemplateHeader}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Footer</label>
|
||||||
|
<textarea type="text" id="emailFooter" rows="10" class="form-control" name="emailTemplateFooter">{{.str.emailTemplateFooter}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab2">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Register Welcome And Email Validation:</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>header</code>
|
||||||
|
<code>footer</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
<code>$.tokenUrl</code>
|
||||||
|
<code>$.token</code>
|
||||||
|
<code>$.tokenTimeout</code>
|
||||||
|
<code>$.user.userId</code>
|
||||||
|
<code>$.user.email</code>
|
||||||
|
<code>$.user.username</code>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" name="emailTemplateRegisterSubject" value="{{.str.emailTemplateRegisterSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emailTemplateRegister">{{.str.emailTemplateRegister}}</textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Preview
|
||||||
|
<div class="preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Update Email and Send Active Email</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>header</code>
|
||||||
|
<code>footer</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
<code>$.tokenUrl</code>
|
||||||
|
<code>$.token</code>
|
||||||
|
<code>$.tokenTimeout</code>
|
||||||
|
<code>$.user.userId</code>
|
||||||
|
<code>$.user.email</code>
|
||||||
|
<code>$.user.username</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" name="emailTemplateUpdateEmailSubject" value="{{.str.emailTemplateUpdateEmailSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emailTemplateUpdateEmail">{{.str.emailTemplateUpdateEmail}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Preview
|
||||||
|
<div class="preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane" id="tab4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Find Passord</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>header</code>
|
||||||
|
<code>footer</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
<code>$.tokenUrl</code>
|
||||||
|
<code>$.token</code>
|
||||||
|
<code>$.tokenTimeout</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" name="emailTemplateFindPasswordSubject" value="{{.str.emailTemplateFindPasswordSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emailTemplateFindPassword">{{.str.emailTemplateFindPassword}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Preview
|
||||||
|
<div class="preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane" id="tab5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Invite Register</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>header</code>
|
||||||
|
<code>footer</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
<code>$.registerUrl</code>
|
||||||
|
<code>$.user.username</code>
|
||||||
|
<code>$.user.email</code>
|
||||||
|
<code>$.content</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" name="emailTemplateInviteSubject" value="{{.str.emailTemplateInviteSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emailTemplateInvite">{{.str.emailTemplateInvite}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Preview
|
||||||
|
<div class="preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane" id="tab6">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<b>Blog Comment</b>
|
||||||
|
<div>
|
||||||
|
Available tokens:
|
||||||
|
<code>header</code>
|
||||||
|
<code>footer</code>
|
||||||
|
<code>$.siteUrl</code>
|
||||||
|
<code>$.blogUrl</code>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<code>$.commentContent</code>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<code>$.blog.id</code>
|
||||||
|
<code>$.blog.title</code>
|
||||||
|
<code>$.blog.url</code>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<code>$.commentUser.userId</code>
|
||||||
|
<code>$.commentUser.username</code>
|
||||||
|
<code>$.commentUser.email</code>
|
||||||
|
<code>$.commentUser.isBlogAuthor</code>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<code>$.commentedUser.userId</code>
|
||||||
|
<code>$.commentedUser.username</code>
|
||||||
|
<code>$.commentedUser.email</code>
|
||||||
|
<code>$.commentedUser.isBlogAuthor</code>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Subject</label>
|
||||||
|
<input type="text" class="form-control" name="emailTemplateCommentSubject" value="{{.str.emailTemplateCommentSubject}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Body</label>
|
||||||
|
<textarea type="text" rows="10" class="form-control" name="emailTemplateComment">{{.str.emailTemplateComment}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Preview
|
||||||
|
<div class="preview">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("code").each(function() {
|
||||||
|
var h = $(this).text();
|
||||||
|
$(this).text("{" + "{" + h + "}" + "}");
|
||||||
|
});
|
||||||
|
|
||||||
|
function previewEmail(t) {
|
||||||
|
var $p = $(t).closest(".row");
|
||||||
|
var tpl = $(t).val();
|
||||||
|
var subject = $p.find("input").val() || "";
|
||||||
|
var $preview = $p.find(".preview");
|
||||||
|
|
||||||
|
var header = $("#emailHeader").val();
|
||||||
|
var footer = $("#emailFooter").val();
|
||||||
|
|
||||||
|
header = header.replace("{" + "{$.subject}" + "}", subject);
|
||||||
|
tpl = tpl.replace("{" + "{header}" + "}", header);
|
||||||
|
tpl = tpl.replace("{" + "{footer}" + "}", footer);
|
||||||
|
|
||||||
|
$preview.html(tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("textarea").each(function() {
|
||||||
|
previewEmail(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("textarea").keyup(function() {
|
||||||
|
previewEmail(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
init_validator("#add_user_form");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#add_user_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminEmail/template", getFormJsonData("add_user_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Demo User</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Demo Username</label>
|
||||||
|
<input type="text" class="form-control" name="demoUsername" value="{{.str.demoUsername}}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Demo Password</label>
|
||||||
|
<input type="text" class="form-control" name="demoPassword" value="{{.str.demoPassword}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#add_user_form");
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#add_user_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/doDemo", getFormJsonData("add_user_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Open Register</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="form_data">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Open ?</label>
|
||||||
|
<input type="checkbox" class="form-control" name="openRegister" {{if .str.openRegister}}checked="checked"{{end}} value="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#form_data");
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#form_data").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/openRegister", getFormJsonData("form_data"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Register Share Note</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formContainer">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Shared UserId</label>
|
||||||
|
<input type="text" class="form-control" name="registerSharedUserId" value="{{.str.registerSharedUserId}}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Shared Notebooks</label>
|
||||||
|
<div class="clearfix" id="notebooks">
|
||||||
|
{{range $notebook := .arrMap.registerSharedNotebooks}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" placeholder="notebookId" name="registerSharedNotebookIds[]"
|
||||||
|
value="{{$notebook.notebookId}}"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotebookPerms[]">
|
||||||
|
<option value="0" {{if eq $notebook.perm "0"}}selected{{end}}>Read Only</option>
|
||||||
|
<option value="1" {{if eq $notebook.perm "1"}}selected{{end}}>Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" placeholder="notebookId" name="registerSharedNotebookIds[]">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotebookPerms[]">
|
||||||
|
<option value="0">Read Only</option>
|
||||||
|
<option value="1">Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" placeholder="notebookId" name="registerSharedNotebookIds[]">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotebookPerms[]">
|
||||||
|
<option value="0">Read Only</option>
|
||||||
|
<option value="1">Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
The notebooks will shared to register user
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Shared Notes</label>
|
||||||
|
<div class="clearfix" id="notebooks">
|
||||||
|
{{range $note := .arrMap.registerSharedNotes}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" name="registerSharedNoteIds[]"
|
||||||
|
value="{{$note.noteId}}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotePerms[]">
|
||||||
|
<option value="0" {{if eq $note.perm "0"}}selected{{end}}>Read Only</option>
|
||||||
|
<option value="1" {{if eq $note.perm "1"}}selected{{end}}>Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" placeholder="noteId" name="registerSharedNoteIds[]">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotePerms[]">
|
||||||
|
<option value="0">Read Only</option>
|
||||||
|
<option value="1">Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<input type="text" class="form-control" placeholder="noteId" name="registerSharedNoteIds[]">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<select class="form-control" name="registerSharedNotePerms[]">
|
||||||
|
<option value="0">Read Only</option>
|
||||||
|
<option value="1">Writable</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
The notes will shared to register user
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Copy Notes</label>
|
||||||
|
<div class="clearfix" id="notebooks">
|
||||||
|
{{range $noteId := .arr.registerCopyNoteIds}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<input type="text" class="form-control" name="registerCopyNoteIds[]"
|
||||||
|
value="{{$noteId}}"
|
||||||
|
placeholder="noteId"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<input type="text" class="form-control" name="registerCopyNoteIds[]" placeholder="noteId"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<input type="text" class="form-control" name="registerCopyNoteIds[]" placeholder="noteId"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
The notes will copy to register user
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
var a = "{{json .arrMap}}"
|
||||||
|
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
init_validator("#formContainer");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#formContainer").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/shareNote", getFormJsonData("formContainer"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips(ret.Msg || "Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Add User</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email</label>
|
||||||
|
<input type="text" class="form-control" name="email" data-rule-required="true" data-rule-email="true">
|
||||||
|
</div>
|
||||||
|
<div class="form-group pull-in clearfix">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<label>Enter password</label>
|
||||||
|
<input type="password" class="form-control" data-rule-required="true" id="pwd" name="pwd" data-rule-minlength="6">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<label>Confirm password</label>
|
||||||
|
<input type="password" class="form-control parsley-validated" data-rule-equalto="#pwd" data-rule-required="true" name="password2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#add_user_form");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#add_user_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/auth/doRegister", getFormJsonData("add_user_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
Loaded 100 of 755 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user