Compare commits
174 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
2d107b754d | ||
|
|
872f4e68cf | ||
|
|
8f86baa616 | ||
|
|
1fa03e901d | ||
|
|
04d41dff4a | ||
|
|
4d1f3b957e | ||
|
|
0929c715c0 | ||
|
|
cac06e673a | ||
|
|
ab5e5c7b76 | ||
|
|
88ad35e9be | ||
|
|
cd61592f74 | ||
|
|
bf6590eef9 | ||
|
|
0a75902865 | ||
|
|
58d1e0ec00 | ||
|
|
5244c89987 | ||
|
|
6ed0e30d2b | ||
|
|
2f79331ccf | ||
|
|
76ecc00ad0 | ||
|
|
418c70bad2 | ||
|
|
077e702ba1 | ||
|
|
6ee8fc999d | ||
|
|
4f7d2b5645 | ||
|
|
7a89eca49d | ||
|
|
d392c0eb36 | ||
|
|
e3f4b50c53 | ||
|
|
03f2ebe3f7 | ||
|
|
48c2474668 | ||
|
|
cbe62557f8 | ||
|
|
0b9dd488c2 | ||
|
|
3db06ed738 | ||
|
|
76b279c1e5 | ||
|
|
6eb4702cd2 | ||
|
|
f0b4012118 | ||
|
|
0e45f2c17f | ||
|
|
3baa31d44c | ||
|
|
365ad3853c | ||
|
|
98cf275e37 | ||
|
|
498f2dc3a8 | ||
|
|
98b048235c | ||
|
|
273028ea96 | ||
|
|
a93048b016 | ||
|
|
b63e79954a | ||
|
|
b8b103ace1 | ||
|
|
b2436ee711 | ||
|
|
91f4698c09 | ||
|
|
2605b86e00 | ||
|
|
cd7915f92b | ||
|
|
6f413bfa1f | ||
|
|
298f7bc1d6 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -2,9 +2,12 @@
|
||||
pkg
|
||||
bin2
|
||||
bin/i18n
|
||||
bin/leanote-linux
|
||||
bin/leanote-mac
|
||||
bin/release
|
||||
bin/tmp
|
||||
bin/test
|
||||
bin/src
|
||||
conf/app.conf
|
||||
conf/routes
|
||||
public/upload
|
||||
@@ -12,3 +15,6 @@ app/routes/routes.go
|
||||
app/tmp/main.go
|
||||
.DS_Store
|
||||
.settings
|
||||
.project
|
||||
public/config.codekit
|
||||
files
|
||||
|
||||
2
.project
2
.project
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>leanote-public</name>
|
||||
<name>leanote2</name>
|
||||
<comment>leanote, your own cloud note!</comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
||||
26
LICENSE
26
LICENSE
@@ -1,5 +1,25 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
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
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
@@ -336,4 +356,4 @@ This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
Public License instead of this License.
|
||||
|
||||
203
README.md
203
README.md
@@ -1,46 +1,57 @@
|
||||
## Introduction
|
||||
[中文](https://github.com/leanote/leanote#1-介绍)
|
||||
|
||||
Leanote, a cloud note. You can create your own cloud note by leanote.
|
||||
## 1. Introduction
|
||||
|
||||
## Features
|
||||
* Knowledge: manage your knowledge in leanote. leanote contains tinymce editor and markdown editor, just enjoy yourself in writting.
|
||||
* Share: share your knowledge to your friends in leanote. Well, you are not alone, you can invite your friends to join your cloud note and share your knowledge each other.
|
||||
* Cooperation: collaborate with friends to improve your knowledge.
|
||||
* Blog: public your knowledge and leanote be your blog.
|
||||
Leanote, note just a notebook!
|
||||
|
||||
## Why we create leanote
|
||||
To be honest, our inspiration comes from evernote, and we use evenote to manage our knowledge everyday. But we find that:
|
||||
* Evernote's editor can't meet our needs, it hasn't document navigation, can't put our codes(as a programmer, put codes is the basic needs), can't resize images...)
|
||||
* We like markdown, but evernote don't support it.
|
||||
* We want to public our knowledge, so we have our blog(such as wordpress) and evernote, but why can't be the one!
|
||||
**Some Features**
|
||||
|
||||
* Knowledge: Manage your knowledge in leanote. leanote contains the tinymce editor and a markdown editor, just enjoy yourself writing.
|
||||
* Share: Share your knowledge with your friends in leanote. You can invite your friends to join your notepad in the cloud so you can share knowledge.
|
||||
* Cooperation: Collaborate with friends to improve your skills.
|
||||
* Blog: Publish your knowledge and make leanote your blog.
|
||||
|
||||
## 2. Why we created leanote
|
||||
To be honest, our inspiration comes from Evernote. We use Evernote to manage our knowledge everyday. But we find that:
|
||||
* Evernote's editor can't meet our needs, it does not have document navigation, it does not render code properly (as a programmer, syntax highlighted code rendering is a basic need), it cannot resize images and so forth
|
||||
* We like markdown, but Evernote does not support it.
|
||||
* We want to share our knowledge, so all of us have our blogs (e.g. on Wordpress) and our Evernote accounts, but why can not those two be one!
|
||||
* ......
|
||||
|
||||
## How to use it
|
||||
Leanote build with golang(revel) and mongodb. so you must install mongodb at first.
|
||||
## 3. How to install leanote
|
||||
|
||||
### Install mongodb
|
||||
For more tips please go https://github.com/leanote/leanote/wiki/mongodb-in-leanote
|
||||
### 3.1. Download leanote
|
||||
|
||||
Go http://www.mongodb.org to download and install it.
|
||||
Leanote V0.4 has been released. Binaries:
|
||||
|
||||
### Export initial mongodb data
|
||||
* Linux: [leanote-linux-v0.4.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-v0.4.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz)
|
||||
|
||||
The mongodb data is in path_to_leante/mongodb_backup/leanote_install_data
|
||||
### 3.2. Install MongoDB
|
||||
|
||||
Leanote is written in go using [revel](https://revel.github.io/) and [MongoDB](https://www.mongodb.org). Thus, you need to first install MongoDB.
|
||||
|
||||
For more tips please have a look at [our wiki](https://github.com/leanote/leanote/wiki/Install-Mongodb)
|
||||
|
||||
### 3.3. Import initial MongoDB data
|
||||
|
||||
The mongodb data is in `[PATH_TO_LEANOTE]/mongodb_backup/leanote_install_data`
|
||||
|
||||
```
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb path_to_leante/mongodb_backup/leanote_install_data
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||
```
|
||||
|
||||
The initial data contains two users:
|
||||
The initial database contains three users:
|
||||
|
||||
```
|
||||
user1 username: leanote, password: abc123
|
||||
user2 username: admin, password: abc123
|
||||
user3 username: demo@leanote.com, password: demo@leanote.com (this user is for demo)
|
||||
```
|
||||
|
||||
### Configuration
|
||||
### 3.4. Configuration
|
||||
|
||||
Copy path_to_leante/conf/app-default.conf to path_to_leante/conf/app.conf, the options contains:
|
||||
Modify `[PATH_TO_LEANOTE]/conf/app.conf`. Available configuration options are:
|
||||
|
||||
``mongodb`` **required**
|
||||
|
||||
@@ -58,55 +69,151 @@ Default is 80
|
||||
|
||||
``site.url``
|
||||
|
||||
Default is http://localhost, you must config it when your domain isn't it, it is used when upload images.
|
||||
Default is `http://localhost`, you must edit this when hosting leanote anywhere else. This is used when uploading images.
|
||||
|
||||
``email``
|
||||
|
||||
for find password
|
||||
For password recovery mails
|
||||
|
||||
``adminUsername``
|
||||
|
||||
Default is admin. The index site is the adminUsername's blog
|
||||
Default is `admin`. The landing page is the admin user's blog.
|
||||
|
||||
For more infomation please see app/app.conf and revel manuals http://revel.github.io
|
||||
For more infomation please see `app/app.conf` and the [revel manuals](https://revel.github.io/)
|
||||
|
||||
### Run leanote
|
||||
### 3.5. Run leanote
|
||||
|
||||
```
|
||||
$> cd path_to_leanote/bin
|
||||
$> cd PATH_TO_LEANOTE/bin
|
||||
$> sudo sh run.sh
|
||||
```
|
||||
|
||||
## How to develop leanote
|
||||
## 4. How to develop leanote
|
||||
|
||||
For more tips please go 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(http://revel.github.io), so if you want to develop leanote as you want, you must be familar with revel.
|
||||
|
||||
### 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 GOPATH
|
||||
## 6. Contributing
|
||||
|
||||
### Install revel
|
||||
```
|
||||
go get github.com/revel/revel
|
||||
go get github.com/revel/cmd/revel
|
||||
```
|
||||
Please fork this repository and contribute back using [pull requests](https://github.com/leanote/leanote/pulls).
|
||||
|
||||
### Get leanote
|
||||
## Discussion
|
||||
* [leanote bbs](http://bbs.leanote.com)
|
||||
* [leanote google group](https://groups.google.com/forum/#!forum/leanote)
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
## 1. 介绍
|
||||
|
||||
Leanote, 不只是笔记!
|
||||
|
||||
**特性**
|
||||
|
||||
* 知识管理: 通过leanote来管理知识, leanote有易操作的界面, 包含两款编辑器tinymce和markdown. 在leanote, 你可以尽情享受写作.
|
||||
* 分享: 你也可以通过分享知识给好友, 让好友拥有你的知识.
|
||||
* 协作: 在分享的同时也可以与好友一起协作知识.
|
||||
* 博客: leanote也可以作为你的博客, 将知识公开成博客, 让leanote把你的知识传播的更远!
|
||||
|
||||
## 2. 为什么我们要创建leanote?
|
||||
说实话, 我们曾是evernote的忠实粉丝, 但是我们也发现evernote的不足:
|
||||
* evernote的编辑器不能满足我们的需求, 不能贴代码(格式会乱掉, 作为程序员, 代码是我们的基本需求啊), 图片不能缩放.
|
||||
* 我们是markdown的爱好者, 可是evernote竟然没有.
|
||||
* 我们也想将知识公开, 所以我们有自己的博客, 如wordpress, 但为什么这两者不能合二为一呢?
|
||||
* 还有...
|
||||
|
||||
## 3.安装leanote
|
||||
leanote是一款私有云笔记, 你可以下载它安装在自己的服务器上, 当然也可以在 http://leanote.com 上注册.
|
||||
|
||||
这里详细整理了leanote二进版和leanote开发版的安装教程, 请移步至:
|
||||
* [leanote二进制详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
||||
|
||||
### 3.1. 下载leanote
|
||||
|
||||
Leanote V0.4 已发布, 二进制文件(暂时没有windows版的):
|
||||
|
||||
* Linux: [leanote-linux-v0.4.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz)
|
||||
* MacOS X: [leanote-mac-v0.4.bin.tar.gz](https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.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`
|
||||
|
||||
```
|
||||
go get github.com/leanote/leanote/app
|
||||
$> mongorestore -h localhost -d leanote --directoryperdb PATH_TO_LEANOTE/mongodb_backup/leanote_install_data
|
||||
```
|
||||
|
||||
### Build/Run leanote via revel
|
||||
|
||||
cp conf/routes-default to conf/routes
|
||||
|
||||
Now you can modify leanote source and build/run with revel
|
||||
初始数据包含三个用户:
|
||||
|
||||
```
|
||||
revel run github.com/leanote/leanote
|
||||
user1 username: leanote, password: abc123
|
||||
user2 username: admin, password: abc123
|
||||
user3 username: demo@leanote.com, password: demo@leanote.com (为体验使用)
|
||||
```
|
||||
|
||||
Welcome to join with us and contribute your code to leanote! Thanks.
|
||||
### 3.4. 配置
|
||||
|
||||
修改 `[PATH_TO_LEANOTE]/conf/app.conf`. 有以下选项:
|
||||
|
||||
``mongodb`` **必须配置!**
|
||||
|
||||
```Shell
|
||||
db.host=localhost
|
||||
db.port=27017
|
||||
db.dbname=leanote
|
||||
db.username=
|
||||
db.password=
|
||||
```
|
||||
|
||||
``http.port``
|
||||
|
||||
默认为 80
|
||||
|
||||
``site.url``
|
||||
|
||||
默认是 `http://localhost`, 这会在上传图片后的图片路径中用户, 还有发邮件, 找回密码验证邮箱时用到.
|
||||
|
||||
``email``
|
||||
|
||||
找回密码和验证邮箱时使用
|
||||
|
||||
``adminUsername``
|
||||
|
||||
默认是 `admin`. 首页即为该用户的博客
|
||||
|
||||
更多配置请查看 `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)
|
||||
|
||||
47
app/controllers/AlbumController.go
Normal file
47
app/controllers/AlbumController.go
Normal file
@@ -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))
|
||||
}
|
||||
210
app/controllers/AttachController.go
Normal file
210
app/controllers/AttachController.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -32,6 +32,7 @@ func (c Auth) DoLogin(email, pwd string) revel.Result {
|
||||
c.SetSession(userInfo)
|
||||
// 必须要redirect, 不然用户刷新会重复提交登录信息
|
||||
// return c.Redirect("/")
|
||||
configService.InitUserConfigs(userInfo.UserId.Hex())
|
||||
return c.RenderJson(info.Re{Ok: true})
|
||||
}
|
||||
// return c.RenderTemplate("login.html")
|
||||
|
||||
@@ -2,7 +2,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
@@ -154,7 +154,7 @@ func (c BaseController) E404() revel.Result {
|
||||
}
|
||||
|
||||
// 设置本地
|
||||
func (c BaseController) SetLocale() {
|
||||
func (c BaseController) SetLocale() string {
|
||||
locale := string(c.Request.Locale) // zh-CN
|
||||
lang := locale
|
||||
if strings.Contains(locale, "-") {
|
||||
@@ -165,6 +165,7 @@ func (c BaseController) SetLocale() {
|
||||
lang = "en";
|
||||
}
|
||||
c.RenderArgs["locale"] = lang;
|
||||
return lang
|
||||
}
|
||||
|
||||
// 设置userInfo
|
||||
|
||||
@@ -3,8 +3,8 @@ package controllers
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// . "leanote/app/lea"
|
||||
"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"
|
||||
@@ -45,15 +45,14 @@ func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||
//-----------------------------
|
||||
// 前台
|
||||
|
||||
// 默认是admin用户的博客
|
||||
// 列表
|
||||
// 这里还需要得到其它博客配置信息...
|
||||
// 配置信息可以放在users表中, 或添加一个user_options表(用户配置表)
|
||||
|
||||
// 进入某个用户的博客
|
||||
var blogPageSize = 5
|
||||
var searchBlogPageSize = 30
|
||||
func (c Blog) Index(userId string, notebookId string) revel.Result {
|
||||
// 用户id为空, 转至博客平台
|
||||
if userId == "" {
|
||||
userId = leanoteUserId
|
||||
userId = leanoteUserId;
|
||||
}
|
||||
|
||||
// userId可能是 username, email
|
||||
@@ -90,7 +89,7 @@ func (c Blog) Index(userId string, notebookId string) revel.Result {
|
||||
c.RenderArgs["page"] = page
|
||||
c.RenderArgs["pageSize"] = blogPageSize
|
||||
c.RenderArgs["count"] = count
|
||||
|
||||
|
||||
// 当前notebook
|
||||
c.RenderArgs["notebookId"] = notebookId
|
||||
c.RenderArgs["notebook"] = notebook
|
||||
@@ -173,6 +172,8 @@ func (c Blog) Set() revel.Result {
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
c.SetLocale();
|
||||
|
||||
return c.RenderTemplate("blog/set.html")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,13 @@ 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"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 首页
|
||||
@@ -14,44 +17,62 @@ type File struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 上传图片 editor
|
||||
func (c File) UploadImage(renderHtml string) revel.Result {
|
||||
if renderHtml == "" {
|
||||
renderHtml = "file/image.html"
|
||||
}
|
||||
// 上传的是博客logo
|
||||
// TODO logo不要设置权限, 另外的目录
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
re := c.uploadImage("logo", "");
|
||||
|
||||
re := c.uploadImage();
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
||||
c.RenderArgs["fileUrlPath"] = siteUrl + "/" + re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
|
||||
return c.RenderTemplate(renderHtml)
|
||||
return c.RenderTemplate("file/blog_logo.html")
|
||||
}
|
||||
|
||||
// 上传的是博客logo
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
return c.UploadImage("file/blog_logo.html");
|
||||
// 拖拉上传, pasteImage
|
||||
// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
|
||||
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 {
|
||||
re := c.uploadImage();
|
||||
re.Id = siteUrl + re.Id
|
||||
// re.Id = re.Id
|
||||
// leaui image plugin upload image
|
||||
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||
re := c.uploadImage("", albumId);
|
||||
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 fileId = ""
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultMsg = "内部错误" // 错误信息
|
||||
var Ok = false
|
||||
|
||||
defer func() {
|
||||
re.Id = fileUrlPath
|
||||
re.Id = fileId // 只是id, 没有其它信息
|
||||
re.Code = resultCode
|
||||
re.Msg = resultMsg
|
||||
re.Ok = Ok
|
||||
}()
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
@@ -60,20 +81,30 @@ func (c File) uploadImage() (re info.Re) {
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
|
||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||
if(from == "logo") {
|
||||
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||
} else {
|
||||
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||
}
|
||||
dir := revel.BasePath + "/" + fileUrlPath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return re
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
_, ext := SplitFilename(filename)
|
||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||
resultMsg = "不是图片"
|
||||
return re
|
||||
|
||||
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") {
|
||||
resultMsg = "不是图片"
|
||||
return re
|
||||
}
|
||||
}
|
||||
|
||||
filename = NewGuid() + ext
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
@@ -96,10 +127,140 @@ func (c File) uploadImage() (re info.Re) {
|
||||
}
|
||||
// 改变成gif图片
|
||||
_, toPathGif := TransToGif(toPath, 0, true)
|
||||
|
||||
fileUrlPath += "/" + GetFilename(toPathGif)
|
||||
filename = GetFilename(toPathGif)
|
||||
filesize := GetFilesize(toPathGif)
|
||||
fileUrlPath += "/" + filename
|
||||
resultCode = 1
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
//------------
|
||||
// 过时 已弃用!
|
||||
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)
|
||||
}
|
||||
@@ -17,9 +17,9 @@ func (c Index) Index() revel.Result {
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "leanote"
|
||||
c.RenderArgs["openRegister"] = openRegister
|
||||
c.SetLocale()
|
||||
lang := c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("home/index.html");
|
||||
return c.RenderTemplate("home/index_" + lang + ".html");
|
||||
}
|
||||
|
||||
// 建议
|
||||
|
||||
@@ -22,6 +22,7 @@ func (c Mobile) Index() revel.Result {
|
||||
return c.RenderTemplate("mobile/login.html")
|
||||
}
|
||||
|
||||
/*
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
@@ -32,8 +33,9 @@ func (c Mobile) Index() revel.Result {
|
||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||
*/
|
||||
|
||||
return c.RenderTemplate("mobile/index.html");
|
||||
return c.RenderTemplate("mobile/angular.html");
|
||||
}
|
||||
|
||||
func (c Mobile) Logout() revel.Result {
|
||||
|
||||
@@ -3,7 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/lea/html2image"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
@@ -85,6 +85,11 @@ func (c Note) ListTrashNotes() revel.Result {
|
||||
return c.RenderJson(notes)
|
||||
}
|
||||
|
||||
// 得到note和内容
|
||||
func (c Note) GetNoteAndContent(noteId string) revel.Result {
|
||||
return c.RenderJson(noteService.GetNoteAndContent(noteId, c.GetUserId()))
|
||||
}
|
||||
|
||||
// 得到内容
|
||||
func (c Note) GetNoteContent(noteId string) revel.Result {
|
||||
noteContent := noteService.GetNoteContent(noteId, c.GetUserId())
|
||||
@@ -112,7 +117,6 @@ type NoteOrContent struct {
|
||||
// 这里不能用json, 要用post
|
||||
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
// 新添加note
|
||||
LogJ(noteOrContent)
|
||||
if noteOrContent.IsNew {
|
||||
userId := c.GetObjectUserId();
|
||||
myUserId := userId
|
||||
|
||||
@@ -2,9 +2,9 @@ package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
@@ -13,17 +13,12 @@ type Notebook struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 得到笔记本
|
||||
// 该用户下的
|
||||
func (c Notebook) GetNotebooks() {
|
||||
}
|
||||
|
||||
func (c Notebook) Index(notebook info.Notebook, i int, name string) revel.Result {
|
||||
return c.RenderJson(notebook)
|
||||
}
|
||||
|
||||
// 得到用户的所有笔记本
|
||||
func (c Notebook) getNotebooks() revel.Result {
|
||||
func (c Notebook) GetNotebooks() revel.Result {
|
||||
re := notebookService.GetNotebooks(c.GetUserId())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -34,11 +29,14 @@ func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
||||
}
|
||||
|
||||
// 添加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),
|
||||
Title: title,
|
||||
Seq: -1,
|
||||
UserId: c.GetObjectUserId()}
|
||||
if(parentNotebookId != "") {
|
||||
notebook.ParentNotebookId = bson.ObjectIdHex(parentNotebookId)
|
||||
}
|
||||
re := notebookService.AddNotebook(notebook)
|
||||
|
||||
if(re) {
|
||||
@@ -51,7 +49,23 @@ func (c Notebook) AddNotebook(notebookId, title string) revel.Result {
|
||||
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
||||
}
|
||||
|
||||
// 排序
|
||||
// 无用
|
||||
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||
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 (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "labix.org/v2/mgo/bson"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
|
||||
@@ -3,7 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "labix.org/v2/mgo/bson"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
@@ -77,7 +77,8 @@ func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
||||
|
||||
// 发送邮件
|
||||
var userInfo = c.GetUserInfo();
|
||||
url := "http://leanote.com/register?from=" + userInfo.Username
|
||||
siteUrl, _ := revel.Config.String("site.url")
|
||||
url := siteUrl + "/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)
|
||||
|
||||
51
app/controllers/admin/AdminBaseController.go
Normal file
51
app/controllers/admin/AdminBaseController.go
Normal file
@@ -0,0 +1,51 @@
|
||||
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;
|
||||
}
|
||||
30
app/controllers/admin/AdminBlogController.go
Normal file
30
app/controllers/admin/AdminBlogController.go
Normal file
@@ -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)
|
||||
}
|
||||
25
app/controllers/admin/AdminController.go
Normal file
25
app/controllers/admin/AdminController.go
Normal file
@@ -0,0 +1,25 @@
|
||||
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()
|
||||
|
||||
return c.RenderTemplate("admin/index.html");
|
||||
}
|
||||
|
||||
func (c Admin) GetView(view string) revel.Result {
|
||||
return c.RenderTemplate("admin/" + view);
|
||||
}
|
||||
62
app/controllers/admin/AdminSettingController.go
Normal file
62
app/controllers/admin/AdminSettingController.go
Normal file
@@ -0,0 +1,62 @@
|
||||
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.UpdateUserArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||
re.Ok = configService.UpdateUserArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||
|
||||
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.UpdateUserStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||
re.Ok = configService.UpdateUserStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||
re.Ok = configService.UpdateUserStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
|
||||
|
||||
28
app/controllers/admin/AdminUserController.go
Normal file
28
app/controllers/admin/AdminUserController.go
Normal file
@@ -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");
|
||||
}
|
||||
127
app/controllers/admin/init.go
Normal file
127
app/controllers/admin/init.go
Normal file
@@ -0,0 +1,127 @@
|
||||
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 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
|
||||
}
|
||||
|
||||
func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Admin{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminSetting{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUser{})
|
||||
revel.OnAppStart(func() {
|
||||
adminUsername, _ = revel.Config.String("adminUsername")
|
||||
})
|
||||
}
|
||||
27
app/controllers/api/UserController.go
Normal file
27
app/controllers/api/UserController.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
// "strconv"
|
||||
)
|
||||
|
||||
type ApiUser struct {
|
||||
*revel.Controller
|
||||
}
|
||||
|
||||
// 修改用户名, 需要重置session
|
||||
func (c ApiUser) Info() revel.Result {
|
||||
Log("APIUser");
|
||||
return c.RenderTemplate("home/index.html");
|
||||
// return nil;
|
||||
}
|
||||
@@ -3,18 +3,16 @@ package controllers
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 该文件初始化所有service方法
|
||||
|
||||
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
|
||||
@@ -22,6 +20,11 @@ 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 pageSize = 1000
|
||||
var defaultSortField = "UpdatedTime"
|
||||
@@ -53,12 +56,14 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
||||
"User": map[string]bool{"UpdateEmail": 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 {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
// 不在commonUrl里
|
||||
// 在commonUrl里
|
||||
if _, ok2 := v[method]; ok2 {
|
||||
return false
|
||||
}
|
||||
@@ -73,13 +78,11 @@ 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 // 已登录
|
||||
@@ -95,6 +98,28 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
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
|
||||
}
|
||||
|
||||
func init() {
|
||||
// interceptor
|
||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
||||
@@ -103,24 +128,10 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &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() {
|
||||
leanoteUserId, _ = revel.Config.String("adminUsername")
|
||||
siteUrl, _ = revel.Config.String("site.url")
|
||||
|
||||
@@ -2,8 +2,8 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
@@ -33,6 +33,14 @@ var Tokens *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
|
||||
|
||||
// 初始化时连接数据库
|
||||
func Init() {
|
||||
var url string
|
||||
@@ -94,8 +102,17 @@ func Init() {
|
||||
// find password
|
||||
Tokens = Session.DB(dbname).C("tokens")
|
||||
|
||||
//
|
||||
// Suggestion
|
||||
Suggestions = Session.DB(dbname).C("suggestions")
|
||||
|
||||
// Album & file
|
||||
Albums = Session.DB(dbname).C("albums")
|
||||
Files = Session.DB(dbname).C("files")
|
||||
Attachs = Session.DB(dbname).C("attachs")
|
||||
|
||||
NoteImages = Session.DB(dbname).C("note_images")
|
||||
|
||||
Configs = Session.DB(dbname).C("configs")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
// convert revel msg to js msg
|
||||
|
||||
var msgBasePath = "/Users/life/Documents/Go/package/src/leanote/messages/"
|
||||
var targetBasePath = "/Users/life/Documents/Go/package/src/leanote/public/js/i18n/"
|
||||
var msgBasePath = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/messages/"
|
||||
var targetBasePath = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/public/js/i18n/"
|
||||
func parse(filename string) {
|
||||
file, err := os.Open(msgBasePath + filename)
|
||||
reader := bufio.NewReader(file)
|
||||
|
||||
15
app/info/AlbumInfo.go
Normal file
15
app/info/AlbumInfo.go
Normal file
@@ -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`
|
||||
}
|
||||
21
app/info/AttachInfo.go
Normal file
21
app/info/AttachInfo.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
// 只为blog, 不为note
|
||||
@@ -10,6 +10,7 @@ type BlogItem struct {
|
||||
Note
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
User User // 用户信息
|
||||
}
|
||||
|
||||
type UserBlogBase struct {
|
||||
|
||||
15
app/info/Configinfo.go
Normal file
15
app/info/Configinfo.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 配置
|
||||
// 用户配置高于全局配置
|
||||
type Config struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
StringConfigs map[string]string `StringConfigs` // key => value
|
||||
ArrayConfigs map[string][]string `ArrayConfigs` // key => []value
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
}
|
||||
21
app/info/FileInfo.go
Normal file
21
app/info/FileInfo.go
Normal file
@@ -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
|
||||
}
|
||||
12
app/info/NoteImage.go
Normal file
12
app/info/NoteImage.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -17,13 +17,17 @@ type Note struct {
|
||||
|
||||
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
||||
Tags []string `Tags,omitempty`
|
||||
|
||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||
|
||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||
|
||||
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
||||
|
||||
AttachNum int `AttachNum` // 2014/9/21, attachments num
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
@@ -54,11 +58,11 @@ type NoteAndContent struct {
|
||||
// 每一个历史记录对象
|
||||
type EachHistory struct {
|
||||
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
Content string `Content`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
Content string `Content`
|
||||
}
|
||||
type NoteContentHistory struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||
Histories []EachHistory `Histories`
|
||||
}
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||
Histories []EachHistory `Histories`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ type Notebook struct {
|
||||
}
|
||||
|
||||
// 仅仅是为了返回前台
|
||||
type SubNotebooks []Notebooks
|
||||
type SubNotebooks []*Notebooks // 存地址, 为了生成tree
|
||||
type Notebooks struct {
|
||||
Notebook
|
||||
Subs SubNotebooks // 子notebook 在数据库中是没有的
|
||||
@@ -32,7 +32,7 @@ func (this SubNotebooks) Len() int {
|
||||
return len(this)
|
||||
}
|
||||
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) {
|
||||
this[i], this[j] = this[j], this[i]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
// 建议
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
// 这里主要是为了统计每个tag的note数目
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -20,6 +20,7 @@ type User struct {
|
||||
Pwd string `bson:"Pwd" json:"-"`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
Logo string `Logo` // 9-24
|
||||
// 主题
|
||||
Theme string `Theme`
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,5 +9,14 @@ import (
|
||||
type Page struct {
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
Count int // 总记录数
|
||||
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}
|
||||
}
|
||||
135
app/init.go
135
app/init.go
@@ -3,11 +3,15 @@ package app
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
"github.com/leanote/leanote/app/controllers/admin"
|
||||
_ "github.com/leanote/leanote/app/lea/binder"
|
||||
"reflect"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math"
|
||||
"strings"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
@@ -16,7 +20,8 @@ func init() {
|
||||
// Filters is the default set of global filters.
|
||||
revel.Filters = []revel.Filter{
|
||||
revel.PanicFilter, // Recover from panics and display an error page instead.
|
||||
revel.RouterFilter, // Use the routing table to select the right Action
|
||||
RouterFilter,
|
||||
// revel.RouterFilter, // Use the routing table to select the right Action
|
||||
// AuthFilter, // Invoke the action.
|
||||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
|
||||
revel.ParamsFilter, // Parse parameters into Controller.Params.
|
||||
@@ -35,9 +40,13 @@ func init() {
|
||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||
return template.HTML(str)
|
||||
}
|
||||
revel.TemplateFuncs["add"] = func(i int) template.HTML {
|
||||
revel.TemplateFuncs["add"] = func(i int) string {
|
||||
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["concat"] = func(s1, s2 string) template.HTML {
|
||||
return template.HTML(s1 + s2)
|
||||
@@ -75,6 +84,76 @@ func init() {
|
||||
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 ""
|
||||
}
|
||||
|
||||
// 为后台管理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
|
||||
revel.TemplateFuncs["page"] = func(userId, notebookId string, page, pageSize, count int) template.HTML {
|
||||
if count == 0 {
|
||||
@@ -111,9 +190,59 @@ func init() {
|
||||
}
|
||||
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
|
||||
revel.OnAppStart(func() {
|
||||
InitEmail()
|
||||
|
||||
service.InitService()
|
||||
controllers.InitService()
|
||||
admin.InitService()
|
||||
service.ConfigS.InitGlobalConfigs()
|
||||
})
|
||||
}
|
||||
@@ -28,8 +28,8 @@ var bodyTpl = `
|
||||
<div style="float:left; height: 40px;">
|
||||
<a href="http://leanote.com" style="font-size: 24px">leanote</a>
|
||||
</div>
|
||||
<div style="float:left; height:40px; line-height:16px;">
|
||||
| <span style="font-size:24px">$title</span>
|
||||
<div style="float:left; height:40px; line-height:40px;">
|
||||
| <span style="font-size:14px">$title</span>
|
||||
</div>
|
||||
<div style="clear:both"></div>
|
||||
</div>
|
||||
@@ -50,7 +50,7 @@ var bodyTpl = `
|
||||
font-size: 12px;
|
||||
}
|
||||
</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>
|
||||
</body>
|
||||
@@ -78,6 +78,7 @@ func SendEmail(to, subject, title, body string) bool {
|
||||
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
|
||||
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"os"
|
||||
"io"
|
||||
)
|
||||
|
||||
// 分离文件名与扩展名(包含.)
|
||||
@@ -30,6 +31,16 @@ func GetFilename(path string) string {
|
||||
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下所有的文件和文件夹
|
||||
// RemoveAll会清空本文件夹, 所以还要创建之
|
||||
func ClearDir(dir string) bool {
|
||||
@@ -42,4 +53,28 @@ func ClearDir(dir string) bool {
|
||||
return false
|
||||
}
|
||||
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)
|
||||
}
|
||||
60
app/lea/Route.go
Normal file
60
app/lea/Route.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// overwite revel RouterFilter
|
||||
// /api/user/Info => ApiUser.Info()
|
||||
func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
// 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
|
||||
path := c.Request.Request.URL.Path
|
||||
// Log(c.Request.Request.URL.Host)
|
||||
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:])
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
math_rand "math/rand"
|
||||
)
|
||||
@@ -266,4 +266,16 @@ func RandomPwd(num int) string {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package session
|
||||
|
||||
import (
|
||||
"github.com/robfig/revel"
|
||||
"leanote/app/lea/memcache"
|
||||
"github.com/leanote/leanote/app/lea/memcache"
|
||||
// . "leanote/app/lea"
|
||||
)
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
||||
|
||||
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"
|
||||
|
||||
func cmdError(err error) {
|
||||
@@ -89,8 +90,8 @@ func dev() {
|
||||
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
||||
"console.log(o);": "",
|
||||
}
|
||||
path := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note-dev.html"
|
||||
target := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note.html"
|
||||
path := base1 + "/src/views/note/note-dev.html"
|
||||
target := base1 + "/src/views/note/note.html"
|
||||
|
||||
bs, _ := ioutil.ReadFile(path)
|
||||
content := string(bs)
|
||||
|
||||
44
app/service/AlbumService.go
Normal file
44
app/service/AlbumService.go
Normal file
@@ -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)
|
||||
}
|
||||
175
app/service/AttachService.go
Normal file
175
app/service/AttachService.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/revel/revel"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
// "sort"
|
||||
)
|
||||
@@ -40,7 +40,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
||||
|
||||
// 组装成blogItem
|
||||
blog = info.BlogItem{note, noteContent.Content, false}
|
||||
blog = info.BlogItem{note, noteContent.Content, false, info.User{}}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||
}
|
||||
return count, blogs
|
||||
}
|
||||
@@ -119,11 +119,91 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
//------------------------
|
||||
// 博客设置
|
||||
@@ -152,4 +232,12 @@ func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.User
|
||||
}
|
||||
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
}
|
||||
|
||||
//------------
|
||||
// 后台管理
|
||||
|
||||
// 推荐博客
|
||||
func (this *BlogService) SetRecommend(noteId string, isRecommend bool) bool {
|
||||
return db.UpdateByQField(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsBlog": true}, "IsRecommend", isRecommend)
|
||||
}
|
||||
141
app/service/ConfigService.go
Normal file
141
app/service/ConfigService.go
Normal file
@@ -0,0 +1,141 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// 配置服务
|
||||
type ConfigService struct {
|
||||
// 全局的
|
||||
GlobalStringConfigs map[string]string
|
||||
GlobalArrayConfigs map[string][]string
|
||||
|
||||
// 两种配置, 用户自己的
|
||||
UserStringConfigs map[string]string
|
||||
UserArrayConfigs map[string][]string
|
||||
|
||||
// 合并之后的
|
||||
AllStringConfigs map[string]string
|
||||
AllArrayConfigs map[string][]string
|
||||
}
|
||||
|
||||
var adminUserId = ""
|
||||
|
||||
// appStart时 将全局的配置从数据库中得到作为全局
|
||||
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalStringConfigs = map[string]string{}
|
||||
this.GlobalArrayConfigs = map[string][]string{}
|
||||
|
||||
this.UserStringConfigs = map[string]string{}
|
||||
this.UserArrayConfigs = map[string][]string{}
|
||||
|
||||
this.AllStringConfigs = map[string]string{}
|
||||
this.AllArrayConfigs = 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.Get2(db.Configs, userInfo.UserId, &configs)
|
||||
|
||||
if configs.UserId == "" {
|
||||
db.Insert(db.Configs, info.Config{UserId: userInfo.UserId, StringConfigs: map[string]string{}, ArrayConfigs: map[string][]string{}})
|
||||
}
|
||||
|
||||
this.GlobalStringConfigs = configs.StringConfigs;
|
||||
this.GlobalArrayConfigs = configs.ArrayConfigs;
|
||||
|
||||
// 复制到所有配置上
|
||||
for key, value := range this.GlobalStringConfigs {
|
||||
this.AllStringConfigs[key] = value
|
||||
}
|
||||
for key, value := range this.GlobalArrayConfigs {
|
||||
this.AllArrayConfigs[key] = value
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 用户登录后获取用户自定义的配置, 并将所有的配置都用上
|
||||
func (this *ConfigService) InitUserConfigs(userId string) bool {
|
||||
configs := info.Config{}
|
||||
db.Get(db.Configs, userId, &configs)
|
||||
|
||||
if configs.UserId == "" {
|
||||
db.Insert(db.Configs, info.Config{UserId: bson.ObjectIdHex(userId), StringConfigs: map[string]string{}, ArrayConfigs: map[string][]string{}})
|
||||
}
|
||||
|
||||
this.UserStringConfigs = configs.StringConfigs;
|
||||
this.UserArrayConfigs = configs.ArrayConfigs;
|
||||
|
||||
// 合并配置
|
||||
for key, value := range this.UserStringConfigs {
|
||||
this.AllStringConfigs[key] = value
|
||||
}
|
||||
for key, value := range this.UserArrayConfigs {
|
||||
this.AllArrayConfigs[key] = value
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
func (this *ConfigService) GetStringConfig(key string) string {
|
||||
return this.AllStringConfigs[key]
|
||||
}
|
||||
func (this *ConfigService) GetArrayConfig(key string) []string {
|
||||
arr := this.AllArrayConfigs[key]
|
||||
if arr == nil {
|
||||
return []string{}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// 更新用户配置
|
||||
func (this *ConfigService) UpdateUserStringConfig(userId, key string, value string) bool {
|
||||
this.UserStringConfigs[key] = value
|
||||
this.AllStringConfigs[key] = value
|
||||
if userId == adminUserId {
|
||||
this.GlobalStringConfigs[key] = value
|
||||
}
|
||||
|
||||
// 保存到数据库中
|
||||
return db.UpdateByQMap(db.Configs, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||
bson.M{"StringConfigs": this.UserStringConfigs, "UpdatedTime": time.Now()})
|
||||
}
|
||||
func (this *ConfigService) UpdateUserArrayConfig(userId, key string, value []string) bool {
|
||||
this.UserArrayConfigs[key] = value
|
||||
this.AllArrayConfigs[key] = value
|
||||
if userId == adminUserId {
|
||||
this.GlobalArrayConfigs[key] = value
|
||||
}
|
||||
|
||||
// 保存到数据库中
|
||||
return db.UpdateByQMap(db.Configs, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||
bson.M{"ArrayConfigs": this.UserArrayConfigs, "UpdatedTime": time.Now()})
|
||||
}
|
||||
|
||||
// 获取全局配置, 博客平台使用
|
||||
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
|
||||
}
|
||||
236
app/service/FileService.go
Normal file
236
app/service/FileService.go
Normal file
@@ -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/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
)
|
||||
|
||||
|
||||
102
app/service/NoteImageService.go
Normal file
102
app/service/NoteImageService.go
Normal file
@@ -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;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -17,6 +17,12 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||
return
|
||||
}
|
||||
// fileService调用
|
||||
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||
note = info.Note{}
|
||||
db.Get(db.Notes, noteId, ¬e)
|
||||
return
|
||||
}
|
||||
// 得到blog, blogService用
|
||||
// 不要传userId, 因为是公开的
|
||||
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
||||
@@ -31,6 +37,13 @@ func (this *NoteService) GetNoteContent(noteContentId, userId string) (noteConte
|
||||
return
|
||||
}
|
||||
|
||||
// 得到笔记和内容
|
||||
func (this *NoteService) GetNoteAndContent(noteId, userId string) (noteAndContent info.NoteAndContent) {
|
||||
note := this.GetNote(noteId, userId)
|
||||
noteContent := this.GetNoteContent(noteId, userId)
|
||||
return info.NoteAndContent{note, noteContent}
|
||||
}
|
||||
|
||||
// 列出note, 排序规则, 还有分页
|
||||
// CreatedTime, UpdatedTime, title 来排序
|
||||
func (this *NoteService) ListNotes(userId, notebookId string,
|
||||
@@ -141,6 +154,10 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
||||
noteContent.UpdatedTime = noteContent.CreatedTime
|
||||
noteContent.UpdatedUserId = noteContent.UserId
|
||||
db.Insert(db.NoteContents, noteContent)
|
||||
|
||||
// 更新笔记图片
|
||||
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
|
||||
|
||||
return noteContent;
|
||||
}
|
||||
|
||||
@@ -230,11 +247,23 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
||||
Content: content,
|
||||
UpdatedTime: time.Now(),
|
||||
})
|
||||
|
||||
// 更新笔记图片
|
||||
noteImageService.UpdateNoteImages(userId, noteId, content)
|
||||
|
||||
return true
|
||||
}
|
||||
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
|
||||
// [ok] [del]
|
||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||
@@ -309,9 +338,12 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
||||
}
|
||||
|
||||
// 复制别人的共享笔记给我
|
||||
// TODO 判断是否共享了给我
|
||||
// 将别人可用的图片转为我的图片, 复制图片
|
||||
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)
|
||||
if note.NoteId == "" {
|
||||
return info.Note{}
|
||||
@@ -325,10 +357,18 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
|
||||
note.IsTop = false
|
||||
note.IsBlog = false // 别人的可能是blog
|
||||
|
||||
note.ImgSrc = "" // 为什么清空, 因为图片需要复制, 先清空
|
||||
|
||||
// content
|
||||
noteContent.NoteId = note.NoteId
|
||||
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);
|
||||
|
||||
@@ -346,8 +386,10 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
|
||||
// shareService call
|
||||
// [ok]
|
||||
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
||||
note := &info.Note{}
|
||||
db.Get(db.Notes, noteId, note)
|
||||
note := info.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
|
||||
}
|
||||
|
||||
@@ -389,7 +431,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
LogJ(noteIds)
|
||||
noteContents := []info.NoteContent{}
|
||||
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
||||
if isBlog {
|
||||
@@ -412,9 +453,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
||||
noteIds2[i] = content.NoteId
|
||||
}
|
||||
|
||||
// Log(" content search ")
|
||||
// Log(lenContent)
|
||||
|
||||
// 得到notes
|
||||
notes2 := this.ListNotesByNoteIds(noteIds2)
|
||||
|
||||
@@ -439,8 +477,6 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
||||
// 总记录数
|
||||
count, _ = q.Count()
|
||||
|
||||
Log(count)
|
||||
|
||||
q.Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
|
||||
@@ -2,7 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
@@ -47,31 +47,40 @@ func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSo
|
||||
newNotebooks.NumberNotes = each.NumberNotes
|
||||
newNotebooks.IsTrash = each.IsTrash
|
||||
newNotebooks.IsBlog = each.IsBlog
|
||||
|
||||
// 存地址
|
||||
userNotebooksMap[each.NotebookId] = &newNotebooks
|
||||
}
|
||||
|
||||
// 第二遍, 追加到父下
|
||||
// nilObjectId := bson.ObjectIdHex("")
|
||||
|
||||
// 需要删除的id
|
||||
needDeleteNotebookId := map[bson.ObjectId]bool{}
|
||||
for id, each := range userNotebooksMap {
|
||||
// 如果有父, 那么追加到父下, 并剪掉当前, 那么最后就只有根的元素
|
||||
if each.ParentNotebookId.Hex() != "" {
|
||||
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 {
|
||||
// 没有父, 且设置了要删除
|
||||
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
|
||||
for _, each := range userNotebooksMap {
|
||||
final[i] = *each
|
||||
i++
|
||||
for id, each := range userNotebooksMap {
|
||||
if !needDeleteNotebookId[id] {
|
||||
final[i] = each
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// 最后排序
|
||||
@@ -182,14 +191,20 @@ func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdat
|
||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||
}
|
||||
|
||||
// 查看是否有子notebook
|
||||
// 先查看该notebookId下是否有notes, 没有则删除
|
||||
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false}) == 0 { // 不包含trash
|
||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||
if db.Count(db.Notebooks, bson.M{"ParentNotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId)}) == 0 { // 无
|
||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false}) == 0 { // 不包含trash
|
||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||
}
|
||||
return false, "笔记本下有笔记"
|
||||
} else {
|
||||
return false, "笔记本下有子笔记本"
|
||||
}
|
||||
return false, "笔记本下有笔记"
|
||||
}
|
||||
|
||||
// 排序
|
||||
@@ -207,5 +222,30 @@ func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[st
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *NotebookService) DragNotebooks(userId string, curNotebookId string, parentNotebookId string, siblings []string) bool {
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
|
||||
ok := false
|
||||
// 如果没parentNotebookId, 则parentNotebookId设空
|
||||
if(parentNotebookId == "") {
|
||||
ok = db.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
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
@@ -31,7 +32,8 @@ func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://leanote.com/findPassword/" + token
|
||||
siteUrl, _ := revel.Config.String("site.url")
|
||||
url := siteUrl + "/findPassword/" + token
|
||||
body := fmt.Sprintf("请点击链接修改密码: <a href='%v'>%v</a>. %v小时后过期.", url, url, int(overHours));
|
||||
if !SendEmail(email, "leanote-找回密码", "找回密码", body) {
|
||||
return false, "邮箱发送失败"
|
||||
|
||||
@@ -3,8 +3,8 @@ package service
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"sort"
|
||||
)
|
||||
@@ -286,6 +286,28 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
||||
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的权限?
|
||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||
// 1. noteId是否被共享了?
|
||||
@@ -334,14 +356,14 @@ func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
|
||||
}
|
||||
|
||||
// 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)})
|
||||
}
|
||||
// noteId的notebook是否共享了给我
|
||||
func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
|
||||
note := noteService.GetNote(noteId, sharedUserId)
|
||||
if note.NoteId != "" {
|
||||
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": note.NotebookId,
|
||||
func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId != "" {
|
||||
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": notebookId,
|
||||
"UserId": bson.ObjectIdHex(sharedUserId),
|
||||
"ToUserId": bson.ObjectIdHex(myUserId),
|
||||
})
|
||||
@@ -355,7 +377,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
||||
noteContent = info.NoteContent{}
|
||||
// 是否单独共享了该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)
|
||||
} else {
|
||||
}
|
||||
@@ -507,4 +529,51 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
|
||||
db.DeleteAll(db.HasShareNotes, query);
|
||||
|
||||
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/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
// "sort"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
@@ -53,7 +53,15 @@ func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
||||
|
||||
// 删除trash
|
||||
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, 排序规则, 还有分页
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"time"
|
||||
"strings"
|
||||
"fmt"
|
||||
@@ -64,6 +65,7 @@ func (this *UserService) GetUserInfoByAny(idEmailUsername string) info.User {
|
||||
return this.GetUserInfoByEmail(idEmailUsername)
|
||||
}
|
||||
|
||||
// username
|
||||
return this.GetUserInfoByUsername(idEmailUsername)
|
||||
}
|
||||
|
||||
@@ -82,6 +84,7 @@ func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
||||
// 得到用户信息 username
|
||||
func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
||||
user := info.User{}
|
||||
username = strings.ToLower(username)
|
||||
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
||||
return user
|
||||
}
|
||||
@@ -96,6 +99,29 @@ func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.
|
||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||
return users
|
||||
}
|
||||
// 用户信息和博客设置信息
|
||||
func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectId) map[bson.ObjectId]info.User {
|
||||
users := []info.User{}
|
||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||
|
||||
userBlogs := []info.UserBlog{}
|
||||
db.ListByQWithFields(db.UserBlogs, bson.M{"_id": bson.M{"$in": userIds}}, []string{"Logo"}, &userBlogs)
|
||||
|
||||
userBlogMap := make(map[bson.ObjectId]info.UserBlog, len(userBlogs))
|
||||
for _, user := range userBlogs {
|
||||
userBlogMap[user.UserId] = user
|
||||
}
|
||||
|
||||
userMap := make(map[bson.ObjectId]info.User, len(users))
|
||||
for _, user := range users {
|
||||
if userBlog, ok := userBlogMap[user.UserId]; ok {
|
||||
user.Logo = userBlog.Logo
|
||||
}
|
||||
userMap[user.UserId] = user
|
||||
}
|
||||
|
||||
return userMap
|
||||
}
|
||||
|
||||
// 通过ids得到users, 按id的顺序组织users
|
||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||
@@ -132,7 +158,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
||||
|
||||
// 更新username
|
||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||
if userId == "" || username == "" {
|
||||
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||
return false, "用户已存在"
|
||||
}
|
||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||
@@ -180,7 +206,8 @@ func (this *UserService) RegisterSendActiveEmail(userId string, email string) bo
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://leanote.com/user/activeEmail?token=" + token
|
||||
siteUrl, _ := revel.Config.String("site.url")
|
||||
url := siteUrl + "/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
|
||||
@@ -208,11 +235,12 @@ func (this *UserService) UpdateEmailSendActiveEmail(userId, email string) (ok bo
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://115.28.133.226/user/updateEmail?token=" + token
|
||||
siteUrl, _ := revel.Config.String("site.url")
|
||||
url := siteUrl + "/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 = "发送失败"
|
||||
msg = "发送失败, 该邮箱存在?"
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
@@ -292,3 +320,24 @@ func (this *UserService)UpdateColumnWidth(userId string, notebookWidth, noteList
|
||||
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
|
||||
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
|
||||
}
|
||||
@@ -8,24 +8,56 @@ import (
|
||||
// 初始化, 实例service
|
||||
// 为了共享service
|
||||
|
||||
var notebookService *NotebookService
|
||||
var noteService *NoteService
|
||||
var noteContentHistoryService *NoteContentHistoryService
|
||||
var trashService *TrashService
|
||||
var shareService *ShareService
|
||||
var userService *UserService
|
||||
var tagService *TagService
|
||||
var blogService *BlogService
|
||||
var tokenService *TokenService
|
||||
var notebookService, NotebookS *NotebookService
|
||||
var noteService, NoteS *NoteService
|
||||
var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService
|
||||
var trashService, TrashS *TrashService
|
||||
var shareService, ShareS *ShareService
|
||||
var userService, UserS *UserService
|
||||
var tagService, TagS *TagService
|
||||
var blogService, BlogS *BlogService
|
||||
var tokenService, TokenS *TokenService
|
||||
var noteImageService, NoteImageS *NoteImageService
|
||||
var fileService, FileS *FileService
|
||||
var albumService, AlbumS *AlbumService
|
||||
var attachService, AttachS *AttachService
|
||||
var configService, ConfigS *ConfigService
|
||||
var PwdS *PwdService
|
||||
var SuggestionS *SuggestionService
|
||||
var AuthS *AuthService
|
||||
|
||||
func init() {
|
||||
notebookService = &NotebookService{}
|
||||
noteService = &NoteService{}
|
||||
noteContentHistoryService = &NoteContentHistoryService{}
|
||||
trashService = &TrashService{}
|
||||
shareService = &ShareService{}
|
||||
userService = &UserService{}
|
||||
tagService = &TagService{}
|
||||
blogService = &BlogService{}
|
||||
tokenService = &TokenService{}
|
||||
// onAppStart调用
|
||||
func InitService() {
|
||||
NotebookS = &NotebookService{}
|
||||
NoteS = &NoteService{}
|
||||
NoteContentHistoryS = &NoteContentHistoryService{}
|
||||
TrashS = &TrashService{}
|
||||
ShareS = &ShareService{}
|
||||
UserS = &UserService{}
|
||||
TagS = &TagService{}
|
||||
BlogS = &BlogService{}
|
||||
TokenS = &TokenService{}
|
||||
NoteImageS = &NoteImageService{}
|
||||
FileS = &FileService{}
|
||||
AlbumS = &AlbumService{}
|
||||
AttachS = &AttachService{}
|
||||
ConfigS = &ConfigService{}
|
||||
PwdS = &PwdService{}
|
||||
SuggestionS = &SuggestionService{}
|
||||
AuthS = &AuthService{}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/leanote/leanote/app/lea/html2image"
|
||||
"time"
|
||||
"fmt"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "labix.org/v2/mgo"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "gopkg.in/mgo.v2"
|
||||
// "encoding/json"
|
||||
// "strings"
|
||||
)
|
||||
@@ -181,8 +181,15 @@ make<br>make --- install</pre>
|
||||
`, "/Users/life/Desktop/a.png")
|
||||
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() {
|
||||
revel.BasePath = "/Users/life/Documents/Go/package/src/leanote"
|
||||
testLea();
|
||||
// a, b := SplitFilename("http://ab/c/a.gif#??")
|
||||
// println(a)
|
||||
// println(b)
|
||||
@@ -199,7 +206,7 @@ func main() {
|
||||
//_, err := mgo.Dial("mongodb://leanote:nKFAkxKnWkEQy8Vv2LlM@115.28.133.226:27017/leanote")
|
||||
|
||||
// testNotebookService();
|
||||
testNoteService();
|
||||
// testNoteService();
|
||||
// testShareService()
|
||||
// testAuthService()
|
||||
|
||||
|
||||
175
app/views/Admin/Blog/list.html
Normal file
175
app/views/Admin/Blog/list.html
Normal file
@@ -0,0 +1,175 @@
|
||||
{{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">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="0">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Delete selected
|
||||
</option>
|
||||
<option value="2">
|
||||
Bulk edit
|
||||
</option>
|
||||
<option value="3">
|
||||
Export
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default">
|
||||
Apply
|
||||
</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 "isRecommend" .sorter}}
|
||||
>
|
||||
isRecommend
|
||||
<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>
|
||||
<th width="30">
|
||||
</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>
|
||||
<button data-loading-text="..." class="btn btn-default change-recommend" data-id="{{.NoteId.Hex}}" data-recommend="{{if .IsRecommend}}1{{else}}0{{end}}">
|
||||
{{if .IsRecommend}}
|
||||
Y
|
||||
{{else}}
|
||||
N
|
||||
{{end}}
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
{{.CreatedTime|datetime}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-default">Send Email</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<footer class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 hidden-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="0">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Delete selected
|
||||
</option>
|
||||
<option value="2">
|
||||
Bulk edit
|
||||
</option>
|
||||
<option value="3">
|
||||
Export
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default">
|
||||
Apply
|
||||
</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" .}}
|
||||
33
app/views/Admin/Blog/page.html
Normal file
33
app/views/Admin/Blog/page.html
Normal file
@@ -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}}
|
||||
55
app/views/Admin/Setting/blog.html
Normal file
55
app/views/Admin/Setting/blog.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<div class="m-b-md"> <h3 class="m-b-none">Blog</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>Recommend Tags</label>
|
||||
<input type="text" class="form-control" name="recommendTags" value="{{.recommendTags}}">
|
||||
Split by ','
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>New Tags</label>
|
||||
<input type="text" class="form-control" name="newTags" value="{{.newTags}}">
|
||||
Split by ','
|
||||
</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/doBlogTag", 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" .}}
|
||||
52
app/views/Admin/Setting/demo.html
Normal file
52
app/views/Admin/Setting/demo.html
Normal file
@@ -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="{{.demoUsername}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Demo Password</label>
|
||||
<input type="text" class="form-control" name="demoPassword" value="{{.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" .}}
|
||||
58
app/views/Admin/User/add.html
Normal file
58
app/views/Admin/User/add.html
Normal file
@@ -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" .}}
|
||||
163
app/views/Admin/User/list.html
Normal file
163
app/views/Admin/User/list.html
Normal file
@@ -0,0 +1,163 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<div class="m-b-md"> <h3 class="m-b-none">User</h3></div>
|
||||
|
||||
<section class="panel panel-default">
|
||||
<div class="row wrapper">
|
||||
<div class="col-sm-5 m-b-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="0">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Delete selected
|
||||
</option>
|
||||
<option value="2">
|
||||
Bulk edit
|
||||
</option>
|
||||
<option value="3">
|
||||
Export
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default">
|
||||
Apply
|
||||
</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="/adminUser/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 "/adminUser/index" "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 "username" .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 "verified" .sorter}}
|
||||
>
|
||||
Verified
|
||||
<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}}
|
||||
>
|
||||
Register 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 width="30">
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .users}}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="post[]" value="2">
|
||||
</td>
|
||||
<td>
|
||||
{{.Email}}
|
||||
</td>
|
||||
<td>
|
||||
{{.Username}}
|
||||
</td>
|
||||
<td>
|
||||
{{.Verified}}
|
||||
</td>
|
||||
<td>
|
||||
{{.CreatedTime|datetime}}
|
||||
<a href="#" class="active" data-toggle="class">
|
||||
<i class="fa fa-check text-success text-active">
|
||||
</i>
|
||||
<i class="fa fa-times text-danger text">
|
||||
</i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-default">Send Email</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<footer class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 hidden-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="0">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
Delete selected
|
||||
</option>
|
||||
<option value="2">
|
||||
Bulk edit
|
||||
</option>
|
||||
<option value="3">
|
||||
Export
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default">
|
||||
Apply
|
||||
</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 "/adminUser/index" "sorter" .sorter "keywords" .keywords)}}
|
||||
{{template "admin/user/page.html" .}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
{{template "admin/footer.html" .}}
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
});
|
||||
</script>
|
||||
|
||||
{{template "admin/end.html" .}}
|
||||
33
app/views/Admin/User/page.html
Normal file
33
app/views/Admin/User/page.html
Normal file
@@ -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}}
|
||||
639
app/views/Admin/button.html
Normal file
639
app/views/Admin/button.html
Normal file
@@ -0,0 +1,639 @@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-6">
|
||||
<h4 class="m-t-xs">
|
||||
Button options
|
||||
</h4>
|
||||
<div class="doc-buttons">
|
||||
<a href="#" class="btn btn-s-md btn-default">
|
||||
Default
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-primary">
|
||||
Primary
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-success">
|
||||
Success
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-info">
|
||||
Info
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-warning">
|
||||
Warning
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-danger">
|
||||
Danger
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-dark">
|
||||
Dark
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-default disabled">
|
||||
Disabled
|
||||
</a>
|
||||
</div>
|
||||
<h4 class="m-t">
|
||||
Button size
|
||||
</h4>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default btn-lg">
|
||||
Large button
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default">
|
||||
Default button
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default btn-sm">
|
||||
Small button
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default btn-xs">
|
||||
Extra small button
|
||||
</a>
|
||||
</p>
|
||||
<h4 class="m-t-lg">
|
||||
Button dropdowns
|
||||
</h4>
|
||||
<p class="text-muted">
|
||||
Single button dropdowns
|
||||
</p>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
Action
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success dropdown-toggle" data-toggle="dropdown">
|
||||
Action
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
Action
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
Action
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
Split button dropdowns & variation
|
||||
</p>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-default">
|
||||
Action
|
||||
</button>
|
||||
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group dropup">
|
||||
<button class="btn btn-default">
|
||||
Action
|
||||
</button>
|
||||
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Another action
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Something else here
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider">
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Separated link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="m-t-lg">
|
||||
Button with icon
|
||||
</h4>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default">
|
||||
<i class="fa fa-html5">
|
||||
</i>
|
||||
Html5
|
||||
</a>
|
||||
<a href="#" class="btn btn-info">
|
||||
<i class="fa fa-css3">
|
||||
</i>
|
||||
CSS3
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default btn-lg btn-block">
|
||||
<i class="fa fa-bars pull-right">
|
||||
</i>
|
||||
Block button with icon
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" class="btn btn-default btn-block">
|
||||
<i class="fa fa-bars pull-left">
|
||||
</i>
|
||||
Block button with icon
|
||||
</a>
|
||||
</p>
|
||||
<h4 class="m-t-lg">
|
||||
Button icon
|
||||
</h4>
|
||||
<p id="social-buttons">
|
||||
<a href="#" class="btn btn-sm btn-icon btn-info">
|
||||
<i class="fa fa-twitter">
|
||||
</i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-sm btn-icon btn-success">
|
||||
<i class="fa fa-facebook">
|
||||
</i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-sm btn-icon btn-danger">
|
||||
<i class="fa fa-google-plus">
|
||||
</i>
|
||||
</a>
|
||||
</p>
|
||||
<h4 class="m-t-lg">
|
||||
Button icon rounded
|
||||
</h4>
|
||||
<p id="social-buttons">
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-icon btn-default">
|
||||
<i class="fa fa-twitter">
|
||||
</i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-icon btn-default">
|
||||
<i class="fa fa-facebook">
|
||||
</i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-icon btn-default">
|
||||
<i class="fa fa-google-plus">
|
||||
</i>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4 class="m-t-xs">
|
||||
Rounded button
|
||||
</h4>
|
||||
<div class="doc-buttons">
|
||||
<a href="#" class="btn btn-s-md btn-default btn-rounded">
|
||||
Default
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-primary btn-rounded">
|
||||
Primary
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-success btn-rounded">
|
||||
Success
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-info btn-rounded">
|
||||
Info
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-warning btn-rounded">
|
||||
Warning
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-danger btn-rounded">
|
||||
Danger
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-dark btn-rounded">
|
||||
Dark
|
||||
</a>
|
||||
<a href="#" class="btn btn-s-md btn-default btn-rounded disabled">
|
||||
Disabled
|
||||
</a>
|
||||
</div>
|
||||
<h4 class="m-t-lg">
|
||||
Button groups
|
||||
</h4>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default">
|
||||
Left
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
Middle
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
Right
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
Vertical button groups
|
||||
</p>
|
||||
<div class="btn-group-vertical m-b-sm">
|
||||
<button type="button" class="btn btn-default">
|
||||
Top
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
Middle
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
Bottom
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
Nested button groups
|
||||
</p>
|
||||
<div class="btn-group m-b-sm">
|
||||
<button type="button" class="btn btn-default">
|
||||
1
|
||||
</button>
|
||||
<button type="button" class="btn btn-success">
|
||||
2
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
3
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
Dropdown
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#">
|
||||
Dropdown link
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Dropdown link
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Dropdown link
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
Justified button groups
|
||||
</p>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group btn-group-justified">
|
||||
<a href="#" class="btn btn-primary">
|
||||
Left
|
||||
</a>
|
||||
<a href="#" class="btn btn-info">
|
||||
Middle
|
||||
</a>
|
||||
<a href="#" class="btn btn-success">
|
||||
Right
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
Multiple button groups
|
||||
</p>
|
||||
<div class="btn-toolbar">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default">
|
||||
1
|
||||
</button>
|
||||
<button type="button" class="btn btn-default active">
|
||||
2
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
3
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
4
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default">
|
||||
5
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
6
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
7
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default">
|
||||
8
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="m-t-lg">
|
||||
Button components
|
||||
</h4>
|
||||
<p class="text-muted">
|
||||
<span>
|
||||
There are a few easy ways to quickly get started with Bootstrap, each
|
||||
one ...
|
||||
</span>
|
||||
<span class="text-muted hide" id="moreless">
|
||||
appealing to a different skill level and use case. Read through to see
|
||||
what suits your particular needs.
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<button href="#moreless" class="btn btn-sm btn-default" data-toggle="class:show">
|
||||
<i class="fa fa-plus text">
|
||||
</i>
|
||||
<span class="text">
|
||||
More
|
||||
</span>
|
||||
<i class="fa fa-minus text-active">
|
||||
</i>
|
||||
<span class="text-active">
|
||||
Less
|
||||
</span>
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-default" id="btn-1" href="#btn-1" data-toggle="class:btn-success">
|
||||
<i class="fa fa-cloud-upload text">
|
||||
</i>
|
||||
<span class="text">
|
||||
Upload
|
||||
</span>
|
||||
<i class="fa fa-check text-active">
|
||||
</i>
|
||||
<span class="text-active">
|
||||
Success
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-default" data-toggle="button">
|
||||
<i class="fa fa-heart-o text">
|
||||
</i>
|
||||
<i class="fa fa-heart text-active text-danger">
|
||||
</i>
|
||||
</button>
|
||||
<button class="btn btn-default" data-toggle="button">
|
||||
<span class="text">
|
||||
<i class="fa fa-thumbs-up text-success">
|
||||
</i>
|
||||
25
|
||||
</span>
|
||||
<span class="text-active">
|
||||
<i class="fa fa-thumbs-down text-danger">
|
||||
</i>
|
||||
10
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-success" data-toggle="class:show inline" data-target="#spin"
|
||||
data-loading-text="Saving...">
|
||||
Save
|
||||
</button>
|
||||
<i class="fa fa-spin fa-spinner hide" id="spin">
|
||||
</i>
|
||||
</p>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group" data-toggle="buttons">
|
||||
<label class="btn btn-sm btn-info active">
|
||||
<input type="radio" name="options" id="option1">
|
||||
<i class="fa fa-check text-active">
|
||||
</i>
|
||||
Male
|
||||
</label>
|
||||
<label class="btn btn-sm btn-success">
|
||||
<input type="radio" name="options" id="option2">
|
||||
<i class="fa fa-check text-active">
|
||||
</i>
|
||||
Female
|
||||
</label>
|
||||
<label class="btn btn-sm btn-primary">
|
||||
<input type="radio" name="options" id="option3">
|
||||
<i class="fa fa-check text-active">
|
||||
</i>
|
||||
N/A
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-b-sm">
|
||||
<div class="btn-group" data-toggle="buttons">
|
||||
<label class="btn btn-sm btn-default">
|
||||
<input type="checkbox" name="options" id="option1">
|
||||
option1
|
||||
</label>
|
||||
<label class="btn btn-sm btn-default">
|
||||
<input type="checkbox" name="options" id="option2">
|
||||
option2
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="m-t-lg">
|
||||
Select Button
|
||||
</h5>
|
||||
<div class="btn-group m-r">
|
||||
<button data-toggle="dropdown" class="btn btn-sm btn-default dropdown-toggle">
|
||||
<span class="dropdown-label">
|
||||
Option1
|
||||
</span>
|
||||
<span class="caret">
|
||||
</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-select">
|
||||
<li class="active">
|
||||
<a href="#">
|
||||
<input type="radio" name="d-s-r" checked="">
|
||||
Option1
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<input type="radio" name="d-s-r">
|
||||
Option2
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<input type="radio" name="d-s-r">
|
||||
Option3
|
||||
</a>
|
||||
</li>
|
||||
<li class="disabled">
|
||||
<a href="#">
|
||||
<input type="radio" name="d-s-r" disabled="">
|
||||
I'm disabled
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h4 class="m-t-lg">
|
||||
<a href="#" class="pull-right text-sm" data-toggle="class:btn-rounded"
|
||||
data-target="#social-buttons a">
|
||||
Toggle
|
||||
</a>
|
||||
Social buttons
|
||||
</h4>
|
||||
<p id="social-buttons">
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-twitter">
|
||||
<i class="fa fa-fw fa-twitter">
|
||||
</i>
|
||||
Twitter
|
||||
</a>
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-facebook">
|
||||
<i class="fa fa-fw fa-facebook">
|
||||
</i>
|
||||
Facebook
|
||||
</a>
|
||||
<a href="#" class="btn btn-rounded btn-sm btn-gplus">
|
||||
<i class="fa fa-fw fa-google-plus">
|
||||
</i>
|
||||
Google+
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
3
app/views/Admin/end.html
Normal file
3
app/views/Admin/end.html
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
</body>
|
||||
</html>
|
||||
36
app/views/Admin/footer.html
Normal file
36
app/views/Admin/footer.html
Normal file
@@ -0,0 +1,36 @@
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<!-- Bootstrap -->
|
||||
<!-- App -->
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
<script src="/public/admin/js/artDialog/jquery.artDialog.js?skin=default"></script>
|
||||
<script src="/public/js/common.js"></script>
|
||||
<script src="/public/admin/js/admin.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var pathname = location.pathname;
|
||||
var arr = pathname.split("/");
|
||||
if(arr.length == 0){
|
||||
return;
|
||||
}
|
||||
var controller = "";
|
||||
var action = "";
|
||||
if(arr[0] == "") {
|
||||
arr = arr.slice(1);
|
||||
}
|
||||
controller = arr[0];
|
||||
if(arr.length > 1) {
|
||||
action = arr[1];
|
||||
}
|
||||
$("#nav > li").removeClass("active");
|
||||
$("#" + controller + "Nav").addClass("active");
|
||||
|
||||
$('a[href="' + pathname + '"]').parent().addClass("active");
|
||||
});
|
||||
</script>
|
||||
37
app/views/Admin/header.html
Normal file
37
app/views/Admin/header.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||
<meta name="author" content="leanote">
|
||||
<title>{{.title}}</title>
|
||||
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/admin.css" rel="stylesheet">
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
if(window.console) {
|
||||
console.log(o);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="headerContainer" class="navbar-fixed-top">
|
||||
<div class="container" style="clearfix" id="header">
|
||||
<div class="pull-left">
|
||||
<h1 id="logo" class="clearfix">
|
||||
<a href="/admin/index"></a>
|
||||
<span>Admin</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
106
app/views/Admin/index.html
Normal file
106
app/views/Admin/index.html
Normal file
@@ -0,0 +1,106 @@
|
||||
{{template "admin/top.html" .}}
|
||||
<div class="m-b-md"> <h3 class="m-b-none">Workset</h3> <small>Welcome you!</small> </div>
|
||||
<section class="panel panel-default">
|
||||
<div class="row m-l-none m-r-none bg-light lter">
|
||||
<div class="col-sm-6 col-md-3 padder-v b-r b-light">
|
||||
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||
<i class="fa fa-circle fa-stack-2x text-info"></i>
|
||||
<i class="fa fa-male fa-stack-1x text-white"></i>
|
||||
</span>
|
||||
<a class="clear" href="#">
|
||||
<span class="h3 block m-t-xs"><strong>52,000</strong></span>
|
||||
<small class="text-muted text-uc">users</small>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 padder-v b-r b-light lt">
|
||||
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||
<i class="fa fa-circle fa-stack-2x text-warning"></i>
|
||||
<i class="fa fa-file-o fa-stack-1x text-white"></i>
|
||||
</span>
|
||||
<a class="clear" href="#">
|
||||
<span class="h3 block m-t-xs"><strong>1312,000</strong></span>
|
||||
<small class="text-muted text-uc">notes</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 最新动态 -->
|
||||
<section class="panel panel-default">
|
||||
<h4 class="font-thin padder">
|
||||
Leanote Events
|
||||
</h4>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<p>
|
||||
Wellcome
|
||||
<a href="#" class="text-info">
|
||||
@Drew Wllon
|
||||
</a>
|
||||
and play this web application template, have fun1
|
||||
</p>
|
||||
<small class="block text-muted">
|
||||
<i class="fa fa-clock-o">
|
||||
</i>
|
||||
2 minuts ago
|
||||
</small>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<p>
|
||||
Morbi nec
|
||||
<a href="#" class="text-info">
|
||||
@Jonathan George
|
||||
</a>
|
||||
nunc condimentum ipsum dolor sit amet, consectetur
|
||||
</p>
|
||||
<small class="block text-muted">
|
||||
<i class="fa fa-clock-o">
|
||||
</i>
|
||||
1 hour ago
|
||||
</small>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<p>
|
||||
<a href="#" class="text-info">
|
||||
@Josh Long
|
||||
</a>
|
||||
Vestibulum ullamcorper sodales nisi nec adipiscing elit.
|
||||
</p>
|
||||
<small class="block text-muted">
|
||||
<i class="fa fa-clock-o">
|
||||
</i>
|
||||
2 hours ago
|
||||
</small>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="panel panel-default">
|
||||
<form>
|
||||
<textarea class="form-control no-border" rows="3" placeholder="Suggestions to leanote"></textarea>
|
||||
</form>
|
||||
<footer class="panel-footer bg-light lter">
|
||||
<button class="btn btn-info pull-right btn-sm">
|
||||
POST
|
||||
</button>
|
||||
<ul class="nav nav-pills nav-sm">
|
||||
<!--
|
||||
<li>
|
||||
<a href="#">
|
||||
<i class="fa fa-camera text-muted">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<i class="fa fa-video-camera text-muted">
|
||||
</i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
-->
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
{{template "admin/footer.html" .}}
|
||||
{{template "admin/end.html" .}}
|
||||
125
app/views/Admin/nav.html
Normal file
125
app/views/Admin/nav.html
Normal file
@@ -0,0 +1,125 @@
|
||||
<nav class="nav-primary hidden-xs">
|
||||
<ul class="nav" id="nav">
|
||||
|
||||
<li class="active" id="adminUserNav">
|
||||
<a href="index.html">
|
||||
<i class="fa fa-users icon">
|
||||
<b class="bg-danger">
|
||||
</b>
|
||||
</i>
|
||||
<span class="pull-right">
|
||||
<i class="fa fa-angle-down text">
|
||||
</i>
|
||||
<i class="fa fa-angle-up text-active">
|
||||
</i>
|
||||
</span>
|
||||
<span>
|
||||
User
|
||||
</span>
|
||||
</a>
|
||||
<!-- 导航列表 -->
|
||||
<ul class="nav lt">
|
||||
<li>
|
||||
<a href="/adminUser/index">
|
||||
<span>
|
||||
List
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/adminUser/add">
|
||||
<span>
|
||||
Add User
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/adminBlog/index">
|
||||
<i class="fa fa-file icon">
|
||||
<b class="bg-warning">
|
||||
</b>
|
||||
</i>
|
||||
<span>
|
||||
Blog
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li id="adminSettingNav">
|
||||
<a href="#layout">
|
||||
<i class="fa fa-cog icon">
|
||||
<b class="bg-warning">
|
||||
</b>
|
||||
</i>
|
||||
<span class="pull-right">
|
||||
<i class="fa fa-angle-down text">
|
||||
</i>
|
||||
<i class="fa fa-angle-up text-active">
|
||||
</i>
|
||||
</span>
|
||||
<span>
|
||||
Setting
|
||||
</span>
|
||||
</a>
|
||||
<ul class="nav lt">
|
||||
<li>
|
||||
<a href="layout-c.html">
|
||||
<span>
|
||||
Register
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="layout-c.html">
|
||||
<span>
|
||||
Login
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="layout-r.html">
|
||||
<span>
|
||||
Email
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="layout-h.html">
|
||||
<span>
|
||||
Share
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/adminSetting/blog">
|
||||
<span>
|
||||
Blog
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/adminSetting/demo">
|
||||
<span>
|
||||
Demo User
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#layout">
|
||||
<i class="fa fa-columns icon">
|
||||
<b class="bg-warning">
|
||||
</b>
|
||||
</i>
|
||||
<span>
|
||||
Others
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
106
app/views/Admin/top.html
Normal file
106
app/views/Admin/top.html
Normal file
@@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="app">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>
|
||||
leanote admin
|
||||
</title>
|
||||
<meta name="description" content="leanote admin"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/bootstrap.3.2.0.min.css" rel="stylesheet">
|
||||
<link href="/public/admin/css/admin.css" rel="stylesheet">
|
||||
<!--[if lt IE 9]>
|
||||
<script src="/public/admin/js/ie/html5shiv.js"></script>
|
||||
<script src="/public/admin/js/ie/respond.min.js"></script>
|
||||
<script src="/public/admin/js/ie/excanvas.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body class="">
|
||||
<section class="vbox">
|
||||
<header class="bg-dark dk header navbar navbar-fixed-top-xs">
|
||||
<div class="navbar-header aside-md clearfix" id="logo">
|
||||
<a href="/admin/index" class="navbar-brand" data-toggle="fullscreen"></a>
|
||||
<div>Admin</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav navbar-nav navbar-right m-n hidden-xs nav-user">
|
||||
<li class="hidden-xs">
|
||||
<a href="/index" class="dk">
|
||||
Index
|
||||
</a>
|
||||
</li>
|
||||
<li class="hidden-xs">
|
||||
<a href="/note" class="dk">
|
||||
My Note
|
||||
</a>
|
||||
</li>
|
||||
<li class="hidden-xs">
|
||||
<a href="/blog/admin" class="dk">
|
||||
Blog
|
||||
</a>
|
||||
</li>
|
||||
<li class="hidden-xs">
|
||||
<a href="/blog/admin" class="dk">
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<section>
|
||||
<section class="hbox stretch">
|
||||
<!-- .aside -->
|
||||
<aside class="bg-light lter b-r aside-md hidden-print hidden-xs" id="nav">
|
||||
<section class="vbox">
|
||||
<header class="header bg-primary lter text-center clearfix">
|
||||
<div class="btn-group">
|
||||
<div class="hidden-nav-xs">
|
||||
<a class="btn btn-sm btn-primary">
|
||||
Welcome, admin!
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="w-f scrollable">
|
||||
<div class="slim-scroll" data-height="auto" data-disable-fade-out="true"
|
||||
data-distance="0" data-size="5px" data-color="#333333">
|
||||
<!-- nav -->
|
||||
{{template "admin/nav.html" .}}
|
||||
<!-- / nav -->
|
||||
</div>
|
||||
</section>
|
||||
<footer class="footer lt hidden-xs b-t b-light">
|
||||
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
|
||||
<i class="fa fa-angle-left text">
|
||||
</i>
|
||||
<i class="fa fa-angle-right text-active">
|
||||
</i>
|
||||
</a>
|
||||
|
||||
</footer>
|
||||
</section>
|
||||
</aside>
|
||||
<!-- /.aside -->
|
||||
<section id="content">
|
||||
<section class="vbox">
|
||||
<section class="scrollable padder">
|
||||
<!-- 导航 -->
|
||||
<ul class="breadcrumb no-border no-radius b-b b-light pull-in">
|
||||
<li>
|
||||
<a href="index.html">
|
||||
<i class="fa fa-home">
|
||||
</i>
|
||||
Home
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
Elements
|
||||
</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
Components
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 主要内容区 -->
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div id="posts">
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
关于我
|
||||
{{msg . "aboutMe"}}
|
||||
</div>
|
||||
<div class="created-time">
|
||||
</div>
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
{{$userId := .userBlog.UserId.Hex}}
|
||||
<div class="container" id="footer">
|
||||
<div class="col-md-4">
|
||||
<h3>导航</h3>
|
||||
<h3>{{msg . "blogNavs"}}</h3>
|
||||
<ul>
|
||||
<li><a href="/blog/{{$userId}}">首页</a></li>
|
||||
<li><a href="/blog/{{$userId}}">{{msg . "home"}}</a></li>
|
||||
{{range .notebooks}}
|
||||
<li>
|
||||
<a href="/blog/{{$userId}}/{{.NotebookId.Hex}}">{{.Title}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li><a href="/blog/aboutMe/{{$userId}}">关于我</a></li>
|
||||
<li><a href="/blog/aboutMe/{{$userId}}">{{msg . "aboutMe"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h3>最近发表</h3>
|
||||
<h3>{{msg . "latestPosts"}}</h3>
|
||||
<ul>
|
||||
{{range .recentBlogs}}
|
||||
<li title="{{.Title}}"><a href="/blog/view/{{.NoteId.Hex}}/">{{.Title}}</a></li>
|
||||
@@ -22,10 +22,10 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h3>快速链接</h3>
|
||||
<h3>{{msg . "quickLinks"}}</h3>
|
||||
<ul>
|
||||
<li><a href="/note">我的笔记</a></li>
|
||||
<li><a href="/login">登录</a></li>
|
||||
<li><a href="/note">{{msg . "myNote"}}</a></li>
|
||||
<li><a href="/login">{{msg . "login"}}</a></li>
|
||||
<li><a href="http://leanote.com" target="_blank">leanote</a></li>
|
||||
<li><a href="https://github.com/leanote/leanote" target="_blank">leanote github</a></li>
|
||||
</ul>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||
<meta name="author" content="leanote">
|
||||
|
||||
<title>{{.title}}</title>
|
||||
@@ -58,17 +58,17 @@ function log(o) {
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
{{$navNotebookId := .notebookId}}
|
||||
<li class="{{if .index}}active{{end}}"><a href="/blog/{{$username}}">首页</a></li>
|
||||
<li class="{{if .index}}active{{end}}"><a href="/blog/{{$username}}">{{msg . "home"}}</a></li>
|
||||
{{range .notebooks}}
|
||||
{{$notebookId := .NotebookId.Hex}}
|
||||
<li class="{{if eq $navNotebookId $notebookId}}active{{else}}{{end}}">
|
||||
<li class="{{if $navNotebookId}}{{if eq $navNotebookId $notebookId}}active{{else}}{{end}}{{end}}">
|
||||
<a href="/blog/{{$username}}/{{$notebookId}}"
|
||||
>{{.Title}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li class="{{if .aboutMe}}active{{end}}"><a href="/blog/aboutMe/{{$username}}">关于我</a></li>
|
||||
<li class="{{if .aboutMe}}active{{end}}"><a href="/blog/aboutMe/{{$username}}">{{msg . "aboutMe"}}</a></li>
|
||||
{{if .isMe}}
|
||||
<li class="{{if .set}}active{{end}}"><a href="/blog/set" >博客设置</a></li>
|
||||
<li class="{{if .set}}active{{end}}"><a href="/blog/set">{{msg . "blogSet"}}</a></li>
|
||||
<li><a href="/note" >{{msg . "myNote"}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<!-- This file is Depreciated -->
|
||||
|
||||
<link href="/public/mdeditor/editor/google-code-prettify/prettify.css" type="text/css" rel="stylesheet">
|
||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
<div id="postsContainer">
|
||||
<div class="container">
|
||||
{{if .notebookId}}
|
||||
<h2>分类 {{.notebook.Title}}</h2>
|
||||
<h2>{{msg . "blogClass"}}: {{.notebook.Title}}</h2>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="posts">
|
||||
{{$G := .}}
|
||||
{{range .blogs}}
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
<a href="/blog/view/{{.NoteId.Hex}}" title="全文">
|
||||
<a href="/blog/view/{{.NoteId.Hex}}" title="{{msg $G "fullBlog"}}">
|
||||
{{.Title}}
|
||||
</a>
|
||||
</div>
|
||||
@@ -19,16 +20,16 @@
|
||||
{{if .Tags}}
|
||||
{{blogTags .Tags}}
|
||||
{{else}}
|
||||
无
|
||||
{{msg $G "noTag"}}
|
||||
{{end}}
|
||||
|
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 更新 {{.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 创建 {{.CreatedTime | datetime}}
|
||||
<i class="fa fa-calendar" style="color: #666"></i> {{msg $G "updatedTime"}} {{.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> {{msg $G "createdTime"}} {{.CreatedTime | datetime}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{.Content | raw}}
|
||||
</div>
|
||||
<a class="more" href="/blog/view/{{.NoteId.Hex}}" title="更多">More...</a>
|
||||
<a class="more" href="/blog/view/{{.NoteId.Hex}}" title="{{msg $G "fullBlog"}}">More...</a>
|
||||
</div>
|
||||
{{end}}
|
||||
<!-- 分页 -->
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<!-- -->
|
||||
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css"
|
||||
type="text/css">
|
||||
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
|
||||
<style>
|
||||
.tab-pane {
|
||||
padding-top: 10px;
|
||||
@@ -11,9 +10,9 @@
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<ul id="myTab" class="nav nav-tabs">
|
||||
<li class="active"><a href="#baseInfo" data-toggle="tab">基本设置</a></li>
|
||||
<li class=""><a href="#commentInfo" data-toggle="tab">评论设置</a></li>
|
||||
<li class=""><a href="#styleInfo" data-toggle="tab">主题设置</a></li>
|
||||
<li class="active"><a href="#baseInfo" data-toggle="tab">{{msg . "baseInfoSet"}}</a></li>
|
||||
<li class=""><a href="#commentInfo" data-toggle="tab">{{msg . "commentSet"}}</a></li>
|
||||
<li class=""><a href="#styleInfo" data-toggle="tab">{{msg . "themeSet"}}</a></li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
@@ -21,7 +20,7 @@
|
||||
<div class="tab-pane" id="styleInfo">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="Style" class="col-sm-2 control-label">主题</label>
|
||||
<label for="Style" class="col-sm-2 control-label">{{msg . "theme"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_default"
|
||||
@@ -32,19 +31,19 @@
|
||||
checked="checked"
|
||||
{{end}}
|
||||
{{end}}>
|
||||
默认 </label>
|
||||
{{msg . "default"}} </label>
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_daqi"
|
||||
{{if eq .userBlog.Style "blog_daqi"}}checked="checked"{{end}}>
|
||||
大气</label>
|
||||
{{msg . "elegant"}}</label>
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_left_fixed"
|
||||
{{if eq .userBlog.Style "blog_left_fixed"}}checked="checked"{{end}}>
|
||||
左侧导航固定</label>
|
||||
{{msg . "navFixed"}}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<button class="btn btn-success">{{msg . "save"}}</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,26 +53,25 @@
|
||||
<div class="tab-pane" id="commentInfo">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="subTitle" class="col-sm-2 control-label">开启评论</label>
|
||||
<label for="subTitle" class="col-sm-2 control-label">{{msg . "openComment"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="checkbox" id="CanComment" name="CanComment"
|
||||
{{if .userBlog.CanComment}}checked="checked"{{end}} >
|
||||
<br />
|
||||
leanote采用 <a href="http://disqus.com" target="_blank">Disqus</a>
|
||||
作为评论系统
|
||||
{{msg . "commentSys"}}
|
||||
<div id="disqusSet">
|
||||
<label for="DisqusId">Disqus Id</label> <input type="text"
|
||||
class="form-control" style="display: inline; width: 50%"
|
||||
id="DisqusId" name="DisqusId"
|
||||
value="{{if .userBlog.DisqusId}}{{.userBlog.DisqusId}}{{else}}leanote{{end}}">
|
||||
<br /> (请填写您申请的Disqus唯一url前缀, 建议您申请Disqus帐号, 这样可以自己管理评论.
|
||||
或使用leanote的默认Disqus Id. <a target="_blank"
|
||||
href="/blog/view/52db8463e01c530ef8000001">需要帮助?</a>)
|
||||
<br />
|
||||
{{msg . "disqusHelp"}}
|
||||
<a target="_blank" href="http://leanote.com/blog/view/52db8463e01c530ef8000001">{{msg . "needHelp"}}</a>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<button class="btn btn-success">{{msg . "save"}}</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,16 +88,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-sm-2 control-label">博客名称</label>
|
||||
<label for="title" class="col-sm-2 control-label">{{msg . "blogName"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="Title" name="Title"
|
||||
placeholder="比如: leanote的博客"
|
||||
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 的博客{{end}}">
|
||||
placeholder="eg: leanote's blog"
|
||||
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 's blog{{end}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="logo" class="col-sm-2 control-label">博客Logo</label>
|
||||
<label for="logo" class="col-sm-2 control-label">{{msg . "blogLogo"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="hidden" name="Logo" id="Logo"
|
||||
value="{{.userBlog.Logo}}" />
|
||||
@@ -107,14 +105,15 @@
|
||||
enctype="multipart/form-data" target="logoTarget"
|
||||
onsubmit="inProgress()">
|
||||
<input type="file" class="form-control" id="logo2" name="file"
|
||||
onChange='$("#formLogo").submit();' /> 上传logo将显示logo(替代博客标题)
|
||||
onChange='$("#formLogo").submit();' />
|
||||
{{msg . "blogLogoTips"}}
|
||||
<div id="logoImg"
|
||||
{{if .userBlog.Logo }}
|
||||
{{else}}
|
||||
style="display: none"{{end}}
|
||||
>
|
||||
<img src="{{.userBlog.Logo}}" style="height: 40px" /> <a
|
||||
href="#" id="deleteLogo">删除</a>
|
||||
href="#" id="deleteLogo">{{msg . "delete"}}</a>
|
||||
</div>
|
||||
</form>
|
||||
<iframe id="logoTarget" name="logoTarget" src="#"
|
||||
@@ -123,11 +122,11 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="subTitle" class="col-sm-2 control-label">博客描述</label>
|
||||
<label for="subTitle" class="col-sm-2 control-label">{{msg . "blogDesc"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="SubTitle"
|
||||
name="SubTitle" value="{{.userBlog.SubTitle}}"
|
||||
placeholder="比如: leanote, 不只是笔记">
|
||||
placeholder="eg: leanote, {{msg $ "moto"}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -139,7 +138,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="aboutMe" class="col-sm-2 control-label">关于我</label>
|
||||
<label for="aboutMe" class="col-sm-2 control-label">{{msg . "aboutMe"}}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea id="AboutMe" name="AboutMe">{{.userBlog.AboutMe}}</textarea>
|
||||
</div>
|
||||
@@ -147,7 +146,7 @@
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<button class="btn btn-success">{{msg . "save"}}</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -167,19 +166,17 @@
|
||||
$(function() {
|
||||
tinymce.init({
|
||||
selector : "#AboutMe",
|
||||
content_css : [ "/css/bootstrap.css", "/css/editor.css" ],
|
||||
content_css : [ "/css/bootstrap.css", "/css/editor/editor.css" ],
|
||||
skin : "custom",
|
||||
language : "zh_CN",
|
||||
language : "{{.locale}}",
|
||||
height : 300,
|
||||
width : "100%",
|
||||
skin : "custom",
|
||||
plugins : [
|
||||
"advlist autolink link image lists charmap hr ",
|
||||
"searchreplace visualblocks visualchars code tabfocus",
|
||||
"table contextmenu directionality textcolor paste fullpage textcolor" ],
|
||||
|
||||
toolbar1 : "formatselect fontselect fontsizeselect | forecolor backcolor | bold italic underline strikethrough | image | bullist numlist | alignleft aligncenter alignright alignjustify",
|
||||
toolbar2 : "outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript | visualchars visualblocks | searchreplace | code",
|
||||
|
||||
"advlist autolink link leanote_image lists charmap hr ",
|
||||
"searchreplace visualblocks visualchars leanote_code tabfocus",
|
||||
"table contextmenu directionality textcolor paste fullpage textcolor"],
|
||||
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
|
||||
menubar : false,
|
||||
toolbar_items_size : 'small',
|
||||
statusbar : false,
|
||||
@@ -218,7 +215,7 @@ $(function() {
|
||||
}
|
||||
|
||||
post("/blog/setUserBlogBase", data, function(ret) {
|
||||
showMsg2($("#baseInfo .msg"), "保存成功", 2000);
|
||||
showMsg2($("#baseInfo .msg"), "{{msg . "saveSuccess"}}", 2000);
|
||||
$("#blogDesc").html(data.SubTitle);
|
||||
$("#logo").html(data.Title);
|
||||
if(data.Logo) {
|
||||
@@ -234,7 +231,7 @@ $(function() {
|
||||
DisqusId : $("#DisqusId").val(),
|
||||
}
|
||||
post("/blog/setUserBlogComment", data, function(ret) {
|
||||
showMsg2($("#commentInfo .msg"), "保存成功", 2000);
|
||||
showMsg2($("#commentInfo .msg"), "{{msg . "saveSuccess"}}", 2000);
|
||||
}, this);
|
||||
});
|
||||
// 主题
|
||||
@@ -244,7 +241,7 @@ $(function() {
|
||||
Style : $("input[name='Style']:checked").val()
|
||||
}
|
||||
post("/blog/setUserBlogStyle", data, function(ret) {
|
||||
showMsg2($("#styleInfo .msg"), "保存成功", 2000);
|
||||
showMsg2($("#styleInfo .msg"), "{{msg . "saveSuccess"}}", 2000);
|
||||
}, this);
|
||||
});
|
||||
$("input[name='Style']").click(function() {
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
{{if .blog.Tags}}
|
||||
{{blogTags .blog.Tags}}
|
||||
{{else}}
|
||||
无
|
||||
{{msg . "noTag"}}
|
||||
{{end}}
|
||||
|
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 更新 {{.blog.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 创建 {{.blog.CreatedTime | datetime}}
|
||||
<i class="fa fa-calendar" style="color: #666"></i> {{msg . "updatedTime"}} {{.blog.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> {{msg . "createdTime"}} {{.blog.CreatedTime | datetime}}
|
||||
</div>
|
||||
|
||||
<div class="desc" id="content">
|
||||
@@ -93,7 +93,7 @@
|
||||
<div id="blogNav">
|
||||
<div id="blogNavNav">
|
||||
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||
<span>{{msg . "nav"}}</span>
|
||||
<span>{{msg . "blogNav"}}</span>
|
||||
</div>
|
||||
<div id="blogNavContent" style="max-width: 200px">
|
||||
</div>
|
||||
|
||||
@@ -5,14 +5,31 @@
|
||||
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>error-404</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div>
|
||||
<h1 class="h text-white animated fadeInDownBig">404</h1>
|
||||
</div>
|
||||
<div id="errorBox">
|
||||
<p class="error-info">
|
||||
This page cann't found.
|
||||
<br />
|
||||
<a href="javascript:history.go(-1)">Back</a>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
<div class="list-group m-b-sm bg-white m-b-lg">
|
||||
<a href="javascript:history.go(-1);" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-arrow-left icon-muted"></i> Back </a>
|
||||
<a href="/index" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-home icon-muted"></i> Goto homepage </a>
|
||||
<a href="/note" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-file-o icon-muted"></i> My note</a>
|
||||
<a class="list-group-item" href="mailto:leanote@leanote.com">
|
||||
<span class="badge">leanote@leanote.com</span>
|
||||
<i class="fa fa-fw fa-envelope-o icon-muted"></i> Contact Us </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
{{end}}
|
||||
@@ -5,14 +5,31 @@
|
||||
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>error-500</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
Sorry, we got a error.
|
||||
<br />
|
||||
<a href="javascript:history.go(-1)">Back</a>
|
||||
</form>
|
||||
<div>
|
||||
<h1 class="h text-white animated fadeInDownBig">404</h1>
|
||||
</div>
|
||||
<div id="errorBox">
|
||||
<p class="error-info">
|
||||
Sorry, we got an error.
|
||||
</p>
|
||||
|
||||
<div class="list-group m-b-sm bg-white m-b-lg">
|
||||
<a href="javascript:history.go(-1);" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-arrow-left icon-muted"></i> Back </a>
|
||||
<a href="/index" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-home icon-muted"></i> Goto homepage </a>
|
||||
<a href="/note" class="list-group-item"><!-- <i class="fa fa-chevron-right icon-muted"> --></i> <i class="fa fa-fw fa-file-o icon-muted"></i> My note</a>
|
||||
<a class="list-group-item" href="mailto:leanote@leanote.com">
|
||||
<span class="badge">leanote@leanote.com</span>
|
||||
<i class="fa fa-fw fa-envelope-o icon-muted"></i> Contact Us </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
{{end}}
|
||||
@@ -1,32 +1,36 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<style>
|
||||
</style>
|
||||
<section id="box">
|
||||
<section id="box" class="animated fadeInUp">
|
||||
<div>
|
||||
<h1>leanote | {{msg . "findPassword"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 110px"><label for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "findPassword"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
<h1 id="logo">leanote</h1>
|
||||
<div id="boxForm">
|
||||
<div id="boxHeader">{{msg . "findPassword"}}</div>
|
||||
<form>
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}">
|
||||
</div>
|
||||
|
||||
<button id="loginBtn" class="btn btn-success">{{msg . "findPassword"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
|
||||
@@ -1,44 +1,45 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
|
||||
<section id="box" class="animated fadeInUp">
|
||||
<div>
|
||||
<h1>leanote | {{msg . "updatePassword"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="form-group">
|
||||
</div>
|
||||
<div class="alert alert-danger" id="loginMsg"> </div>
|
||||
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 350px"><label for="email">{{msg . "email"}}</label>
|
||||
<h1 id="logo">leanote</h1>
|
||||
<div id="boxForm">
|
||||
<div id="boxHeader">{{msg . "updatePassword"}}</div>
|
||||
<form>
|
||||
<div class="alert alert-danger" id="loginMsg"> </div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="email">{{msg . "email"}}</label>
|
||||
<br />
|
||||
{{.findPwd.Email}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "updatePassword"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2" >
|
||||
</div>
|
||||
<button id="loginBtn" class="btn btn-success">{{msg . "updatePassword"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<section id="box">
|
||||
<section id="box" class="animated fadeInUp">
|
||||
<div>
|
||||
<h1>leanote {{msg . "findPassword"}} - {{msg . "findPasswordTimeout"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg" style="display: block">
|
||||
{{msg . "findPasswordTimeout"}}, <a href="/findPassword">{{msg . "reFindPassword"}}</a>
|
||||
</div>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
<h1 id="logo">leanote</h1>
|
||||
<div id="boxForm">
|
||||
<div id="boxHeader">{{msg . "findPasswordTimeout"}}</div>
|
||||
<form>
|
||||
<div class="alert alert-danger" id="loginMsg" style="display: block">
|
||||
{{msg . "findPasswordTimeout"}}, <a href="/findPassword">{{msg . "reFindPassword"}}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
<i class="fa fa-globe fa-3x icon-muted"></i>
|
||||
<h2>Join Us</h2>
|
||||
<a href="https://github.com/leanote/leanote">github leanote</a>
|
||||
<br />
|
||||
QQ Group: 158716820
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||
<meta name="author" content="leanote">
|
||||
<title>{{.title}}</title>
|
||||
|
||||
@@ -27,7 +27,7 @@ function log(o) {
|
||||
<div class="pull-left">
|
||||
<h1>
|
||||
<a href="/index">
|
||||
<img src="/images/logo.png" id="" style="height: 40px" title="leanote, Your own cloud note!"/>
|
||||
<img src="/images/logo/leanote_black.png" id="" style="height: 50px" title="leanote, {{msg $ "moto"}}"/>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -47,8 +47,22 @@ function log(o) {
|
||||
|
||||
<ul id="blogNav" class="pull-right">
|
||||
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||
<!--
|
||||
<li><a href="/index#aboutLeanote" target="#aboutLeanote" class="smooth-scroll">{{msg . "aboutLeanote"}}</a> </li>
|
||||
<li><a id="leanoteBlog" href="http://leanote.com/blog/leanote" target="_blank" class="">{{msg . "leanoteBlog"}}</a></li>
|
||||
-->
|
||||
<li><a href="/index#download" target="#download" class="smooth-scroll">{{msg . "download"}}</a> </li>
|
||||
<li><a href="/index#donate" target="#donate" class="smooth-scroll">{{msg . "donate"}}</a> </li>
|
||||
<li><a id="leanoteBlog" href="http://leanote.com/lea/index" target="_blank" title="lea++, leanote博客平台" class="">lea++</a></li>
|
||||
<li style="position: relative; margin-right: 3px;">
|
||||
<a href="http://bbs.leanote.com" target="_blank" class="">{{msg . "discussion"}}</a>
|
||||
<div style="position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: red;
|
||||
top: 15px;
|
||||
right: 5px;
|
||||
border-radius: 9px;"></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="description" content="leanote, {{msg $ "moto"}}">
|
||||
<meta name="author" content="leanote">
|
||||
<title>{{.title}}</title>
|
||||
|
||||
@@ -18,4 +18,4 @@ html, body {
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body id="boxBody">
|
||||
@@ -4,18 +4,19 @@
|
||||
</style>
|
||||
<section>
|
||||
<div class="header">
|
||||
<h2>leanote, Your own cloud note!</h2>
|
||||
<p>Knowledge, Sharing, Cooperation, Blog... all just in leanote</p>
|
||||
<h2>leanote, {{msg . "moto"}}</h2>
|
||||
<p>{{msg . "moto3"}}</p>
|
||||
<p>{{msg . "moto2"}}</p>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">Fork leanote from Github</a>
|
||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/demo">Try it</a>
|
||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||
{{if .openRegister}}
|
||||
|
||||
|
||||
OR
|
||||
OR
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||
@@ -61,6 +62,52 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="download">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:300px; margin:auto; padding: 10px;">
|
||||
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||
<br />
|
||||
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="donate">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:500px; margin:auto; padding: 10px;">
|
||||
<p>
|
||||
您可以通过支付宝向leanote捐赠, 所捐赠的钱将用来leanote开发.
|
||||
</p>
|
||||
<p>
|
||||
支付宝账号: <b>pay@leanote.com</b>
|
||||
</p>
|
||||
<p>
|
||||
或使用支付宝扫以下二维码捐赠:
|
||||
</p>
|
||||
<p style="text-align: center">
|
||||
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 10px;"/>
|
||||
</p>
|
||||
<p>
|
||||
我们会定期将捐赠名单发布在 <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">捐赠列表</a>
|
||||
</p>
|
||||
<p>
|
||||
感谢您对leanote的支持!
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
有任何疑问, 建议或需其它服务或支持, 欢迎联系 <code>leanote@leanote.com</code> 或加入官方QQ群: <code>158716820</code> 谢谢!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "home/footer.html"}}
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
|
||||
140
app/views/Home/index_en.html
Normal file
140
app/views/Home/index_en.html
Normal file
@@ -0,0 +1,140 @@
|
||||
{{template "home/header.html" .}}
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<section>
|
||||
<div class="header">
|
||||
<h2>leanote, {{msg . "moto"}}</h2>
|
||||
<p>{{msg . "moto3"}}</p>
|
||||
<p>
|
||||
Knowledge, Blog, Sharing, Cooperation... all in leanote
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||
{{if .openRegister}}
|
||||
|
||||
|
||||
OR
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview" style="position: relative;">
|
||||
<div>
|
||||
<div class="img-header">
|
||||
<img src="/images/home/mac-btns.png"/>
|
||||
</div>
|
||||
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||
</div>
|
||||
<div class="mobile">
|
||||
<div class="mobile-header">
|
||||
<img src="/images/home/mac-dot.png" />
|
||||
</div>
|
||||
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container" id="aboutLeanote">
|
||||
<h2>{{msg . "aboutLeanote"}}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "knowledge"}}</h3>
|
||||
<p>{{msg . "knowledgeInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "share"}}</h3>
|
||||
<p>{{msg . "shareInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "cooperation"}}</h3>
|
||||
<p>{{msg . "cooperationInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "blog"}}</h3>
|
||||
<p>{{msg . "blogInfo"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="container" id="download">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:300px; margin:auto; padding: 10px;">
|
||||
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||
<br />
|
||||
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="container" id="donate">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:500px; margin:auto; padding: 10px;">
|
||||
<p>
|
||||
You can use <a href="http://alipay.com">alipay</a> to donate us, The donated money will be used to develop leanote.
|
||||
</p>
|
||||
<p>
|
||||
Alipay Account: <b>pay@leanote.com</b>
|
||||
</p>
|
||||
<p>
|
||||
Or you can use alipay app to scan the code to donate us:
|
||||
</p>
|
||||
<p style="text-align: center">
|
||||
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 10px; width: 200px;"/>
|
||||
</p>
|
||||
<p>
|
||||
The donation list will be published at <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">Donation List</a>
|
||||
</p>
|
||||
<p>
|
||||
Thanks for your support!
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
<p>
|
||||
Any questions, suggestions or need more supports, you are welcomed to contact us via <code>leanote@leanote.com</code> or the QQ Group <code>158716820</code> Thanks!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "home/footer.html"}}
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
/*
|
||||
var u = navigator.userAgent;
|
||||
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||
if(isMobile || $("body").width() < 600) {
|
||||
location.href = "/mobile/index";
|
||||
}
|
||||
*/
|
||||
// 平滑滚动
|
||||
$(".smooth-scroll").click(function(e) {
|
||||
e.preventDefault();
|
||||
var t = $(this).attr("target");
|
||||
var targetOffset = $(t).offset().top - 80;
|
||||
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
139
app/views/Home/index_zh.html
Normal file
139
app/views/Home/index_zh.html
Normal file
@@ -0,0 +1,139 @@
|
||||
{{template "home/header.html" .}}
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<section>
|
||||
<div class="header">
|
||||
<h2>leanote, {{msg . "moto"}}</h2>
|
||||
<p>{{msg . "moto3"}}</p>
|
||||
<p>{{msg . "moto2"}}</p>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">{{msg . "fork github"}}</a>
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/demo">{{msg . "try"}}</a>
|
||||
{{if .openRegister}}
|
||||
|
||||
|
||||
OR
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview" style="position: relative;">
|
||||
<div>
|
||||
<div class="img-header">
|
||||
<img src="/images/home/mac-btns.png"/>
|
||||
</div>
|
||||
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||
</div>
|
||||
<div class="mobile">
|
||||
<div class="mobile-header">
|
||||
<img src="/images/home/mac-dot.png" />
|
||||
</div>
|
||||
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container" id="aboutLeanote">
|
||||
<h2>{{msg . "aboutLeanote"}}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "knowledge"}}</h3>
|
||||
<p>{{msg . "knowledgeInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "share"}}</h3>
|
||||
<p>{{msg . "shareInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "cooperation"}}</h3>
|
||||
<p>{{msg . "cooperationInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "blog"}}</h3>
|
||||
<p>{{msg . "blogInfo"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="container" id="download">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "download"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:300px; margin:auto; padding: 10px;">
|
||||
Linux : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-linux-v0.4.bin.tar.gz">leanote-linux-v0.4.bin.tar.gz</a> <br />
|
||||
MacOS X : <a href="https://github.com/leanote/leanote/releases/download/0.4/leanote-mac-v0.4.bin.tar.gz">leanote-mac-v0.4.bin.tar.gz</a> <br />
|
||||
<br />
|
||||
<a href="https://github.com/leanote/leanote#3-how-to-install-leanote">{{msg . "howToInstallLeanote"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="container" id="donate">
|
||||
<h2 style="margin: 20px 0;text-align: center;">{{msg . "donate"}}</h2>
|
||||
<div class="row">
|
||||
<div style="width:500px; margin:auto; padding: 10px;">
|
||||
<p>
|
||||
您可以通过<a href="http://alipay.com">支付宝</a>向leanote捐赠, 所捐赠的款项将用于开发leanote.
|
||||
</p>
|
||||
<p>
|
||||
支付宝账号: <b>pay@leanote.com</b>
|
||||
</p>
|
||||
<p>
|
||||
或使用支付宝扫以下二维码捐赠:
|
||||
</p>
|
||||
<p style="text-align: center">
|
||||
<img src="/images/leanote/leanote_alipay.jpg" style="padding: 10px;
|
||||
border: 2px solid #eee;
|
||||
border-radius: 10px; width: 200px;"/>
|
||||
</p>
|
||||
<p>
|
||||
我们会定期将捐赠名单发布在 <a href="http://leanote.com/blog/view/5417ecf81a910828fd000000">捐赠列表</a>
|
||||
</p>
|
||||
<p>
|
||||
感谢您对leanote的支持!
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
有任何疑问, 建议或需其它服务或支持, 欢迎联系 <code>leanote@leanote.com</code> 或加入官方QQ群: <code>158716820</code> 谢谢!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "home/footer.html"}}
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
/*
|
||||
var u = navigator.userAgent;
|
||||
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||
if(isMobile || $("body").width() < 600) {
|
||||
location.href = "/mobile/index";
|
||||
}
|
||||
*/
|
||||
// 平滑滚动
|
||||
$(".smooth-scroll").click(function(e) {
|
||||
e.preventDefault();
|
||||
var t = $(this).attr("target");
|
||||
var targetOffset = $(t).offset().top - 80;
|
||||
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,51 +1,57 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
<section id="box" class="animated fadeInUp">
|
||||
<!--
|
||||
<div>
|
||||
<a class="back" href="javascript:history.go(-1);" tabindex="-1">←Back</a>
|
||||
</div>
|
||||
-->
|
||||
<div>
|
||||
<h1>leanote | {{msg . "login"}}</h1>
|
||||
<form class="form-inline" id="boxForm" >
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="email">{{msg . "usernameOrEmail"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "login"}}</button>
|
||||
<br />
|
||||
<a href="/findPassword">{{msg . "forgetPassword"}}</a>
|
||||
{{if .openRegister}}
|
||||
<br />
|
||||
<a href="/register">{{msg . "register"}}</a>
|
||||
{{msg . "or"}}
|
||||
<a href="/demo">{{msg . "try"}}</a>
|
||||
<div style="border-top: 1px dashed #666;margin:2px 0">
|
||||
{{msg . "3th"}}: <a id="github">github<i class="fa fa-github"></i></a>
|
||||
<span id="thirdLoginLoading" style="display: none"> <img src="/images/loading-a-20-2.gif" />正在登录...</span>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
<h1 id="logo">leanote</h1>
|
||||
<div id="boxForm">
|
||||
<div id="boxHeader">{{msg . "login"}}</div>
|
||||
<form>
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">{{msg . "usernameOrEmail"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
</div>
|
||||
<div class="clearfix">
|
||||
<a href="/findPassword" class="pull-right m-t-xs"><small>{{msg . "forgetPassword"}}</small></a>
|
||||
<button id="loginBtn" class="btn btn-success">{{msg . "login"}}</button>
|
||||
</div>
|
||||
<div class="line line-dashed"></div>
|
||||
|
||||
<a href="#" id="github" class="btn btn-github btn-block m-b-sm"><i class="fa fa-github pull-left"></i>{{msg . "use"}} Github</a>
|
||||
|
||||
<div class="line line-dashed"></div>
|
||||
|
||||
<p class="text-muted text-center"><small>{{msg . "hasAcount"}}</small></p>
|
||||
|
||||
{{if .openRegister}}
|
||||
<a href="/register" class="btn btn-default btn-block">{{msg . "register"}}</a>
|
||||
{{end}}
|
||||
|
||||
{{msg . "or"}}
|
||||
|
||||
<a id="loginBtn" href="/demo" class="btn btn-default btn-block">{{msg . "try"}}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
@@ -98,7 +104,7 @@ $(function() {
|
||||
|
||||
// github
|
||||
$("#github").click(function() {
|
||||
$("#thirdLoginLoading").show();
|
||||
$(this).button("loading");
|
||||
location.href="https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2Fleanote.com%2Foauth%2FgithubCallback&response_type=code&scope=user&state=";
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
<section id="box" class="animated fadeInUp">
|
||||
<!--
|
||||
<div>
|
||||
<a class="back" href="javascript:history.go(-1);" tabindex="-1">←Back</a>
|
||||
</div>
|
||||
-->
|
||||
<div>
|
||||
<h1>leanote | {{msg . "register"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</td>
|
||||
</tr>
|
||||
<h1 id="logo">leanote</h1>
|
||||
<div id="boxForm">
|
||||
<div id="boxHeader">{{msg . "register"}}</div>
|
||||
<form>
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2" >
|
||||
</div>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
<button id="registerBtn" class="btn btn-success">{{msg . "register"}}</button>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="registerBtn" class="btn btn-success" style="width: 100%">{{msg . "register"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="line line-dashed"></div>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
<p class="text-muted text-center"><small>{{msg . "hadAcount"}}</small></p>
|
||||
|
||||
<a id="loginBtn" href="/login" class="btn btn-default btn-block">{{msg . "login"}}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="boxFooter">
|
||||
<p>
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="/index">leanote</a> © 2014
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user