Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
371f5e23c3 | ||
|
|
825fda5544 | ||
|
|
6ede5c1559 | ||
|
|
1ff90dacde | ||
|
|
2654b684df | ||
|
|
d424395d85 | ||
|
|
54810b3458 | ||
|
|
1cf66ad6c0 | ||
|
|
6dc334ca51 | ||
|
|
f9b4ead6be | ||
|
|
3bf6703929 | ||
|
|
ec657b9dcb | ||
|
|
4ffd048b2a | ||
|
|
6af19670da | ||
|
|
721e375d76 | ||
|
|
41f95cf0e5 | ||
|
|
ba411ef580 | ||
|
|
9dcf0ed53e | ||
|
|
d5d853ffd3 | ||
|
|
ae29119664 | ||
|
|
ad644258f5 | ||
|
|
8c98f4da5c | ||
|
|
e2585bf695 | ||
|
|
3b9bc687c4 | ||
|
|
2db182db1b | ||
|
|
f3e1eb6c3f | ||
|
|
956e1ba2bb | ||
|
|
f294fa4124 | ||
|
|
cabf89f9b8 | ||
|
|
d183cd5a77 | ||
|
|
000dfea92d | ||
|
|
a53398ebb4 | ||
|
|
b23592229a | ||
|
|
584bde247e | ||
|
|
6774392807 | ||
|
|
964cf1a750 | ||
|
|
52128e6453 |
No files matched your search
@@ -7,7 +7,6 @@ bin/release
|
|||||||
bin/test.sh
|
bin/test.sh
|
||||||
bin/tmp
|
bin/tmp
|
||||||
bin/test
|
bin/test
|
||||||
bin/src
|
|
||||||
public/upload
|
public/upload
|
||||||
app/routes/routes.go
|
app/routes/routes.go
|
||||||
app/tmp/main.go
|
app/tmp/main.go
|
||||||
|
|||||||
+1
-3
@@ -1,5 +1,5 @@
|
|||||||
language: go
|
language: go
|
||||||
go: 1.4
|
go: 1.7
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- mongodb # 2.4.12
|
- mongodb # 2.4.12
|
||||||
@@ -18,8 +18,6 @@ script:
|
|||||||
- mongo --version
|
- mongo --version
|
||||||
- mongorestore -h localhost -d leanote --directoryperdb ./mongodb_backup/leanote_install_data/
|
- mongorestore -h localhost -d leanote --directoryperdb ./mongodb_backup/leanote_install_data/
|
||||||
|
|
||||||
- go test github.com/leanote/leanote/app/tests
|
|
||||||
|
|
||||||
# gen tmp/main.go, routes/routes.go
|
# gen tmp/main.go, routes/routes.go
|
||||||
- go run app/cmd/main.go
|
- go run app/cmd/main.go
|
||||||
# build
|
# build
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ gulp.task('concatDepJs', function() {
|
|||||||
'js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js',
|
'js/jQuery-slimScroll-1.3.0/jquery.slimscroll-min.js',
|
||||||
'js/contextmenu/jquery.contextmenu-min.js',
|
'js/contextmenu/jquery.contextmenu-min.js',
|
||||||
'js/bootstrap-min.js',
|
'js/bootstrap-min.js',
|
||||||
'js/object_id-min.js',
|
'js/object_id.js',
|
||||||
];
|
];
|
||||||
|
|
||||||
for(var i in jss) {
|
for(var i in jss) {
|
||||||
@@ -340,7 +340,7 @@ gulp.task('tinymce', function() {
|
|||||||
|
|
||||||
var cp = require('child_process');
|
var cp = require('child_process');
|
||||||
|
|
||||||
var bundleCmd = 'grunt bundle --themes leanote --plugins autolink,link,leaui_image,lists,hr,paste,searchreplace,leanote_nav,leanote_code,tabfocus,table,directionality,textcolor';
|
var bundleCmd = 'grunt bundle --themes leanote --plugins autolink,link,leaui_image,leaui_mindmap,lists,hr,paste,searchreplace,leanote_nav,leanote_code,tabfocus,table,directionality,textcolor';
|
||||||
// build
|
// build
|
||||||
cp.exec('grunt minify', {cwd: tinymceBase}, function(err, stdout, stderr) {
|
cp.exec('grunt minify', {cwd: tinymceBase}, function(err, stdout, stderr) {
|
||||||
console.log('stdout: ' + stdout);
|
console.log('stdout: ' + stdout);
|
||||||
|
|||||||
@@ -184,6 +184,6 @@ Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善Lea
|
|||||||
## 联系&加入我们
|
## 联系&加入我们
|
||||||
* Email: leanote@leanote.com
|
* Email: leanote@leanote.com
|
||||||
* [Leanote 社区](http://bbs.leanote.com)
|
* [Leanote 社区](http://bbs.leanote.com)
|
||||||
* QQ群: 326073529, 256076853, 158716820
|
* [QQ群](http://leanote.leanote.com/post/Leanote-groups)
|
||||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
# Leanote
|
|
||||||
|
|
||||||
[](https://gitter.im/leanote/leanote?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
|
||||||
[](https://travis-ci.org/leanote/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)
|
|
||||||
|
|
||||||
## 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 相关文档
|
|
||||||
* [leanote二进制版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [leanote开发版详细安装教程](https://github.com/leanote/leanote/wiki/leanote%E5%BC%80%E5%8F%91%E7%89%88%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B)
|
|
||||||
* [Leanote source leanote源码导读](https://github.com/leanote/leanote/wiki/Leanote-source-leanote源码导读)
|
|
||||||
* [leanote blog theme api(中文版)](https://github.com/leanote/leanote/wiki/leanote-blog-theme-api)
|
|
||||||
* [How to develop leanote 如何开发leanote](https://github.com/leanote/leanote/wiki/How-to-develop-leanote-如何开发leanote)
|
|
||||||
|
|
||||||
更多文档请查看 [wiki](https://github.com/leanote/leanote/wiki).
|
|
||||||
|
|
||||||
## 6. 贡献者
|
|
||||||
多谢 [贡献者](https://github.com/leanote/leanote/graphs/contributors) 的贡献, leanote因有你们而更完美!
|
|
||||||
|
|
||||||
## 7. 加入我们
|
|
||||||
|
|
||||||
欢迎提交[pull requests](https://github.com/leanote/leanote/pulls) 到leanote.
|
|
||||||
|
|
||||||
有任何问题或建议, 欢迎提交[issue](https://github.com/leanote/leanote/issues).
|
|
||||||
|
|
||||||
Leanote还有很多问题, 如果你喜欢它, 欢迎加入我们一起完善leanote.
|
|
||||||
|
|
||||||
## 8. 捐赠
|
|
||||||
支持我们, [捐赠Leanote](http://leanote.org/#donate). 感谢[捐赠者](http://leanote.leanote.com/post/leanote-donation-list), 谢谢你们的鼓励, Leanote会一直坚持!
|
|
||||||
|
|
||||||
## 9. 其它相关项目
|
|
||||||
* [Leanote Desktop App](https://github.com/leanote/desktop-app), [下载地址](http://app.leanote.com)
|
|
||||||
* [Leanote IOS](https://github.com/leanote/leanote-ios), [从App Store下载](https://itunes.apple.com/zn/app/leanote/id1022302858?mt=8)
|
|
||||||
* [Leanote Android](https://github.com/Dminter/leanote-android-client), 开发阶段
|
|
||||||
|
|
||||||
欢迎加入我们!
|
|
||||||
|
|
||||||
## 联系&加入我们
|
|
||||||
* Email: leanote@leanote.com
|
|
||||||
* [leanote 社区](http://bbs.leanote.com)
|
|
||||||
* QQ群: 158716820, 256076853
|
|
||||||
* [Leanote Google Group](https://groups.google.com/forum/#!forum/leanote)
|
|
||||||
|
|
||||||
----------------------------------------------------------------
|
|
||||||
[English](README.md)
|
|
||||||
@@ -23,11 +23,11 @@ func (c Album) Index() revel.Result {
|
|||||||
// all albums by userId
|
// all albums by userId
|
||||||
func (c Album) GetAlbums() revel.Result {
|
func (c Album) GetAlbums() revel.Result {
|
||||||
re := albumService.GetAlbums(c.GetUserId())
|
re := albumService.GetAlbums(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
func (c Album) DeleteAlbum(albumId string) revel.Result {
|
||||||
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
re, msg := albumService.DeleteAlbum(c.GetUserId(), albumId)
|
||||||
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
return c.RenderJSON(info.Re{Ok: re, Msg: msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
// add album
|
// add album
|
||||||
@@ -40,13 +40,13 @@ func (c Album) AddAlbum(name string) revel.Result {
|
|||||||
re := albumService.AddAlbum(album)
|
re := albumService.AddAlbum(album)
|
||||||
|
|
||||||
if re {
|
if re {
|
||||||
return c.RenderJson(album)
|
return c.RenderJSON(album)
|
||||||
} else {
|
} else {
|
||||||
return c.RenderJson(false)
|
return c.RenderJSON(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update alnum name
|
// update alnum name
|
||||||
func (c Album) UpdateAlbum(albumId, name string) revel.Result {
|
func (c Album) UpdateAlbum(albumId, name string) revel.Result {
|
||||||
return c.RenderJson(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
|
return c.RenderJSON(albumService.UpdateAlbum(albumId, c.GetUserId(), name))
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ type Attach struct {
|
|||||||
// 上传附件
|
// 上传附件
|
||||||
func (c Attach) UploadAttach(noteId string) revel.Result {
|
func (c Attach) UploadAttach(noteId string) revel.Result {
|
||||||
re := c.uploadAttach(noteId)
|
re := c.uploadAttach(noteId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||||
var fileId = ""
|
var fileId = ""
|
||||||
@@ -118,7 +118,7 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
|||||||
func (c Attach) DeleteAttach(attachId string) revel.Result {
|
func (c Attach) DeleteAttach(attachId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
|
re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all attachs by noteId
|
// get all attachs by noteId
|
||||||
@@ -126,7 +126,7 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.List = attachService.ListAttachs(noteId, c.GetUserId())
|
re.List = attachService.ListAttachs(noteId, c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载附件
|
// 下载附件
|
||||||
|
|||||||
@@ -17,29 +17,29 @@ type Auth struct {
|
|||||||
//--------
|
//--------
|
||||||
// 登录
|
// 登录
|
||||||
func (c Auth) Login(email, from string) revel.Result {
|
func (c Auth) Login(email, from string) revel.Result {
|
||||||
c.RenderArgs["title"] = c.Message("login")
|
c.ViewArgs["title"] = c.Message("login")
|
||||||
c.RenderArgs["subTitle"] = c.Message("login")
|
c.ViewArgs["subTitle"] = c.Message("login")
|
||||||
c.RenderArgs["email"] = email
|
c.ViewArgs["email"] = email
|
||||||
c.RenderArgs["from"] = from
|
c.ViewArgs["from"] = from
|
||||||
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
c.ViewArgs["openRegister"] = configService.IsOpenRegister()
|
||||||
|
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.ID()
|
||||||
if sessionService.LoginTimesIsOver(sessionId) {
|
if sessionService.LoginTimesIsOver(sessionId) {
|
||||||
c.RenderArgs["needCaptcha"] = true
|
c.ViewArgs["needCaptcha"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
if c.Has("demo") {
|
if c.Has("demo") {
|
||||||
c.RenderArgs["demo"] = true
|
c.ViewArgs["demo"] = true
|
||||||
c.RenderArgs["email"] = "demo@leanote.com"
|
c.ViewArgs["email"] = "demo@leanote.com"
|
||||||
}
|
}
|
||||||
return c.RenderTemplate("home/login.html")
|
return c.RenderTemplate("home/login.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为了demo和register
|
// 为了demo和register
|
||||||
func (c Auth) doLogin(email, pwd string) revel.Result {
|
func (c Auth) doLogin(email, pwd string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.ID()
|
||||||
var msg = ""
|
var msg = ""
|
||||||
|
|
||||||
userInfo, err := authService.Login(email, pwd)
|
userInfo, err := authService.Login(email, pwd)
|
||||||
@@ -49,13 +49,13 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
|
|||||||
} else {
|
} else {
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
sessionService.ClearLoginTimes(sessionId)
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
return c.RenderJson(info.Re{Ok: true})
|
return c.RenderJSON(info.Re{Ok: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
|
return c.RenderJSON(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
|
||||||
}
|
}
|
||||||
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.ID()
|
||||||
var msg = ""
|
var msg = ""
|
||||||
|
|
||||||
// > 5次需要验证码, 直到登录成功
|
// > 5次需要验证码, 直到登录成功
|
||||||
@@ -70,16 +70,16 @@ func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
|
|||||||
} else {
|
} else {
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
sessionService.ClearLoginTimes(sessionId)
|
sessionService.ClearLoginTimes(sessionId)
|
||||||
return c.RenderJson(info.Re{Ok: true})
|
return c.RenderJSON(info.Re{Ok: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
|
return c.RenderJSON(info.Re{Ok: false, Item: sessionService.LoginTimesIsOver(sessionId), Msg: c.Message(msg)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注销
|
// 注销
|
||||||
func (c Auth) Logout() revel.Result {
|
func (c Auth) Logout() revel.Result {
|
||||||
sessionId := c.Session.Id()
|
sessionId := c.Session.ID()
|
||||||
sessionService.Clear(sessionId)
|
sessionService.Clear(sessionId)
|
||||||
c.ClearSession()
|
c.ClearSession()
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
@@ -92,7 +92,7 @@ func (c Auth) Demo() revel.Result {
|
|||||||
|
|
||||||
userInfo, err := authService.Login(email, pwd)
|
userInfo, err := authService.Login(email, pwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
return c.RenderJSON(info.Re{Ok: false})
|
||||||
} else {
|
} else {
|
||||||
c.SetSession(userInfo)
|
c.SetSession(userInfo)
|
||||||
return c.Redirect("/note")
|
return c.Redirect("/note")
|
||||||
@@ -107,11 +107,11 @@ func (c Auth) Register(from, iu string) revel.Result {
|
|||||||
return c.Redirect("/index")
|
return c.Redirect("/index")
|
||||||
}
|
}
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["from"] = from
|
c.ViewArgs["from"] = from
|
||||||
c.RenderArgs["iu"] = iu
|
c.ViewArgs["iu"] = iu
|
||||||
|
|
||||||
c.RenderArgs["title"] = c.Message("register")
|
c.ViewArgs["title"] = c.Message("register")
|
||||||
c.RenderArgs["subTitle"] = c.Message("register")
|
c.ViewArgs["subTitle"] = c.Message("register")
|
||||||
return c.RenderTemplate("home/register.html")
|
return c.RenderTemplate("home/register.html")
|
||||||
}
|
}
|
||||||
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
||||||
@@ -145,22 +145,22 @@ func (c Auth) DoRegister(email, pwd, iu string) revel.Result {
|
|||||||
// 找回密码
|
// 找回密码
|
||||||
func (c Auth) FindPassword() revel.Result {
|
func (c Auth) FindPassword() revel.Result {
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("findPassword")
|
c.ViewArgs["title"] = c.Message("findPassword")
|
||||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
c.ViewArgs["subTitle"] = c.Message("findPassword")
|
||||||
return c.RenderTemplate("home/find_password.html")
|
return c.RenderTemplate("home/find_password.html")
|
||||||
}
|
}
|
||||||
func (c Auth) DoFindPassword(email string) revel.Result {
|
func (c Auth) DoFindPassword(email string) revel.Result {
|
||||||
pwdService.FindPwd(email)
|
pwdService.FindPwd(email)
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击链接后, 先验证之
|
// 点击链接后, 先验证之
|
||||||
func (c Auth) FindPassword2(token string) revel.Result {
|
func (c Auth) FindPassword2(token string) revel.Result {
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("findPassword")
|
c.ViewArgs["title"] = c.Message("findPassword")
|
||||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
c.ViewArgs["subTitle"] = c.Message("findPassword")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return c.RenderTemplate("find_password2_timeout.html")
|
return c.RenderTemplate("find_password2_timeout.html")
|
||||||
}
|
}
|
||||||
@@ -168,10 +168,10 @@ func (c Auth) FindPassword2(token string) revel.Result {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return c.RenderTemplate("home/find_password2_timeout.html")
|
return c.RenderTemplate("home/find_password2_timeout.html")
|
||||||
}
|
}
|
||||||
c.RenderArgs["findPwd"] = findPwd
|
c.ViewArgs["findPwd"] = findPwd
|
||||||
|
|
||||||
c.RenderArgs["title"] = c.Message("updatePassword")
|
c.ViewArgs["title"] = c.Message("updatePassword")
|
||||||
c.RenderArgs["subTitle"] = c.Message("updatePassword")
|
c.ViewArgs["subTitle"] = c.Message("updatePassword")
|
||||||
|
|
||||||
return c.RenderTemplate("home/find_password2.html")
|
return c.RenderTemplate("home/find_password2.html")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ func (c BaseController) GetTotalPage(page, count int) int {
|
|||||||
|
|
||||||
//-------------
|
//-------------
|
||||||
func (c BaseController) E404() revel.Result {
|
func (c BaseController) E404() revel.Result {
|
||||||
c.RenderArgs["title"] = "404"
|
c.ViewArgs["title"] = "404"
|
||||||
return c.NotFound("", nil)
|
return c.NotFound("", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,12 +199,12 @@ func (c BaseController) SetLocale() string {
|
|||||||
if !i18n.HasLang(locale) {
|
if !i18n.HasLang(locale) {
|
||||||
lang = i18n.GetDefaultLang()
|
lang = i18n.GetDefaultLang()
|
||||||
}
|
}
|
||||||
c.RenderArgs["locale"] = lang
|
c.ViewArgs["locale"] = lang
|
||||||
c.RenderArgs["siteUrl"] = configService.GetSiteUrl()
|
c.ViewArgs["siteUrl"] = configService.GetSiteUrl()
|
||||||
|
|
||||||
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
c.ViewArgs["blogUrl"] = configService.GetBlogUrl()
|
||||||
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
c.ViewArgs["leaUrl"] = configService.GetLeaUrl()
|
||||||
c.RenderArgs["noteUrl"] = configService.GetNoteUrl()
|
c.ViewArgs["noteUrl"] = configService.GetNoteUrl()
|
||||||
|
|
||||||
return lang
|
return lang
|
||||||
}
|
}
|
||||||
@@ -212,9 +212,9 @@ func (c BaseController) SetLocale() string {
|
|||||||
// 设置userInfo
|
// 设置userInfo
|
||||||
func (c BaseController) SetUserInfo() info.User {
|
func (c BaseController) SetUserInfo() info.User {
|
||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
if userInfo.Username == configService.GetAdminUsername() {
|
if userInfo.Username == configService.GetAdminUsername() {
|
||||||
c.RenderArgs["isAdmin"] = true
|
c.ViewArgs["isAdmin"] = true
|
||||||
}
|
}
|
||||||
return userInfo
|
return userInfo
|
||||||
}
|
}
|
||||||
@@ -230,11 +230,11 @@ func (c BaseController) RenderTemplateStr(templatePath string) string {
|
|||||||
|
|
||||||
tpl := &revel.RenderTemplateResult{
|
tpl := &revel.RenderTemplateResult{
|
||||||
Template: template,
|
Template: template,
|
||||||
RenderArgs: c.RenderArgs, // 把args给它
|
ViewArgs: c.ViewArgs, // 把args给它
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
tpl.Template.Render(&buffer, c.RenderArgs)
|
tpl.Template.Render(&buffer, c.ViewArgs)
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,5 +263,5 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
|
|||||||
if strings.HasPrefix(re.Msg, "???") {
|
if strings.HasPrefix(re.Msg, "???") {
|
||||||
re.Msg = oldMsg
|
re.Msg = oldMsg
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,8 @@ $.bootstrapJsUrl
|
|||||||
|
|
||||||
func (c Blog) render(templateName string, themePath string) revel.Result {
|
func (c Blog) render(templateName string, themePath string) revel.Result {
|
||||||
isPreview := false
|
isPreview := false
|
||||||
if c.RenderArgs["isPreview"] != nil {
|
if c.ViewArgs["isPreview"] != nil {
|
||||||
themePath2 := c.RenderArgs["themePath"]
|
themePath2 := c.ViewArgs["themePath"]
|
||||||
if themePath2 == nil {
|
if themePath2 == nil {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
@@ -59,9 +59,9 @@ func (c Blog) render(templateName string, themePath string) revel.Result {
|
|||||||
c.setPreviewUrl()
|
c.setPreviewUrl()
|
||||||
|
|
||||||
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
|
// 因为common的themeInfo是从UserBlog.ThemeId来取的, 所以这里要fugai下
|
||||||
c.RenderArgs["themeInfo"] = c.RenderArgs["themeInfoPreview"]
|
c.ViewArgs["themeInfo"] = c.ViewArgs["themeInfoPreview"]
|
||||||
}
|
}
|
||||||
return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
|
return blog.RenderTemplate(templateName, c.ViewArgs, revel.BasePath+"/"+themePath, isPreview)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 404
|
// 404
|
||||||
@@ -125,19 +125,19 @@ func (c Blog) setPreviewUrl() {
|
|||||||
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
|
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
|
||||||
tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
|
tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
|
||||||
|
|
||||||
c.RenderArgs["indexUrl"] = indexUrl
|
c.ViewArgs["indexUrl"] = indexUrl
|
||||||
c.RenderArgs["cateUrl"] = cateUrl
|
c.ViewArgs["cateUrl"] = cateUrl
|
||||||
c.RenderArgs["postUrl"] = postUrl
|
c.ViewArgs["postUrl"] = postUrl
|
||||||
c.RenderArgs["searchUrl"] = searchUrl
|
c.ViewArgs["searchUrl"] = searchUrl
|
||||||
c.RenderArgs["singleUrl"] = singleUrl // 单页
|
c.ViewArgs["singleUrl"] = singleUrl // 单页
|
||||||
c.RenderArgs["archiveUrl"] = archiveUrl
|
c.ViewArgs["archiveUrl"] = archiveUrl
|
||||||
c.RenderArgs["archivesUrl"] = archiveUrl // 别名
|
c.ViewArgs["archivesUrl"] = archiveUrl // 别名
|
||||||
c.RenderArgs["tagsUrl"] = tagsUrl
|
c.ViewArgs["tagsUrl"] = tagsUrl
|
||||||
c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail
|
c.ViewArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail
|
||||||
c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"]
|
c.ViewArgs["tagUrl"] = c.ViewArgs["tagPostsUrl"]
|
||||||
|
|
||||||
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
|
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
|
||||||
c.RenderArgs["themeBaseUrl"] = "/" + theme.Path
|
c.ViewArgs["themeBaseUrl"] = "/" + theme.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
// 各种地址设置
|
// 各种地址设置
|
||||||
@@ -152,36 +152,36 @@ func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
|
|||||||
// 分类
|
// 分类
|
||||||
// 搜索
|
// 搜索
|
||||||
// 查看
|
// 查看
|
||||||
c.RenderArgs["siteUrl"] = siteUrl
|
c.ViewArgs["siteUrl"] = siteUrl
|
||||||
c.RenderArgs["indexUrl"] = blogUrls.IndexUrl
|
c.ViewArgs["indexUrl"] = blogUrls.IndexUrl
|
||||||
c.RenderArgs["cateUrl"] = blogUrls.CateUrl
|
c.ViewArgs["cateUrl"] = blogUrls.CateUrl
|
||||||
c.RenderArgs["postUrl"] = blogUrls.PostUrl
|
c.ViewArgs["postUrl"] = blogUrls.PostUrl
|
||||||
c.RenderArgs["searchUrl"] = blogUrls.SearchUrl
|
c.ViewArgs["searchUrl"] = blogUrls.SearchUrl
|
||||||
c.RenderArgs["singleUrl"] = blogUrls.SingleUrl // 单页
|
c.ViewArgs["singleUrl"] = blogUrls.SingleUrl // 单页
|
||||||
c.RenderArgs["archiveUrl"] = blogUrls.ArchiveUrl
|
c.ViewArgs["archiveUrl"] = blogUrls.ArchiveUrl
|
||||||
c.RenderArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名
|
c.ViewArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名
|
||||||
c.RenderArgs["tagsUrl"] = blogUrls.TagsUrl
|
c.ViewArgs["tagsUrl"] = blogUrls.TagsUrl
|
||||||
c.RenderArgs["tagPostsUrl"] = blogUrls.TagPostsUrl
|
c.ViewArgs["tagPostsUrl"] = blogUrls.TagPostsUrl
|
||||||
c.RenderArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名
|
c.ViewArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名
|
||||||
|
|
||||||
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
|
// themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
|
||||||
c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
|
c.ViewArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
|
||||||
|
|
||||||
// 其它static js
|
// 其它static js
|
||||||
c.RenderArgs["jQueryUrl"] = "/js/jquery-1.9.0.min.js"
|
c.ViewArgs["jQueryUrl"] = "/js/jquery-1.9.0.min.js"
|
||||||
|
|
||||||
c.RenderArgs["prettifyJsUrl"] = "/js/google-code-prettify/prettify.js"
|
c.ViewArgs["prettifyJsUrl"] = "/js/google-code-prettify/prettify.js"
|
||||||
c.RenderArgs["prettifyCssUrl"] = "/js/google-code-prettify/prettify.css"
|
c.ViewArgs["prettifyCssUrl"] = "/js/google-code-prettify/prettify.css"
|
||||||
|
|
||||||
c.RenderArgs["blogCommonJsUrl"] = "/public/blog/js/common.js"
|
c.ViewArgs["blogCommonJsUrl"] = "/public/blog/js/common.js"
|
||||||
|
|
||||||
c.RenderArgs["shareCommentCssUrl"] = "/public/blog/css/share_comment.css"
|
c.ViewArgs["shareCommentCssUrl"] = "/public/blog/css/share_comment.css"
|
||||||
c.RenderArgs["shareCommentJsUrl"] = "/public/blog/js/share_comment.js"
|
c.ViewArgs["shareCommentJsUrl"] = "/public/blog/js/share_comment.js"
|
||||||
|
|
||||||
c.RenderArgs["fontAwesomeUrl"] = "/css/font-awesome-4.2.0/css/font-awesome.css"
|
c.ViewArgs["fontAwesomeUrl"] = "/css/font-awesome-4.2.0/css/font-awesome.css"
|
||||||
|
|
||||||
c.RenderArgs["bootstrapCssUrl"] = "/css/bootstrap.css"
|
c.ViewArgs["bootstrapCssUrl"] = "/css/bootstrap.css"
|
||||||
c.RenderArgs["bootstrapJsUrl"] = "/js/bootstrap-min.js"
|
c.ViewArgs["bootstrapJsUrl"] = "/js/bootstrap-min.js"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 笔记本分类
|
// 笔记本分类
|
||||||
@@ -265,8 +265,8 @@ func (c Blog) getCates(userBlog info.UserBlog) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["cates"] = cates
|
c.ViewArgs["cates"] = cates
|
||||||
c.RenderArgs["catesTree"] = catesTree
|
c.ViewArgs["catesTree"] = catesTree
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单页
|
// 单页
|
||||||
@@ -281,7 +281,7 @@ func (c Blog) getSingles(userId string) {
|
|||||||
singles2[i] = map[string]string{"title": page["Title"], "singleId": page["SingleId"]}
|
singles2[i] = map[string]string{"title": page["Title"], "singleId": page["SingleId"]}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
c.RenderArgs["singles"] = singles
|
c.ViewArgs["singles"] = singles
|
||||||
}
|
}
|
||||||
|
|
||||||
// $.blog = {userId, title, subTitle, desc, openComment, }
|
// $.blog = {userId, title, subTitle, desc, openComment, }
|
||||||
@@ -300,11 +300,11 @@ func (c Blog) setBlog(userBlog info.UserBlog, userInfo info.User) {
|
|||||||
"SubDomain": userBlog.SubDomain,
|
"SubDomain": userBlog.SubDomain,
|
||||||
"Domain": userBlog.Domain,
|
"Domain": userBlog.Domain,
|
||||||
}
|
}
|
||||||
c.RenderArgs["blogInfo"] = blogInfo
|
c.ViewArgs["blogInfo"] = blogInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Blog) setPaging(pageInfo info.Page) {
|
func (c Blog) setPaging(pageInfo info.Page) {
|
||||||
c.RenderArgs["paging"] = pageInfo
|
c.ViewArgs["paging"] = pageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 公共
|
// 公共
|
||||||
@@ -315,13 +315,13 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
|
|||||||
return false, userBlog
|
return false, userBlog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// c.RenderArgs["userInfo"] = userInfo
|
// c.ViewArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
// 最新笔记
|
// 最新笔记
|
||||||
_, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc)
|
_, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc)
|
||||||
c.RenderArgs["recentPosts"] = blogService.FixBlogs(recentBlogs)
|
c.ViewArgs["recentPosts"] = blogService.FixBlogs(recentBlogs)
|
||||||
c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"]
|
c.ViewArgs["latestPosts"] = c.ViewArgs["recentPosts"]
|
||||||
c.RenderArgs["tags"] = blogService.GetBlogTags(userId)
|
c.ViewArgs["tags"] = blogService.GetBlogTags(userId)
|
||||||
|
|
||||||
// 语言, url地址
|
// 语言, url地址
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
@@ -331,7 +331,7 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
|
|||||||
userBlog = blogService.GetUserBlog(userId)
|
userBlog = blogService.GetUserBlog(userId)
|
||||||
}
|
}
|
||||||
c.setBlog(userBlog, userInfo)
|
c.setBlog(userBlog, userInfo)
|
||||||
// c.RenderArgs["userBlog"] = userBlog
|
// c.ViewArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
// 分类导航
|
// 分类导航
|
||||||
c.getCates(userBlog)
|
c.getCates(userBlog)
|
||||||
@@ -342,12 +342,12 @@ func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.Us
|
|||||||
c.setUrl(userBlog, userInfo)
|
c.setUrl(userBlog, userInfo)
|
||||||
|
|
||||||
// 当前分类Id, 全设为""
|
// 当前分类Id, 全设为""
|
||||||
c.RenderArgs["curCateId"] = ""
|
c.ViewArgs["curCateId"] = ""
|
||||||
c.RenderArgs["curSingleId"] = ""
|
c.ViewArgs["curSingleId"] = ""
|
||||||
|
|
||||||
// 得到主题信息
|
// 得到主题信息
|
||||||
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
|
themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
|
||||||
c.RenderArgs["themeInfo"] = themeInfo
|
c.ViewArgs["themeInfo"] = themeInfo
|
||||||
|
|
||||||
// Log(">>")
|
// Log(">>")
|
||||||
// Log(userBlog.Style)
|
// Log(userBlog.Style)
|
||||||
@@ -404,9 +404,9 @@ func (c Blog) Tags(userIdOrEmail string) (re revel.Result) {
|
|||||||
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["curIsTags"] = true
|
c.ViewArgs["curIsTags"] = true
|
||||||
tags := blogService.GetBlogTags(userId)
|
tags := blogService.GetBlogTags(userId)
|
||||||
c.RenderArgs["tags"] = tags
|
c.ViewArgs["tags"] = tags
|
||||||
return c.render("tags.html", userBlog.ThemePath)
|
return c.render("tags.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,15 +443,15 @@ func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) {
|
|||||||
tag = userIdOrEmail
|
tag = userIdOrEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["curIsTagPosts"] = true
|
c.ViewArgs["curIsTagPosts"] = true
|
||||||
c.RenderArgs["curTag"] = tag
|
c.ViewArgs["curTag"] = tag
|
||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
|
|
||||||
c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
|
c.ViewArgs["posts"] = blogService.FixBlogs(blogs)
|
||||||
tagPostsUrl := c.RenderArgs["tagPostsUrl"].(string)
|
tagPostsUrl := c.ViewArgs["tagPostsUrl"].(string)
|
||||||
c.RenderArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag
|
c.ViewArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag
|
||||||
|
|
||||||
return c.render("tag_posts.html", userBlog.ThemePath)
|
return c.render("tag_posts.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -490,16 +490,16 @@ func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re
|
|||||||
}
|
}
|
||||||
|
|
||||||
arcs := blogService.ListBlogsArchive(userId, notebookId, year, month, "PublicTime", false)
|
arcs := blogService.ListBlogsArchive(userId, notebookId, year, month, "PublicTime", false)
|
||||||
c.RenderArgs["archives"] = arcs
|
c.ViewArgs["archives"] = arcs
|
||||||
|
|
||||||
c.RenderArgs["curIsArchive"] = true
|
c.ViewArgs["curIsArchive"] = true
|
||||||
if notebookId != "" {
|
if notebookId != "" {
|
||||||
notebook := notebookService.GetNotebookById(notebookId)
|
notebook := notebookService.GetNotebookById(notebookId)
|
||||||
c.RenderArgs["curCateTitle"] = notebook.Title
|
c.ViewArgs["curCateTitle"] = notebook.Title
|
||||||
c.RenderArgs["curCateId"] = notebookId
|
c.ViewArgs["curCateId"] = notebookId
|
||||||
}
|
}
|
||||||
c.RenderArgs["curYear"] = year
|
c.ViewArgs["curYear"] = year
|
||||||
c.RenderArgs["curMonth"] = month
|
c.ViewArgs["curMonth"] = month
|
||||||
|
|
||||||
return c.render("archive.html", userBlog.ThemePath)
|
return c.render("archive.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -541,15 +541,15 @@ func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
|
|||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
pageInfo, blogs := blogService.ListBlogs(userId, notebookId2, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.ListBlogs(userId, notebookId2, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
blogs2 := blogService.FixBlogs(blogs)
|
blogs2 := blogService.FixBlogs(blogs)
|
||||||
c.RenderArgs["posts"] = blogs2
|
c.ViewArgs["posts"] = blogs2
|
||||||
|
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
|
|
||||||
c.RenderArgs["curCateTitle"] = notebook.Title
|
c.ViewArgs["curCateTitle"] = notebook.Title
|
||||||
c.RenderArgs["curCateId"] = notebookId2
|
c.ViewArgs["curCateId"] = notebookId2
|
||||||
cateUrl := c.RenderArgs["cateUrl"].(string)
|
cateUrl := c.ViewArgs["cateUrl"].(string)
|
||||||
c.RenderArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId
|
c.ViewArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId
|
||||||
c.RenderArgs["curIsCate"] = true
|
c.ViewArgs["curIsCate"] = true
|
||||||
|
|
||||||
return c.render("cate.html", userBlog.ThemePath)
|
return c.render("cate.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -594,12 +594,12 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
|
|||||||
page := c.GetPage()
|
page := c.GetPage()
|
||||||
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
blogs2 := blogService.FixBlogs(blogs)
|
blogs2 := blogService.FixBlogs(blogs)
|
||||||
c.RenderArgs["posts"] = blogs2
|
c.ViewArgs["posts"] = blogs2
|
||||||
|
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"]
|
c.ViewArgs["pagingBaseUrl"] = c.ViewArgs["indexUrl"]
|
||||||
|
|
||||||
c.RenderArgs["curIsIndex"] = true
|
c.ViewArgs["curIsIndex"] = true
|
||||||
|
|
||||||
return c.render("index.html", userBlog.ThemePath)
|
return c.render("index.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -631,9 +631,9 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post := blogService.FixBlog(blogInfo)
|
post := blogService.FixBlog(blogInfo)
|
||||||
c.RenderArgs["post"] = post
|
c.ViewArgs["post"] = post
|
||||||
// c.RenderArgs["userInfo"] = userInfo
|
// c.ViewArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["curIsPost"] = true
|
c.ViewArgs["curIsPost"] = true
|
||||||
|
|
||||||
// 上一篇, 下一篇
|
// 上一篇, 下一篇
|
||||||
var baseTime interface{}
|
var baseTime interface{}
|
||||||
@@ -649,10 +649,10 @@ func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
|
|||||||
|
|
||||||
prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, post.NoteId, baseTime)
|
prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, post.NoteId, baseTime)
|
||||||
if prePost.NoteId != "" {
|
if prePost.NoteId != "" {
|
||||||
c.RenderArgs["prePost"] = prePost
|
c.ViewArgs["prePost"] = prePost
|
||||||
}
|
}
|
||||||
if nextPost.NoteId != "" {
|
if nextPost.NoteId != "" {
|
||||||
c.RenderArgs["nextPost"] = nextPost
|
c.ViewArgs["nextPost"] = nextPost
|
||||||
}
|
}
|
||||||
return c.render("post.html", userBlog.ThemePath)
|
return c.render("post.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -682,7 +682,7 @@ func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) {
|
|||||||
panic("")
|
panic("")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["single"] = map[string]interface{}{
|
c.ViewArgs["single"] = map[string]interface{}{
|
||||||
"SingleId": single.SingleId.Hex(),
|
"SingleId": single.SingleId.Hex(),
|
||||||
"Title": single.Title,
|
"Title": single.Title,
|
||||||
"UrlTitle": single.UrlTitle,
|
"UrlTitle": single.UrlTitle,
|
||||||
@@ -690,8 +690,8 @@ func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) {
|
|||||||
"CreatedTime": single.CreatedTime,
|
"CreatedTime": single.CreatedTime,
|
||||||
"UpdatedTime": single.UpdatedTime,
|
"UpdatedTime": single.UpdatedTime,
|
||||||
}
|
}
|
||||||
c.RenderArgs["curSingleId"] = single.SingleId.Hex()
|
c.ViewArgs["curSingleId"] = single.SingleId.Hex()
|
||||||
c.RenderArgs["curIsSingle"] = true
|
c.ViewArgs["curIsSingle"] = true
|
||||||
|
|
||||||
return c.render("single.html", userBlog.ThemePath)
|
return c.render("single.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -716,7 +716,7 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) {
|
|||||||
} else {
|
} else {
|
||||||
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
|
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
|
||||||
}
|
}
|
||||||
// c.RenderArgs["userInfo"] = userInfo
|
// c.ViewArgs["userInfo"] = userInfo
|
||||||
userId = userInfo.UserId.Hex()
|
userId = userInfo.UserId.Hex()
|
||||||
var ok = false
|
var ok = false
|
||||||
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
|
||||||
@@ -727,11 +727,11 @@ func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) {
|
|||||||
pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
|
||||||
c.setPaging(pageInfo)
|
c.setPaging(pageInfo)
|
||||||
|
|
||||||
c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
|
c.ViewArgs["posts"] = blogService.FixBlogs(blogs)
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.ViewArgs["keywords"] = keywords
|
||||||
searchUrl, _ := c.RenderArgs["searchUrl"].(string)
|
searchUrl, _ := c.ViewArgs["searchUrl"].(string)
|
||||||
c.RenderArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords
|
c.ViewArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords
|
||||||
c.RenderArgs["curIsSearch"] = true
|
c.ViewArgs["curIsSearch"] = true
|
||||||
|
|
||||||
return c.render("search.html", userBlog.ThemePath)
|
return c.render("search.html", userBlog.ThemePath)
|
||||||
}
|
}
|
||||||
@@ -741,7 +741,7 @@ func (c Blog) setRenderUserInfo(userInfo info.User) {
|
|||||||
if userInfo.Username == "" {
|
if userInfo.Username == "" {
|
||||||
userInfo.Username = userInfo.Email
|
userInfo.Username = userInfo.Email
|
||||||
}
|
}
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
@@ -753,7 +753,7 @@ func (c Blog) GetPostStat(noteId string) revel.Result {
|
|||||||
re.Ok = true
|
re.Ok = true
|
||||||
statInfo := blogService.GetBlogStat(noteId)
|
statInfo := blogService.GetBlogStat(noteId)
|
||||||
re.Item = statInfo
|
re.Item = statInfo
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// jsonP
|
// jsonP
|
||||||
@@ -778,7 +778,7 @@ func (c Blog) GetLikes(noteId string, callback string) revel.Result {
|
|||||||
result["hasMoreLikedUser"] = hasMoreLikedUser
|
result["hasMoreLikedUser"] = hasMoreLikedUser
|
||||||
|
|
||||||
re.Item = result
|
re.Item = result
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
|
func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
@@ -806,13 +806,13 @@ func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
|
|||||||
result["comments"] = comments
|
result["comments"] = comments
|
||||||
result["commentUserInfo"] = commentUserInfo
|
result["commentUserInfo"] = commentUserInfo
|
||||||
re.Item = result
|
re.Item = result
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Blog) IncReadNum(noteId string) revel.Result {
|
func (c Blog) IncReadNum(noteId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.IncReadNum(noteId)
|
re.Ok = blogService.IncReadNum(noteId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点赞, 要用jsonp
|
// 点赞, 要用jsonp
|
||||||
@@ -820,7 +820,7 @@ func (c Blog) LikePost(noteId string, callback string) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
||||||
// 评论
|
// 评论
|
||||||
@@ -836,24 +836,24 @@ func (c Blog) GetComments(noteId string, callback string) revel.Result {
|
|||||||
re.Item = result
|
re.Item = result
|
||||||
|
|
||||||
if callback != "" {
|
if callback != "" {
|
||||||
return c.RenderJsonP(callback, result)
|
return c.RenderJSONP(callback, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// jsonp
|
// jsonp
|
||||||
func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result {
|
func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId())
|
re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId())
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// jsonp
|
// jsonp
|
||||||
func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result {
|
func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content)
|
re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content)
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// jsonp
|
// jsonp
|
||||||
@@ -862,7 +862,7 @@ func (c Blog) LikeComment(commentId string, callback string) revel.Result {
|
|||||||
ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId())
|
ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId())
|
||||||
re.Ok = ok
|
re.Ok = ok
|
||||||
re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num}
|
re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num}
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示分类的最近博客, jsonp
|
// 显示分类的最近博客, jsonp
|
||||||
@@ -898,5 +898,5 @@ func (c Blog) ListCateLatest(notebookId, callback string) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.List = blogs
|
re.List = blogs
|
||||||
return c.RenderJsonP(callback, re)
|
return c.RenderJSONP(callback, re)
|
||||||
}
|
}
|
||||||
@@ -24,9 +24,9 @@ type File struct {
|
|||||||
func (c File) UploadBlogLogo() revel.Result {
|
func (c File) UploadBlogLogo() revel.Result {
|
||||||
re := c.uploadImage("blogLogo", "")
|
re := c.uploadImage("blogLogo", "")
|
||||||
|
|
||||||
c.RenderArgs["fileUrlPath"] = re.Id
|
c.ViewArgs["fileUrlPath"] = re.Id
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.ViewArgs["resultCode"] = re.Code
|
||||||
c.RenderArgs["resultMsg"] = re.Msg
|
c.ViewArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
return c.RenderTemplate("file/blog_logo.html")
|
return c.RenderTemplate("file/blog_logo.html")
|
||||||
}
|
}
|
||||||
@@ -54,16 +54,16 @@ func (c File) PasteImage(noteId string) revel.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 头像设置
|
// 头像设置
|
||||||
func (c File) UploadAvatar() revel.Result {
|
func (c File) UploadAvatar() revel.Result {
|
||||||
re := c.uploadImage("logo", "")
|
re := c.uploadImage("logo", "")
|
||||||
|
|
||||||
c.RenderArgs["fileUrlPath"] = re.Id
|
c.ViewArgs["fileUrlPath"] = re.Id
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.ViewArgs["resultCode"] = re.Code
|
||||||
c.RenderArgs["resultMsg"] = re.Msg
|
c.ViewArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
if re.Ok {
|
if re.Ok {
|
||||||
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
|
re.Ok = userService.UpdateAvatar(c.GetUserId(), re.Id)
|
||||||
@@ -72,13 +72,13 @@ func (c File) UploadAvatar() revel.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// leaui image plugin upload image
|
// leaui image plugin upload image
|
||||||
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||||
re := c.uploadImage("", albumId)
|
re := c.uploadImage("", albumId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传图片, 公用方法
|
// 上传图片, 公用方法
|
||||||
@@ -201,19 +201,19 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
// get all images by userId with page
|
// get all images by userId with page
|
||||||
func (c File) GetImages(albumId, key string, page int) revel.Result {
|
func (c File) GetImages(albumId, key string, page int) revel.Result {
|
||||||
re := fileService.ListImagesWithPage(c.GetUserId(), albumId, key, page, 12)
|
re := fileService.ListImagesWithPage(c.GetUserId(), albumId, key, page, 12)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c File) UpdateImageTitle(fileId, title string) revel.Result {
|
func (c File) UpdateImageTitle(fileId, title string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = fileService.UpdateImageTitle(c.GetUserId(), fileId, title)
|
re.Ok = fileService.UpdateImageTitle(c.GetUserId(), fileId, title)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c File) DeleteImage(fileId string) revel.Result {
|
func (c File) DeleteImage(fileId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
re.Ok, re.Msg = fileService.DeleteImage(c.GetUserId(), fileId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
@@ -235,7 +235,7 @@ func (c File) OutputImage(noteId, fileId string) revel.Result {
|
|||||||
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
|
func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制外网的图片
|
// 复制外网的图片
|
||||||
@@ -251,13 +251,13 @@ func (c File) CopyHttpImage(src string) revel.Result {
|
|||||||
dir := revel.BasePath + "/" + fileUrlPath
|
dir := revel.BasePath + "/" + fileUrlPath
|
||||||
err := os.MkdirAll(dir, 0755)
|
err := os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
filesize, filename, _, ok := netutil.WriteUrl(src, dir)
|
filesize, filename, _, ok := netutil.WriteUrl(src, dir)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
re.Msg = "copy error"
|
re.Msg = "copy error"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File
|
// File
|
||||||
@@ -273,5 +273,5 @@ func (c File) CopyHttpImage(src string) revel.Result {
|
|||||||
// re.Item = fileInfo.Path
|
// re.Item = fileInfo.Path
|
||||||
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
re.Ok, re.Msg = fileService.AddImage(fileInfo, "", c.GetUserId(), true)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,8 @@ func (c Index) Default() revel.Result {
|
|||||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||||
func (c Index) Index() revel.Result {
|
func (c Index) Index() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.RenderArgs["title"] = "leanote"
|
c.ViewArgs["title"] = "leanote"
|
||||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
c.ViewArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
return c.RenderTemplate("home/index.html")
|
return c.RenderTemplate("home/index.html")
|
||||||
@@ -40,5 +40,5 @@ func (c Index) Suggestion(addr, suggestion string) revel.Result {
|
|||||||
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: "+c.GetUserId()+" <br /> Suggestions: "+suggestion)
|
emailService.SendEmail("leanote@leanote.com", "建议", "UserId: "+c.GetUserId()+" <br /> Suggestions: "+suggestion)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,5 @@ type NoteContentHistory struct {
|
|||||||
func (c NoteContentHistory) ListHistories(noteId string) revel.Result {
|
func (c NoteContentHistory) ListHistories(noteId string) revel.Result {
|
||||||
histories := noteContentHistoryService.ListHistories(noteId, c.GetUserId())
|
histories := noteContentHistoryService.ListHistories(noteId, c.GetUserId())
|
||||||
|
|
||||||
return c.RenderJson(histories)
|
return c.RenderJSON(histories)
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"runtime"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -36,7 +37,7 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["openRegister"] = configService.IsOpenRegister()
|
c.ViewArgs["openRegister"] = configService.IsOpenRegister()
|
||||||
|
|
||||||
// 已登录了, 那么得到所有信息
|
// 已登录了, 那么得到所有信息
|
||||||
notebooks := notebookService.GetNotebooks(userId)
|
notebooks := notebookService.GetNotebooks(userId)
|
||||||
@@ -58,16 +59,16 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
noteContent = noteService.GetNoteContent(noteId, noteOwner)
|
||||||
|
|
||||||
hasRightNoteId = true
|
hasRightNoteId = true
|
||||||
c.RenderArgs["curNoteId"] = noteId
|
c.ViewArgs["curNoteId"] = noteId
|
||||||
c.RenderArgs["curNotebookId"] = note.NotebookId.Hex()
|
c.ViewArgs["curNotebookId"] = note.NotebookId.Hex()
|
||||||
|
|
||||||
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
|
// 打开的是共享的笔记, 那么判断是否是共享给我的默认笔记
|
||||||
if noteOwner != c.GetUserId() {
|
if noteOwner != c.GetUserId() {
|
||||||
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
|
if shareService.HasReadPerm(noteOwner, c.GetUserId(), noteId) {
|
||||||
// 不要获取notebook下的笔记
|
// 不要获取notebook下的笔记
|
||||||
// 在前端下发请求
|
// 在前端下发请求
|
||||||
c.RenderArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
|
c.ViewArgs["curSharedNoteNotebookId"] = note.NotebookId.Hex()
|
||||||
c.RenderArgs["curSharedUserId"] = noteOwner
|
c.ViewArgs["curSharedUserId"] = noteOwner
|
||||||
// 没有读写权限
|
// 没有读写权限
|
||||||
} else {
|
} else {
|
||||||
hasRightNoteId = false
|
hasRightNoteId = false
|
||||||
@@ -97,7 +98,7 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
|
|
||||||
// 得到最近的笔记
|
// 得到最近的笔记
|
||||||
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
_, latestNotes := noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
||||||
c.RenderArgs["latestNotes"] = latestNotes
|
c.ViewArgs["latestNotes"] = latestNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有传入笔记
|
// 没有传入笔记
|
||||||
@@ -106,27 +107,27 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false)
|
||||||
if len(notes) > 0 {
|
if len(notes) > 0 {
|
||||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
||||||
c.RenderArgs["curNoteId"] = notes[0].NoteId.Hex()
|
c.ViewArgs["curNoteId"] = notes[0].NoteId.Hex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当然, 还需要得到第一个notes的content
|
// 当然, 还需要得到第一个notes的content
|
||||||
//...
|
//...
|
||||||
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
c.ViewArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||||
|
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["notebooks"] = notebooks
|
c.ViewArgs["notebooks"] = notebooks
|
||||||
c.RenderArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
|
c.ViewArgs["shareNotebooks"] = shareNotebooks // note信息在notes列表中
|
||||||
c.RenderArgs["sharedUserInfos"] = sharedUserInfos
|
c.ViewArgs["sharedUserInfos"] = sharedUserInfos
|
||||||
|
|
||||||
c.RenderArgs["notes"] = notes
|
c.ViewArgs["notes"] = notes
|
||||||
c.RenderArgs["noteContentJson"] = noteContent
|
c.ViewArgs["noteContentJson"] = noteContent
|
||||||
c.RenderArgs["noteContent"] = noteContent.Content
|
c.ViewArgs["noteContent"] = noteContent.Content
|
||||||
|
|
||||||
c.RenderArgs["tags"] = tagService.GetTags(c.GetUserId())
|
c.ViewArgs["tags"] = tagService.GetTags(c.GetUserId())
|
||||||
|
|
||||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
c.ViewArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
|
|
||||||
// return c.RenderTemplate("note/note.html")
|
// return c.RenderTemplate("note/note.html")
|
||||||
|
|
||||||
@@ -142,24 +143,34 @@ func (c Note) Index(noteId, online string) revel.Result {
|
|||||||
// 否则, 转向登录页面
|
// 否则, 转向登录页面
|
||||||
func (c Note) ListNotes(notebookId string) revel.Result {
|
func (c Note) ListNotes(notebookId string) revel.Result {
|
||||||
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
||||||
return c.RenderJson(notes)
|
return c.RenderJSON(notes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到trash
|
// 得到trash
|
||||||
func (c Note) ListTrashNotes() revel.Result {
|
func (c Note) ListTrashNotes() revel.Result {
|
||||||
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
||||||
return c.RenderJson(notes)
|
return c.RenderJSON(notes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到note和内容
|
// 得到note和内容
|
||||||
func (c Note) GetNoteAndContent(noteId string) revel.Result {
|
func (c Note) GetNoteAndContent(noteId string) revel.Result {
|
||||||
return c.RenderJson(noteService.GetNoteAndContent(noteId, c.GetUserId()))
|
return c.RenderJSON(noteService.GetNoteAndContent(noteId, c.GetUserId()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Note) GetNoteAndContentBySrc(src string) revel.Result {
|
||||||
|
noteId, noteAndContent := noteService.GetNoteAndContentBySrc(src, c.GetUserId())
|
||||||
|
ret := info.Re{}
|
||||||
|
if noteId != "" {
|
||||||
|
ret.Ok = true
|
||||||
|
ret.Item = noteAndContent
|
||||||
|
}
|
||||||
|
return c.RenderJSON(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到内容
|
// 得到内容
|
||||||
func (c Note) GetNoteContent(noteId string) revel.Result {
|
func (c Note) GetNoteContent(noteId string) revel.Result {
|
||||||
noteContent := noteService.GetNoteContent(noteId, c.GetUserId())
|
noteContent := noteService.GetNoteContent(noteId, c.GetUserId())
|
||||||
return c.RenderJson(noteContent)
|
return c.RenderJSON(noteContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里不能用json, 要用post
|
// 这里不能用json, 要用post
|
||||||
@@ -177,6 +188,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
|
|||||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||||
Title: noteOrContent.Title,
|
Title: noteOrContent.Title,
|
||||||
|
Src: noteOrContent.Src, // 来源
|
||||||
Tags: strings.Split(noteOrContent.Tags, ","),
|
Tags: strings.Split(noteOrContent.Tags, ","),
|
||||||
Desc: noteOrContent.Desc,
|
Desc: noteOrContent.Desc,
|
||||||
ImgSrc: noteOrContent.ImgSrc,
|
ImgSrc: noteOrContent.ImgSrc,
|
||||||
@@ -190,7 +202,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
|
|||||||
Abstract: noteOrContent.Abstract}
|
Abstract: noteOrContent.Abstract}
|
||||||
|
|
||||||
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||||
return c.RenderJson(note)
|
return c.RenderJSON(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
noteUpdate := bson.M{}
|
noteUpdate := bson.M{}
|
||||||
@@ -237,7 +249,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent info.NoteOrContent) revel.Result
|
|||||||
Log(contentOk)
|
Log(contentOk)
|
||||||
Log(contentMsg)
|
Log(contentMsg)
|
||||||
|
|
||||||
return c.RenderJson(true)
|
return c.RenderJSON(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除note/ 删除别人共享给我的笔记
|
// 删除note/ 删除别人共享给我的笔记
|
||||||
@@ -247,19 +259,19 @@ func (c Note) DeleteNote(noteIds []string, isShared bool) revel.Result {
|
|||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
trashService.DeleteNote(noteId, c.GetUserId())
|
trashService.DeleteNote(noteId, c.GetUserId())
|
||||||
}
|
}
|
||||||
return c.RenderJson(true)
|
return c.RenderJSON(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
trashService.DeleteSharedNote(noteId, c.GetUserId())
|
trashService.DeleteSharedNote(noteId, c.GetUserId())
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(true)
|
return c.RenderJSON(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除trash, 已弃用, 用DeleteNote
|
// 删除trash, 已弃用, 用DeleteNote
|
||||||
func (c Note) DeleteTrash(noteId string) revel.Result {
|
func (c Note) DeleteTrash(noteId string) revel.Result {
|
||||||
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()))
|
return c.RenderJSON(trashService.DeleteTrash(noteId, c.GetUserId()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动note
|
// 移动note
|
||||||
@@ -268,7 +280,7 @@ func (c Note) MoveNote(noteIds []string, notebookId string) revel.Result {
|
|||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
noteService.MoveNote(noteId, notebookId, userId)
|
noteService.MoveNote(noteId, notebookId, userId)
|
||||||
}
|
}
|
||||||
return c.RenderJson(true)
|
return c.RenderJSON(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制note
|
// 复制note
|
||||||
@@ -281,7 +293,7 @@ func (c Note) CopyNote(noteIds []string, notebookId string) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Item = copyNotes
|
re.Item = copyNotes
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制别人共享的笔记给我
|
// 复制别人共享的笔记给我
|
||||||
@@ -294,7 +306,7 @@ func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) re
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Item = copyNotes
|
re.Item = copyNotes
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
@@ -302,13 +314,13 @@ func (c Note) CopySharedNote(noteIds []string, notebookId, fromUserId string) re
|
|||||||
// 通过title搜索
|
// 通过title搜索
|
||||||
func (c Note) SearchNote(key string) revel.Result {
|
func (c Note) SearchNote(key string) revel.Result {
|
||||||
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
||||||
return c.RenderJson(blogs)
|
return c.RenderJSON(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过tags搜索
|
// 通过tags搜索
|
||||||
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
||||||
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
||||||
return c.RenderJson(blogs)
|
return c.RenderJSON(blogs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成PDF
|
// 生成PDF
|
||||||
@@ -338,6 +350,8 @@ func (c Note) ToPdf(noteId, appKey string) revel.Result {
|
|||||||
siteUrlPattern = strings.Replace(siteUrlPattern, "http", "https*", 1)
|
siteUrlPattern = strings.Replace(siteUrlPattern, "http", "https*", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
siteUrlPattern = "(?:" + siteUrlPattern + ")*"
|
||||||
|
|
||||||
regImage, _ := regexp.Compile(`<img .*?(src=('|")` + siteUrlPattern + `/(file/outputImage|api/file/getImage)\?fileId=([a-z0-9A-Z]{24})("|'))`)
|
regImage, _ := regexp.Compile(`<img .*?(src=('|")` + siteUrlPattern + `/(file/outputImage|api/file/getImage)\?fileId=([a-z0-9A-Z]{24})("|'))`)
|
||||||
|
|
||||||
findsImage := regImage.FindAllStringSubmatch(contentStr, -1) // 查找所有的
|
findsImage := regImage.FindAllStringSubmatch(contentStr, -1) // 查找所有的
|
||||||
@@ -384,11 +398,11 @@ func (c Note) ToPdf(noteId, appKey string) revel.Result {
|
|||||||
} else {
|
} else {
|
||||||
note.Tags = nil
|
note.Tags = nil
|
||||||
}
|
}
|
||||||
c.RenderArgs["blog"] = note
|
c.ViewArgs["blog"] = note
|
||||||
c.RenderArgs["content"] = contentStr
|
c.ViewArgs["content"] = contentStr
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
userBlog := blogService.GetUserBlog(noteUserId)
|
userBlog := blogService.GetUserBlog(noteUserId)
|
||||||
c.RenderArgs["userBlog"] = userBlog
|
c.ViewArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
return c.RenderTemplate("file/pdf.html")
|
return c.RenderTemplate("file/pdf.html")
|
||||||
}
|
}
|
||||||
@@ -433,8 +447,12 @@ func (c Note) ExportPdf(noteId string) revel.Result {
|
|||||||
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
|
binPath := configService.GetGlobalStringConfig("exportPdfBinPath")
|
||||||
// 默认路径
|
// 默认路径
|
||||||
if binPath == "" {
|
if binPath == "" {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
binPath = `C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe`
|
||||||
|
} else {
|
||||||
binPath = "/usr/local/bin/wkhtmltopdf"
|
binPath = "/usr/local/bin/wkhtmltopdf"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
|
url := configService.GetSiteUrl() + "/note/toPdf?noteId=" + noteId + "&appKey=" + appKey
|
||||||
// cc := binPath + " --no-stop-slow-scripts --javascript-delay 10000 \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
// cc := binPath + " --no-stop-slow-scripts --javascript-delay 10000 \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
@@ -443,13 +461,29 @@ func (c Note) ExportPdf(noteId string) revel.Result {
|
|||||||
// http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html
|
// http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf_0.10.0_rc2-doc.html
|
||||||
// wkhtmltopdf参数大全
|
// wkhtmltopdf参数大全
|
||||||
var cc string
|
var cc string
|
||||||
|
// var cc []string
|
||||||
|
var ccWindows []string
|
||||||
if note.IsMarkdown {
|
if note.IsMarkdown {
|
||||||
cc = binPath + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
cc = binPath + " --lowquality --window-status done \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
|
// cc = []string{binPath, "--lowquality", "--window-status", "done", "\"" + url + "\"", "\"" + path + "\""}
|
||||||
|
ccWindows = []string{"/C", binPath, "--lowquality", "--window-status", "done", url, path}
|
||||||
} else {
|
} else {
|
||||||
cc = binPath + " --lowquality \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
cc = binPath + " --lowquality \"" + url + "\" \"" + path + "\"" // \"" + cookieDomain + "\" \"" + cookieName + "\" \"" + cookieValue + "\""
|
||||||
|
// cc = []string{binPath, "--lowquality", "\"" + url + "\"", "\"" + path + "\""}
|
||||||
|
ccWindows = []string{"/C", binPath, "--lowquality", url, path}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", cc)
|
var cmd *exec.Cmd
|
||||||
|
|
||||||
|
// fmt.Println("-------1", runtime.GOOS, ccWindows)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
fmt.Println(ccWindows)
|
||||||
|
// cmd = exec.Command("cmd", ccWindows...)
|
||||||
|
cmd = exec.Command(ccWindows[1], ccWindows[2:]...)
|
||||||
|
} else {
|
||||||
|
fmt.Println(cc)
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", cc)
|
||||||
|
}
|
||||||
_, err := cmd.Output()
|
_, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
|
return c.RenderText("export pdf error. " + fmt.Sprintf("%v", err))
|
||||||
@@ -475,5 +509,5 @@ func (c Note) SetNote2Blog(noteIds []string, isBlog, isTop bool) revel.Result {
|
|||||||
for _, noteId := range noteIds {
|
for _, noteId := range noteIds {
|
||||||
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||||
}
|
}
|
||||||
return c.RenderJson(true)
|
return c.RenderJSON(true)
|
||||||
}
|
}
|
||||||
@@ -14,18 +14,18 @@ type Notebook struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c Notebook) Index(notebook info.Notebook, i int, name string) revel.Result {
|
func (c Notebook) Index(notebook info.Notebook, i int, name string) revel.Result {
|
||||||
return c.RenderJson(notebook)
|
return c.RenderJSON(notebook)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户的所有笔记本
|
// 得到用户的所有笔记本
|
||||||
func (c Notebook) GetNotebooks() revel.Result {
|
func (c Notebook) GetNotebooks() revel.Result {
|
||||||
re := notebookService.GetNotebooks(c.GetUserId())
|
re := notebookService.GetNotebooks(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
||||||
re, msg := notebookService.DeleteNotebook(c.GetUserId(), notebookId)
|
re, msg := notebookService.DeleteNotebook(c.GetUserId(), notebookId)
|
||||||
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
return c.RenderJSON(info.Re{Ok: re, Msg: msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加notebook
|
// 添加notebook
|
||||||
@@ -41,21 +41,21 @@ func (c Notebook) AddNotebook(notebookId, title, parentNotebookId string) revel.
|
|||||||
re, notebook := notebookService.AddNotebook(notebook)
|
re, notebook := notebookService.AddNotebook(notebook)
|
||||||
|
|
||||||
if re {
|
if re {
|
||||||
return c.RenderJson(notebook)
|
return c.RenderJSON(notebook)
|
||||||
} else {
|
} else {
|
||||||
return c.RenderJson(false)
|
return c.RenderJSON(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改标题
|
// 修改标题
|
||||||
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||||
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
return c.RenderJSON(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
// 无用
|
// 无用
|
||||||
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
// func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||||
// return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
// return c.RenderJSON(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
|
// 调整notebooks, 可能是排序, 可能是移动到其它笔记本下
|
||||||
@@ -70,11 +70,11 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
|
|||||||
info := DragNotebooksInfo{}
|
info := DragNotebooksInfo{}
|
||||||
json.Unmarshal([]byte(data), &info)
|
json.Unmarshal([]byte(data), &info)
|
||||||
|
|
||||||
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
return c.RenderJSON(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置notebook <-> blog
|
// 设置notebook <-> blog
|
||||||
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||||
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
|
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -32,10 +32,10 @@ func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
|||||||
}
|
}
|
||||||
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
||||||
|
|
||||||
c.RenderArgs["isPreview"] = true
|
c.ViewArgs["isPreview"] = true
|
||||||
c.RenderArgs["themeId"] = themeId
|
c.ViewArgs["themeId"] = themeId
|
||||||
c.RenderArgs["themeInfoPreview"] = theme.Info
|
c.ViewArgs["themeInfoPreview"] = theme.Info
|
||||||
c.RenderArgs["themePath"] = theme.Path
|
c.ViewArgs["themePath"] = theme.Path
|
||||||
if theme.Path == "" {
|
if theme.Path == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
|
|||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Index(c.GetUserId())
|
return c.Blog.Index(c.GetUserId())
|
||||||
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
// return blog.RenderTemplate("index.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
||||||
@@ -62,42 +62,42 @@ func (c Preview) Tags(userIdOrEmail string) revel.Result {
|
|||||||
}
|
}
|
||||||
return c.Blog.Tags(c.GetUserId())
|
return c.Blog.Tags(c.GetUserId())
|
||||||
// if tag == "" {
|
// if tag == "" {
|
||||||
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("tags.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
// }
|
// }
|
||||||
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("tag_posts.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
|
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
|
||||||
if !c.getPreviewThemeAbsolutePath("") {
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
|
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
|
||||||
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("archive.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
|
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
|
||||||
if !c.getPreviewThemeAbsolutePath("") {
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Cate(userIdOrEmail, notebookId)
|
return c.Blog.Cate(userIdOrEmail, notebookId)
|
||||||
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("cate.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
|
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
|
||||||
if !c.getPreviewThemeAbsolutePath("") {
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Post(userIdOrEmail, noteId)
|
return c.Blog.Post(userIdOrEmail, noteId)
|
||||||
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("view.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
|
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
|
||||||
if !c.getPreviewThemeAbsolutePath("") {
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Single(userIdOrEmail, singleId)
|
return c.Blog.Single(userIdOrEmail, singleId)
|
||||||
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("single.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
||||||
if !c.getPreviewThemeAbsolutePath("") {
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
return c.Blog.Search(c.GetUserId(), keywords)
|
return c.Blog.Search(c.GetUserId(), keywords)
|
||||||
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
// return blog.RenderTemplate("search.html", c.ViewArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Resu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(status)
|
return c.RenderJSON(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加共享notebook
|
// 添加共享notebook
|
||||||
@@ -53,7 +53,7 @@ func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(status)
|
return c.RenderJSON(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到notes
|
// 得到notes
|
||||||
@@ -63,10 +63,10 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
|
|||||||
var notes []info.ShareNoteWithPerm
|
var notes []info.ShareNoteWithPerm
|
||||||
if notebookId == "" {
|
if notebookId == "" {
|
||||||
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false)
|
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false)
|
||||||
return c.RenderJson(notes)
|
return c.RenderJSON(notes)
|
||||||
} else {
|
} else {
|
||||||
// 有notebookId的
|
// 有notebookId的
|
||||||
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false))
|
return c.RenderJSON(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
|
|||||||
// sharedUserId 是谁的笔记
|
// sharedUserId 是谁的笔记
|
||||||
func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
|
func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
|
||||||
noteContent := shareService.GetShareNoteContent(noteId, c.GetUserId(), sharedUserId)
|
noteContent := shareService.GetShareNoteContent(noteId, c.GetUserId(), sharedUserId)
|
||||||
return c.RenderJson(noteContent)
|
return c.RenderJSON(noteContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看note的分享信息
|
// 查看note的分享信息
|
||||||
@@ -85,13 +85,13 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
|||||||
note := noteService.GetNote(noteId, c.GetUserId())
|
note := noteService.GetNote(noteId, c.GetUserId())
|
||||||
|
|
||||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
c.ViewArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||||
|
|
||||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
c.ViewArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = true
|
c.ViewArgs["isNote"] = true
|
||||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex()
|
c.ViewArgs["noteOrNotebookId"] = note.NoteId.Hex()
|
||||||
c.RenderArgs["title"] = note.Title
|
c.ViewArgs["title"] = note.Title
|
||||||
|
|
||||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||||
}
|
}
|
||||||
@@ -99,14 +99,14 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
|||||||
notebook := notebookService.GetNotebook(notebookId, c.GetUserId())
|
notebook := notebookService.GetNotebook(notebookId, c.GetUserId())
|
||||||
|
|
||||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
c.ViewArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||||
|
|
||||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
c.ViewArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||||
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
LogJ(c.ViewArgs["noteOrNotebookShareGroupInfos"])
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = false
|
c.ViewArgs["isNote"] = false
|
||||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex()
|
c.ViewArgs["noteOrNotebookId"] = notebook.NotebookId.Hex()
|
||||||
c.RenderArgs["title"] = notebook.Title
|
c.ViewArgs["title"] = notebook.Title
|
||||||
|
|
||||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||||
}
|
}
|
||||||
@@ -114,38 +114,38 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
|||||||
//------------
|
//------------
|
||||||
// 改变share note 权限
|
// 改变share note 权限
|
||||||
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
|
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId))
|
return c.RenderJSON(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改变share notebook 权限
|
// 改变share notebook 权限
|
||||||
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
|
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId))
|
return c.RenderJSON(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId))
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
// 删除share note
|
// 删除share note
|
||||||
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
|
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId))
|
return c.RenderJSON(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除share notebook
|
// 删除share notebook
|
||||||
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
|
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId))
|
return c.RenderJSON(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除share note, 被共享方删除
|
// 删除share note, 被共享方删除
|
||||||
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
|
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()))
|
return c.RenderJSON(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除share notebook, 被共享方删除
|
// 删除share notebook, 被共享方删除
|
||||||
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
|
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()))
|
return c.RenderJSON(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除fromUserId分享给我的所有note, notebook
|
// 删除fromUserId分享给我的所有note, notebook
|
||||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()))
|
return c.RenderJSON(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()))
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------
|
//-------------
|
||||||
@@ -155,14 +155,14 @@ func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
|||||||
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm)
|
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId)
|
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新, 也是一样, 先删后加
|
// 更新, 也是一样, 先删后加
|
||||||
@@ -176,14 +176,14 @@ func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.
|
|||||||
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm)
|
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId)
|
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新, 也是一样, 先删后加
|
// 更新, 也是一样, 先删后加
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func (c Tag) UpdateTag(tag string) revel.Result {
|
|||||||
ret := info.NewRe()
|
ret := info.NewRe()
|
||||||
ret.Ok = true
|
ret.Ok = true
|
||||||
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
|
ret.Item = tagService.AddOrUpdateTag(c.GetUserId(), tag)
|
||||||
return c.RenderJson(ret)
|
return c.RenderJSON(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除标签
|
// 删除标签
|
||||||
@@ -26,5 +26,5 @@ func (c Tag) DeleteTag(tag string) revel.Result {
|
|||||||
ret := info.Re{}
|
ret := info.Re{}
|
||||||
ret.Ok = true
|
ret.Ok = true
|
||||||
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
|
ret.Item = tagService.DeleteTag(c.GetUserId(), tag)
|
||||||
return c.RenderJson(ret)
|
return c.RenderJSON(ret)
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,8 @@ type User struct {
|
|||||||
|
|
||||||
func (c User) Account(tab int) revel.Result {
|
func (c User) Account(tab int) revel.Result {
|
||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["tab"] = tab
|
c.ViewArgs["tab"] = tab
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
return c.RenderTemplate("user/account.html")
|
return c.RenderTemplate("user/account.html")
|
||||||
}
|
}
|
||||||
@@ -70,18 +70,18 @@ func (c User) UpdateTheme(theme string) revel.Result {
|
|||||||
if re.Ok {
|
if re.Ok {
|
||||||
c.UpdateSession("Theme", theme)
|
c.UpdateSession("Theme", theme)
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送邀请链接
|
// 发送邀请链接
|
||||||
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
if content == "" || !IsEmail(toEmail) {
|
if content == "" || !IsEmail(toEmail) {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
|
re.Ok = emailService.SendInviteEmail(c.GetUserInfo(), toEmail, content)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
@@ -90,7 +90,7 @@ func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
|||||||
func (c User) ReSendActiveEmail() revel.Result {
|
func (c User) ReSendActiveEmail() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = emailService.RegisterSendActiveEmail(c.GetUserInfo(), c.GetEmail())
|
re.Ok = emailService.RegisterSendActiveEmail(c.GetUserInfo(), c.GetEmail())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过点击链接
|
// 通过点击链接
|
||||||
@@ -100,10 +100,10 @@ func (c User) UpdateEmail(token string) revel.Result {
|
|||||||
|
|
||||||
ok, msg, email := userService.UpdateEmail(token)
|
ok, msg, email := userService.UpdateEmail(token)
|
||||||
|
|
||||||
c.RenderArgs["title"] = "验证邮箱"
|
c.ViewArgs["title"] = "验证邮箱"
|
||||||
c.RenderArgs["ok"] = ok
|
c.ViewArgs["ok"] = ok
|
||||||
c.RenderArgs["msg"] = msg
|
c.ViewArgs["msg"] = msg
|
||||||
c.RenderArgs["email"] = email
|
c.ViewArgs["email"] = email
|
||||||
|
|
||||||
// 修改session
|
// 修改session
|
||||||
if ok {
|
if ok {
|
||||||
@@ -124,10 +124,10 @@ func (c User) ActiveEmail(token string) revel.Result {
|
|||||||
c.UpdateSession("Verified", "1")
|
c.UpdateSession("Verified", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["title"] = "验证邮箱"
|
c.ViewArgs["title"] = "验证邮箱"
|
||||||
c.RenderArgs["ok"] = ok
|
c.ViewArgs["ok"] = ok
|
||||||
c.RenderArgs["msg"] = msg
|
c.ViewArgs["msg"] = msg
|
||||||
c.RenderArgs["email"] = email
|
c.ViewArgs["email"] = email
|
||||||
|
|
||||||
return c.RenderTemplate("user/active_email.html")
|
return c.RenderTemplate("user/active_email.html")
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func (c User) UpdateColumnWidth(notebookWidth, noteListWidth, mdEditorWidth int)
|
|||||||
|
|
||||||
LogJ(c.Session)
|
LogJ(c.Session)
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
|
func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
@@ -156,5 +156,5 @@ func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
|
|||||||
c.UpdateSession("LeftIsMin", "0")
|
c.UpdateSession("LeftIsMin", "0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ func (c AdminBaseController) getSorter(sorterField string, isAsc bool, okSorter
|
|||||||
} else {
|
} else {
|
||||||
isAsc = false
|
isAsc = false
|
||||||
}
|
}
|
||||||
c.RenderArgs["sorter"] = sorter
|
c.ViewArgs["sorter"] = sorter
|
||||||
return sorterField, isAsc
|
return sorterField, isAsc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
|||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"})
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"})
|
||||||
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.ViewArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["blogs"] = blogs
|
c.ViewArgs["blogs"] = blogs
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.ViewArgs["keywords"] = keywords
|
||||||
return c.RenderTemplate("admin/blog/list.html")
|
return c.RenderTemplate("admin/blog/list.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.SetRecommend(noteId, recommend)
|
re.Ok = blogService.SetRecommend(noteId, recommend)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -14,23 +14,23 @@ type Admin struct {
|
|||||||
func (c Admin) Index() revel.Result {
|
func (c Admin) Index() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
|
|
||||||
c.RenderArgs["title"] = "leanote"
|
c.ViewArgs["title"] = "leanote"
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
c.RenderArgs["countUser"] = userService.CountUser()
|
c.ViewArgs["countUser"] = userService.CountUser()
|
||||||
c.RenderArgs["countNote"] = noteService.CountNote("")
|
c.ViewArgs["countNote"] = noteService.CountNote("")
|
||||||
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
c.ViewArgs["countBlog"] = noteService.CountBlog("")
|
||||||
|
|
||||||
return c.RenderTemplate("admin/index.html")
|
return c.RenderTemplate("admin/index.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模板
|
// 模板
|
||||||
func (c Admin) T(t string) revel.Result {
|
func (c Admin) T(t string) revel.Result {
|
||||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
c.ViewArgs["str"] = configService.GlobalStringConfigs
|
||||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
c.ViewArgs["map"] = configService.GlobalMapConfigs
|
||||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
c.ViewArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||||
c.RenderArgs["version"] = configService.GetVersion()
|
c.ViewArgs["version"] = configService.GetVersion()
|
||||||
return c.RenderTemplate("admin/" + t + ".html")
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,33 +26,33 @@ func (c AdminData) Index() revel.Result {
|
|||||||
backups2[j] = backups[i]
|
backups2[j] = backups[i]
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
c.RenderArgs["backups"] = backups2
|
c.ViewArgs["backups"] = backups2
|
||||||
return c.RenderTemplate("admin/data/index.html")
|
return c.RenderTemplate("admin/data/index.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminData) Backup() revel.Result {
|
func (c AdminData) Backup() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = configService.Backup("")
|
re.Ok, re.Msg = configService.Backup("")
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 还原
|
// 还原
|
||||||
func (c AdminData) Restore(createdTime string) revel.Result {
|
func (c AdminData) Restore(createdTime string) revel.Result {
|
||||||
re := info.Re{}
|
re := info.Re{}
|
||||||
re.Ok, re.Msg = configService.Restore(createdTime)
|
re.Ok, re.Msg = configService.Restore(createdTime)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminData) Delete(createdTime string) revel.Result {
|
func (c AdminData) Delete(createdTime string) revel.Result {
|
||||||
re := info.Re{}
|
re := info.Re{}
|
||||||
re.Ok, re.Msg = configService.DeleteBackup(createdTime)
|
re.Ok, re.Msg = configService.DeleteBackup(createdTime)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c AdminData) UpdateRemark(createdTime, remark string) revel.Result {
|
func (c AdminData) UpdateRemark(createdTime, remark string) revel.Result {
|
||||||
re := info.Re{}
|
re := info.Re{}
|
||||||
re.Ok, re.Msg = configService.UpdateBackupRemark(createdTime, remark)
|
re.Ok, re.Msg = configService.UpdateBackupRemark(createdTime, remark)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c AdminData) Download(createdTime string) revel.Result {
|
func (c AdminData) Download(createdTime string) revel.Result {
|
||||||
backup, ok := configService.GetBackup(createdTime)
|
backup, ok := configService.GetBackup(createdTime)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ func (c AdminEmail) Email() revel.Result {
|
|||||||
func (c AdminEmail) Blog() revel.Result {
|
func (c AdminEmail) Blog() revel.Result {
|
||||||
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
||||||
newTags := configService.GetGlobalArrayConfig("newTags")
|
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||||
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
c.ViewArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||||
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
c.ViewArgs["newTags"] = strings.Join(newTags, ",")
|
||||||
return c.RenderTemplate("admin/setting/blog.html")
|
return c.RenderTemplate("admin/setting/blog.html")
|
||||||
}
|
}
|
||||||
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||||
@@ -33,14 +33,14 @@ func (c AdminEmail) DoBlogTag(recommendTags, newTags string) revel.Result {
|
|||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// demo
|
// demo
|
||||||
// blog标签设置
|
// blog标签设置
|
||||||
func (c AdminEmail) Demo() revel.Result {
|
func (c AdminEmail) Demo() revel.Result {
|
||||||
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
c.ViewArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||||
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
c.ViewArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||||
return c.RenderTemplate("admin/setting/demo.html")
|
return c.RenderTemplate("admin/setting/demo.html")
|
||||||
}
|
}
|
||||||
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
@@ -48,30 +48,30 @@ func (c AdminEmail) DoDemo(demoUsername, demoPassword string) revel.Result {
|
|||||||
|
|
||||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
userInfo, err := authService.Login(demoUsername, demoPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
return c.RenderJSON(info.Re{Ok: false})
|
||||||
}
|
}
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
re.Msg = "The User is Not Exists"
|
re.Msg = "The User is Not Exists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToImage
|
// ToImage
|
||||||
// 长微博的bin路径phantomJs
|
// 长微博的bin路径phantomJs
|
||||||
func (c AdminEmail) ToImage() revel.Result {
|
func (c AdminEmail) ToImage() revel.Result {
|
||||||
c.RenderArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
c.ViewArgs["toImageBinPath"] = configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
return c.RenderTemplate("admin/setting/toImage.html")
|
return c.RenderTemplate("admin/setting/toImage.html")
|
||||||
}
|
}
|
||||||
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
|
func (c AdminEmail) DoToImage(toImageBinPath string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "toImageBinPath", toImageBinPath)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emailSSL string) revel.Result {
|
func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emailSSL string) revel.Result {
|
||||||
@@ -82,7 +82,7 @@ func (c AdminEmail) Set(emailHost, emailPort, emailUsername, emailPassword, emai
|
|||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailPassword", emailPassword)
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "emailSSL", emailSSL)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c AdminEmail) Template() revel.Result {
|
func (c AdminEmail) Template() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
@@ -108,7 +108,7 @@ func (c AdminEmail) Template() revel.Result {
|
|||||||
if !ok {
|
if !ok {
|
||||||
re.Ok = false
|
re.Ok = false
|
||||||
re.Msg = "Error key: " + key + "<br />" + msg
|
re.Msg = "Error key: " + key + "<br />" + msg
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
} else {
|
} else {
|
||||||
configService.UpdateGlobalStringConfig(userId, key, v)
|
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ func (c AdminEmail) Template() revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送Email
|
// 发送Email
|
||||||
@@ -127,7 +127,7 @@ func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmai
|
|||||||
|
|
||||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
re.Msg = "subject or body is blank"
|
re.Msg = "subject or body is blank"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if saveAsOldEmail {
|
if saveAsOldEmail {
|
||||||
@@ -140,7 +140,7 @@ func (c AdminEmail) SendEmailToEmails(sendEmails, latestEmailSubject, latestEmai
|
|||||||
emails := strings.Split(sendEmails, "\n")
|
emails := strings.Split(sendEmails, "\n")
|
||||||
|
|
||||||
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody)
|
re.Ok, re.Msg = emailService.SendEmailToEmails(emails, latestEmailSubject, latestEmailBody)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送Email
|
// 发送Email
|
||||||
@@ -151,7 +151,7 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
|
|||||||
|
|
||||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
re.Msg = "subject or body is blank"
|
re.Msg = "subject or body is blank"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if saveAsOldEmail {
|
if saveAsOldEmail {
|
||||||
@@ -168,7 +168,7 @@ func (c AdminEmail) SendToUsers2(emails, latestEmailSubject, latestEmailBody str
|
|||||||
|
|
||||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Email dialog
|
// send Email dialog
|
||||||
@@ -176,9 +176,9 @@ func (c AdminEmail) SendEmailDialog(emails string) revel.Result {
|
|||||||
emailsArr := strings.Split(emails, ",")
|
emailsArr := strings.Split(emails, ",")
|
||||||
emailsNl := strings.Join(emailsArr, "\n")
|
emailsNl := strings.Join(emailsArr, "\n")
|
||||||
|
|
||||||
c.RenderArgs["emailsNl"] = emailsNl
|
c.ViewArgs["emailsNl"] = emailsNl
|
||||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
c.ViewArgs["str"] = configService.GlobalStringConfigs
|
||||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
c.ViewArgs["map"] = configService.GlobalMapConfigs
|
||||||
|
|
||||||
return c.RenderTemplate("admin/email/emailDialog.html")
|
return c.RenderTemplate("admin/email/emailDialog.html")
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilter
|
|||||||
|
|
||||||
if latestEmailSubject == "" || latestEmailBody == "" {
|
if latestEmailSubject == "" || latestEmailBody == "" {
|
||||||
re.Msg = "subject or body is blank"
|
re.Msg = "subject or body is blank"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if saveAsOldEmail {
|
if saveAsOldEmail {
|
||||||
@@ -204,33 +204,33 @@ func (c AdminEmail) SendToUsers(userFilterEmail, userFilterWhiteList, userFilter
|
|||||||
if users == nil || len(users) == 0 {
|
if users == nil || len(users) == 0 {
|
||||||
re.Ok = false
|
re.Ok = false
|
||||||
re.Msg = "no users"
|
re.Msg = "no users"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
re.Ok, re.Msg = emailService.SendEmailToUsers(users, latestEmailSubject, latestEmailBody)
|
||||||
if !re.Ok {
|
if !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Msg = "users:" + strconv.Itoa(len(users))
|
re.Msg = "users:" + strconv.Itoa(len(users))
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除emails
|
// 删除emails
|
||||||
func (c AdminEmail) DeleteEmails(ids string) revel.Result {
|
func (c AdminEmail) DeleteEmails(ids string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = emailService.DeleteEmails(strings.Split(ids, ","))
|
re.Ok = emailService.DeleteEmails(strings.Split(ids, ","))
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminEmail) List(sorter, keywords string) revel.Result {
|
func (c AdminEmail) List(sorter, keywords string) revel.Result {
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"})
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "ok", "subject", "createdTime"})
|
||||||
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords)
|
pageInfo, emails := emailService.ListEmailLogs(pageNumber, userPageSize, sorterField, isAsc, keywords)
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.ViewArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["emails"] = emails
|
c.ViewArgs["emails"] = emails
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.ViewArgs["keywords"] = keywords
|
||||||
return c.RenderTemplate("admin/email/list.html")
|
return c.RenderTemplate("admin/email/list.html")
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,8 @@ func (c AdminSetting) Email() revel.Result {
|
|||||||
func (c AdminSetting) Blog() revel.Result {
|
func (c AdminSetting) Blog() revel.Result {
|
||||||
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
recommendTags := configService.GetGlobalArrayConfig("recommendTags")
|
||||||
newTags := configService.GetGlobalArrayConfig("newTags")
|
newTags := configService.GetGlobalArrayConfig("newTags")
|
||||||
c.RenderArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
c.ViewArgs["recommendTags"] = strings.Join(recommendTags, ",")
|
||||||
c.RenderArgs["newTags"] = strings.Join(newTags, ",")
|
c.ViewArgs["newTags"] = strings.Join(newTags, ",")
|
||||||
return c.RenderTemplate("admin/setting/blog.html")
|
return c.RenderTemplate("admin/setting/blog.html")
|
||||||
}
|
}
|
||||||
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
|
func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
|
||||||
@@ -33,7 +33,7 @@ func (c AdminSetting) DoBlogTag(recommendTags, newTags string) revel.Result {
|
|||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "recommendTags", strings.Split(recommendTags, ","))
|
||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "newTags", strings.Split(newTags, ","))
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 共享设置
|
// 共享设置
|
||||||
@@ -43,14 +43,14 @@ func (c AdminSetting) ShareNote(registerSharedUserId string,
|
|||||||
|
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds)
|
re.Ok, re.Msg = configService.UpdateShareNoteConfig(registerSharedUserId, registerSharedNotebookPerms, registerSharedNotePerms, registerSharedNotebookIds, registerSharedNoteIds, registerCopyNoteIds)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// demo
|
// demo
|
||||||
// blog标签设置
|
// blog标签设置
|
||||||
func (c AdminSetting) Demo() revel.Result {
|
func (c AdminSetting) Demo() revel.Result {
|
||||||
c.RenderArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
c.ViewArgs["demoUsername"] = configService.GetGlobalStringConfig("demoUsername")
|
||||||
c.RenderArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
c.ViewArgs["demoPassword"] = configService.GetGlobalStringConfig("demoPassword")
|
||||||
return c.RenderTemplate("admin/setting/demo.html")
|
return c.RenderTemplate("admin/setting/demo.html")
|
||||||
}
|
}
|
||||||
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
||||||
@@ -59,40 +59,40 @@ func (c AdminSetting) DoDemo(demoUsername, demoPassword string) revel.Result {
|
|||||||
userInfo, err := authService.Login(demoUsername, demoPassword)
|
userInfo, err := authService.Login(demoUsername, demoPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return c.RenderJson(info.Re{Ok: false})
|
return c.RenderJSON(info.Re{Ok: false})
|
||||||
}
|
}
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
re.Msg = "The User is Not Exists"
|
re.Msg = "The User is Not Exists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUserId", userInfo.UserId.Hex())
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoUsername", demoUsername)
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "demoPassword", demoPassword)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) ExportPdf(path string) revel.Result {
|
func (c AdminSetting) ExportPdf(path string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "exportPdfBinPath", path)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
|
func (c AdminSetting) DoSiteUrl(siteUrl string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "siteUrl", siteUrl)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubDomain
|
// SubDomain
|
||||||
func (c AdminSetting) SubDomain() revel.Result {
|
func (c AdminSetting) SubDomain() revel.Result {
|
||||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
c.ViewArgs["str"] = configService.GlobalStringConfigs
|
||||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
|
|
||||||
c.RenderArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
|
c.ViewArgs["noteSubDomain"] = configService.GetGlobalStringConfig("noteSubDomain")
|
||||||
c.RenderArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
|
c.ViewArgs["blogSubDomain"] = configService.GetGlobalStringConfig("blogSubDomain")
|
||||||
c.RenderArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
|
c.ViewArgs["leaSubDomain"] = configService.GetGlobalStringConfig("leaSubDomain")
|
||||||
|
|
||||||
return c.RenderTemplate("admin/setting/subDomain.html")
|
return c.RenderTemplate("admin/setting/subDomain.html")
|
||||||
}
|
}
|
||||||
@@ -106,13 +106,13 @@ func (c AdminSetting) DoSubDomain(noteSubDomain, blogSubDomain, leaSubDomain, bl
|
|||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackSubDomains", strings.Split(blackSubDomains, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackSubDomains", strings.Split(blackSubDomains, ","))
|
||||||
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackCustomDomains", strings.Split(blackCustomDomains, ","))
|
re.Ok = configService.UpdateGlobalArrayConfig(c.GetUserId(), "blackCustomDomains", strings.Split(blackCustomDomains, ","))
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "openRegister", openRegister)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "openRegister", openRegister)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) HomePage(homePage string) revel.Result {
|
func (c AdminSetting) HomePage(homePage string) revel.Result {
|
||||||
@@ -121,7 +121,7 @@ func (c AdminSetting) HomePage(homePage string) revel.Result {
|
|||||||
homePage = ""
|
homePage = ""
|
||||||
}
|
}
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
|
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
|
||||||
@@ -129,7 +129,7 @@ func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Resu
|
|||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
|
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
|
||||||
@@ -138,5 +138,5 @@ func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLo
|
|||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -20,11 +20,11 @@ func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
|||||||
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
|
func (c AdminUpgrade) UpgradeBeta3ToBeta4() revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
|
re.Ok, re.Msg = upgradeService.Api(c.GetUserId())
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -18,14 +18,14 @@ var userPageSize = 10
|
|||||||
|
|
||||||
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
if userPageSize == 0 {
|
if pageSize == 0 {
|
||||||
pageSize = userPageSize
|
pageSize = userPageSize
|
||||||
}
|
}
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"})
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"})
|
||||||
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords)
|
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords)
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.ViewArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["users"] = users
|
c.ViewArgs["users"] = users
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.ViewArgs["keywords"] = keywords
|
||||||
return c.RenderTemplate("admin/user/list.html")
|
return c.RenderTemplate("admin/user/list.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func (c AdminUser) Register(email, pwd string) revel.Result {
|
|||||||
// 修改帐户
|
// 修改帐户
|
||||||
func (c AdminUser) ResetPwd(userId string) revel.Result {
|
func (c AdminUser) ResetPwd(userId string) revel.Result {
|
||||||
userInfo := userService.GetUserInfo(userId)
|
userInfo := userService.GetUserInfo(userId)
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
return c.RenderTemplate("admin/user/reset_pwd.html")
|
return c.RenderTemplate("admin/user/reset_pwd.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Msg = "NOTLOGIN"
|
re.Msg = "NOTLOGIN"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ func (c ApiAuth) Login(email, pwd string) revel.Result {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
token := bson.NewObjectId().Hex()
|
token := bson.NewObjectId().Hex()
|
||||||
sessionService.SetUserId(token, userInfo.UserId.Hex())
|
sessionService.SetUserId(token, userInfo.UserId.Hex())
|
||||||
return c.RenderJson(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
|
return c.RenderJSON(info.AuthOk{Ok: true, Token: token, UserId: userInfo.UserId, Email: userInfo.Email, Username: userInfo.Username})
|
||||||
} else {
|
} else {
|
||||||
// 登录错误, 则错误次数++
|
// 登录错误, 则错误次数++
|
||||||
msg = "wrongUsernameOrPassword"
|
msg = "wrongUsernameOrPassword"
|
||||||
}
|
}
|
||||||
return c.RenderJson(info.ApiRe{Ok: false, Msg: c.Message(msg)})
|
return c.RenderJSON(info.ApiRe{Ok: false, Msg: c.Message(msg)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注销
|
// 注销
|
||||||
@@ -43,7 +43,7 @@ func (c ApiAuth) Logout() revel.Result {
|
|||||||
sessionService.Clear(token)
|
sessionService.Clear(token)
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
@@ -53,17 +53,17 @@ func (c ApiAuth) Register(email, pwd string) revel.Result {
|
|||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
if !configService.IsOpenRegister() {
|
if !configService.IsOpenRegister() {
|
||||||
re.Msg = "notOpenRegister" // 未开放注册
|
re.Msg = "notOpenRegister" // 未开放注册
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
re.Ok, re.Msg = authService.Register(email, pwd, "")
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -142,10 +142,10 @@ func (c ApiBaseContrller) upload(name string, noteId string, isAttach bool) (ok
|
|||||||
// 生成新的文件名
|
// 生成新的文件名
|
||||||
filename := handel.Filename
|
filename := handel.Filename
|
||||||
_, ext := SplitFilename(filename)
|
_, ext := SplitFilename(filename)
|
||||||
if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
// if ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg" {
|
||||||
msg = "notImage"
|
// msg = "notImage"
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
filename = newGuid + ext
|
filename = newGuid + ext
|
||||||
data, err := ioutil.ReadAll(file)
|
data, err := ioutil.ReadAll(file)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func (c ApiFile) CopyImage(userId, fileId, toUserId string) revel.Result {
|
|||||||
|
|
||||||
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all images by userId with page
|
// get all images by userId with page
|
||||||
@@ -39,19 +39,19 @@ func (c ApiFile) GetImages(albumId, key string, page int) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Item = imagesPage
|
re.Item = imagesPage
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
|
func (c ApiFile) UpdateImageTitle(fileId, title string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
|
re.Ok = fileService.UpdateImageTitle(c.getUserId(), fileId, title)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ApiFile) DeleteImage(fileId string) revel.Result {
|
func (c ApiFile) DeleteImage(fileId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
|
re.Ok, re.Msg = fileService.DeleteImage(c.getUserId(), fileId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func (c ApiNote) GetSyncNotes(afterUsn, maxEntry int) revel.Result {
|
|||||||
maxEntry = 100
|
maxEntry = 100
|
||||||
}
|
}
|
||||||
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
|
notes := noteService.GetSyncNotes(c.getUserId(), afterUsn, maxEntry)
|
||||||
return c.RenderJson(notes)
|
return c.RenderJSON(notes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到笔记本下的笔记
|
// 得到笔记本下的笔记
|
||||||
@@ -61,17 +61,17 @@ func (c ApiNote) GetNotes(notebookId string) revel.Result {
|
|||||||
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
if notebookId != "" && !bson.IsObjectIdHex(notebookId) {
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Msg = "notebookIdInvalid"
|
re.Msg = "notebookIdInvalid"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.getUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false)
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
return c.RenderJSON(noteService.ToApiNotes(notes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到trash
|
// 得到trash
|
||||||
// [OK]
|
// [OK]
|
||||||
func (c ApiNote) GetTrashNotes() revel.Result {
|
func (c ApiNote) GetTrashNotes() revel.Result {
|
||||||
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
_, notes := noteService.ListNotes(c.getUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false)
|
||||||
return c.RenderJson(noteService.ToApiNotes(notes))
|
return c.RenderJSON(noteService.ToApiNotes(notes))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,17 +127,17 @@ func (c ApiNote) GetNote(noteId string) revel.Result {
|
|||||||
if !bson.IsObjectIdHex(noteId) {
|
if !bson.IsObjectIdHex(noteId) {
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Msg = "noteIdInvalid"
|
re.Msg = "noteIdInvalid"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
note := noteService.GetNote(noteId, c.getUserId())
|
note := noteService.GetNote(noteId, c.getUserId())
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Msg = "notExists"
|
re.Msg = "notExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
apiNotes := noteService.ToApiNotes([]info.Note{note})
|
apiNotes := noteService.ToApiNotes([]info.Note{note})
|
||||||
return c.RenderJson(apiNotes[0])
|
return c.RenderJSON(apiNotes[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到note和内容
|
// 得到note和内容
|
||||||
@@ -148,7 +148,7 @@ func (c ApiNote) GetNoteAndContent(noteId string) revel.Result {
|
|||||||
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
|
apiNotes := noteService.ToApiNotes([]info.Note{noteAndContent.Note})
|
||||||
apiNote := apiNotes[0]
|
apiNote := apiNotes[0]
|
||||||
apiNote.Content = noteService.FixContent(noteAndContent.Content, noteAndContent.IsMarkdown)
|
apiNote.Content = noteService.FixContent(noteAndContent.Content, noteAndContent.IsMarkdown)
|
||||||
return c.RenderJson(apiNote)
|
return c.RenderJSON(apiNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
// content里的image, attach链接是
|
// content里的image, attach链接是
|
||||||
@@ -166,18 +166,20 @@ func (c ApiNote) fixPostNotecontent(noteOrContent *info.ApiNote) {
|
|||||||
if file.LocalFileId != "" {
|
if file.LocalFileId != "" {
|
||||||
LogJ(file)
|
LogJ(file)
|
||||||
if !file.IsAttach {
|
if !file.IsAttach {
|
||||||
reg, _ := regexp.Compile(`"https*://[^/]*?/api/file/getImage\?fileId=`+file.LocalFileId)
|
// <img src="https://"
|
||||||
|
// 
|
||||||
|
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getImage\?fileId=`+file.LocalFileId)
|
||||||
// Log(reg)
|
// Log(reg)
|
||||||
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `"/api/file/getImage?fileId=`+file.FileId)
|
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getImage?fileId=`+file.FileId)
|
||||||
|
|
||||||
// // "http://a.com/api/file/getImage?fileId=localId" => /api/file/getImage?fileId=serverId
|
// // "http://a.com/api/file/getImage?fileId=localId" => /api/file/getImage?fileId=serverId
|
||||||
// noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
// noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
||||||
// baseUrl + "/api/file/getImage?fileId="+file.LocalFileId,
|
// baseUrl + "/api/file/getImage?fileId="+file.LocalFileId,
|
||||||
// "/api/file/getImage?fileId="+file.FileId, -1)
|
// "/api/file/getImage?fileId="+file.FileId, -1)
|
||||||
} else {
|
} else {
|
||||||
reg, _ := regexp.Compile(`"https*://[^/]*?/api/file/getAttach\?fileId=`+file.LocalFileId)
|
reg, _ := regexp.Compile(`https*://[^/]*?/api/file/getAttach\?fileId=`+file.LocalFileId)
|
||||||
Log(reg)
|
Log(reg)
|
||||||
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `"/api/file/getAttach?fileId=`+file.FileId)
|
noteOrContent.Content = reg.ReplaceAllString(noteOrContent.Content, `/api/file/getAttach?fileId=`+file.FileId)
|
||||||
/*
|
/*
|
||||||
noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
noteOrContent.Content = strings.Replace(noteOrContent.Content,
|
||||||
baseUrl + "/api/file/getAttach?fileId="+file.LocalFileId,
|
baseUrl + "/api/file/getAttach?fileId="+file.LocalFileId,
|
||||||
@@ -205,7 +207,7 @@ func (c ApiNote) GetNoteContent(noteId string) revel.Result {
|
|||||||
Content: noteContent.Content,
|
Content: noteContent.Content,
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.RenderJson(apiNoteContent)
|
return c.RenderJSON(apiNoteContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加笔记
|
// 添加笔记
|
||||||
@@ -231,10 +233,10 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
LogJ(file)
|
LogJ(file)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// return c.RenderJson(re)
|
// return c.RenderJSON(re)
|
||||||
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
if noteOrContent.NotebookId == "" || !bson.IsObjectIdHex(noteOrContent.NotebookId) {
|
||||||
re.Msg = "notebookIdNotExists"
|
re.Msg = "notebookIdNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
noteId := bson.NewObjectId()
|
noteId := bson.NewObjectId()
|
||||||
@@ -257,7 +259,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
}
|
}
|
||||||
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
|
// 报不是图片的错误没关系, 证明客户端传来非图片的数据
|
||||||
if msg != "notImage" {
|
if msg != "notImage" {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 建立映射
|
// 建立映射
|
||||||
@@ -269,7 +271,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,7 +282,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
// Log("Add")
|
// Log("Add")
|
||||||
// LogJ(noteOrContent)
|
// LogJ(noteOrContent)
|
||||||
|
|
||||||
// return c.RenderJson(re)
|
// return c.RenderJSON(re)
|
||||||
|
|
||||||
note := info.Note{UserId: userId,
|
note := info.Note{UserId: userId,
|
||||||
NoteId: noteId,
|
NoteId: noteId,
|
||||||
@@ -316,7 +318,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
|
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
re.Ok = false
|
re.Ok = false
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加需要返回的
|
// 添加需要返回的
|
||||||
@@ -330,7 +332,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
noteOrContent.Content = ""
|
noteOrContent.Content = ""
|
||||||
noteOrContent.Abstract = ""
|
noteOrContent.Abstract = ""
|
||||||
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
|
// apiNote := info.NoteToApiNote(note, noteOrContent.Files)
|
||||||
return c.RenderJson(noteOrContent)
|
return c.RenderJSON(noteOrContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新笔记
|
// 更新笔记
|
||||||
@@ -345,12 +347,12 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
|
|
||||||
if noteOrContent.NoteId == "" {
|
if noteOrContent.NoteId == "" {
|
||||||
re.Msg = "noteIdNotExists"
|
re.Msg = "noteIdNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if noteOrContent.Usn <= 0 {
|
if noteOrContent.Usn <= 0 {
|
||||||
re.Msg = "usnNotExists"
|
re.Msg = "usnNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log("_____________")
|
// Log("_____________")
|
||||||
@@ -366,12 +368,12 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
note := noteService.GetNote(noteId, userId)
|
note := noteService.GetNote(noteId, userId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
re.Msg = "notExists"
|
re.Msg = "notExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
if note.Usn != noteOrContent.Usn {
|
if note.Usn != noteOrContent.Usn {
|
||||||
re.Msg = "conflict"
|
re.Msg = "conflict"
|
||||||
Log("conflict")
|
Log("conflict")
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
Log("没有冲突")
|
Log("没有冲突")
|
||||||
|
|
||||||
@@ -400,14 +402,14 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
} else {
|
} else {
|
||||||
re.Msg = msg
|
re.Msg = msg
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
} else {
|
} else {
|
||||||
// 建立映射
|
// 建立映射
|
||||||
file.FileId = fileId
|
file.FileId = fileId
|
||||||
noteOrContent.Files[i] = file
|
noteOrContent.Files[i] = file
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -488,7 +490,7 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
if !noteOk {
|
if !noteOk {
|
||||||
re.Ok = false
|
re.Ok = false
|
||||||
re.Msg = noteMsg
|
re.Msg = noteMsg
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +528,7 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !re.Ok {
|
if !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
noteOrContent.Content = ""
|
noteOrContent.Content = ""
|
||||||
@@ -537,14 +539,14 @@ func (c ApiNote) UpdateNote(noteOrContent info.ApiNote) revel.Result {
|
|||||||
// LogJ(noteOrContent.Files)
|
// LogJ(noteOrContent.Files)
|
||||||
noteOrContent.UserId = c.getUserId()
|
noteOrContent.UserId = c.getUserId()
|
||||||
|
|
||||||
return c.RenderJson(noteOrContent)
|
return c.RenderJSON(noteOrContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除trash
|
// 删除trash
|
||||||
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
|
func (c ApiNote) DeleteTrash(noteId string, usn int) revel.Result {
|
||||||
re := info.NewReUpdate()
|
re := info.NewReUpdate()
|
||||||
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
|
re.Ok, re.Msg, re.Usn = trashService.DeleteTrashApi(noteId, c.getUserId(), usn)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到历史列表
|
// 得到历史列表
|
||||||
@@ -556,7 +558,7 @@ func (c ApiNote) GetHistories(noteId string) revel.Result {
|
|||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Item = histories
|
re.Item = histories
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -567,13 +569,13 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
|
|||||||
userId := c.getUserId()
|
userId := c.getUserId()
|
||||||
if noteId == "" {
|
if noteId == "" {
|
||||||
re.Msg = "noteNotExists"
|
re.Msg = "noteNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
note := noteService.GetNoteById(noteId)
|
note := noteService.GetNoteById(noteId)
|
||||||
if note.NoteId == "" {
|
if note.NoteId == "" {
|
||||||
re.Msg = "noteNotExists"
|
re.Msg = "noteNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
noteUserId := note.UserId.Hex()
|
noteUserId := note.UserId.Hex()
|
||||||
@@ -582,7 +584,7 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
|
|||||||
// 是否是有权限协作的
|
// 是否是有权限协作的
|
||||||
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
if !note.IsBlog && !shareService.HasReadPerm(noteUserId, userId, noteId) {
|
||||||
re.Msg = "noteNotExists"
|
re.Msg = "noteNotExists"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +594,7 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
|
|||||||
dir := revel.BasePath + "/" + fileUrlPath
|
dir := revel.BasePath + "/" + fileUrlPath
|
||||||
if !MkdirAll(dir) {
|
if !MkdirAll(dir) {
|
||||||
re.Msg = "noDir"
|
re.Msg = "noDir"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
filename := guid + ".pdf"
|
filename := guid + ".pdf"
|
||||||
path := dir + "/" + filename
|
path := dir + "/" + filename
|
||||||
@@ -621,12 +623,12 @@ func (c ApiNote) ExportPdf(noteId string) revel.Result {
|
|||||||
_, err := cmd.Output()
|
_, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
re.Msg = "sysError"
|
re.Msg = "sysError"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
re.Msg = "sysError"
|
re.Msg = "sysError"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
filenameReturn := note.Title
|
filenameReturn := note.Title
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
|
|||||||
maxEntry = 100
|
maxEntry = 100
|
||||||
}
|
}
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
|
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), afterUsn, maxEntry)
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
return c.RenderJSON(c.fixNotebooks(notebooks))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 得到用户的所有笔记本
|
// 得到用户的所有笔记本
|
||||||
@@ -61,7 +61,7 @@ func (c ApiNotebook) GetSyncNotebooks(afterUsn, maxEntry int) revel.Result {
|
|||||||
// info.SubNotebooks
|
// info.SubNotebooks
|
||||||
func (c ApiNotebook) GetNotebooks() revel.Result {
|
func (c ApiNotebook) GetNotebooks() revel.Result {
|
||||||
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
|
notebooks := notebookService.GeSyncNotebooks(c.getUserId(), 0, 99999)
|
||||||
return c.RenderJson(c.fixNotebooks(notebooks))
|
return c.RenderJSON(c.fixNotebooks(notebooks))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加notebook
|
// 添加notebook
|
||||||
@@ -77,9 +77,9 @@ func (c ApiNotebook) AddNotebook(title, parentNotebookId string, seq int) revel.
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, notebook = notebookService.AddNotebook(notebook)
|
re.Ok, notebook = notebookService.AddNotebook(notebook)
|
||||||
if !re.Ok {
|
if !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
return c.RenderJSON(c.fixNotebook(¬ebook))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记
|
// 修改笔记
|
||||||
@@ -91,10 +91,10 @@ func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string,
|
|||||||
if !ok {
|
if !ok {
|
||||||
re.Ok = false
|
re.Ok = false
|
||||||
re.Msg = msg
|
re.Msg = msg
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
LogJ(notebook)
|
LogJ(notebook)
|
||||||
return c.RenderJson(c.fixNotebook(¬ebook))
|
return c.RenderJSON(c.fixNotebook(¬ebook))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除笔记本
|
// 删除笔记本
|
||||||
@@ -102,5 +102,5 @@ func (c ApiNotebook) UpdateNotebook(notebookId, title, parentNotebookId string,
|
|||||||
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
|
func (c ApiNotebook) DeleteNotebook(notebookId string, usn int) revel.Result {
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
|
re.Ok, re.Msg = notebookService.DeleteNotebookForce(c.getUserId(), notebookId, usn)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
|
|||||||
maxEntry = 100
|
maxEntry = 100
|
||||||
}
|
}
|
||||||
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
|
tags := tagService.GeSyncTags(c.getUserId(), afterUsn, maxEntry)
|
||||||
return c.RenderJson(tags)
|
return c.RenderJSON(tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加Tag
|
// 添加Tag
|
||||||
@@ -44,7 +44,7 @@ func (c ApiTag) GetSyncTags(afterUsn, maxEntry int) revel.Result {
|
|||||||
*/
|
*/
|
||||||
func (c ApiTag) AddTag(tag string) revel.Result {
|
func (c ApiTag) AddTag(tag string) revel.Result {
|
||||||
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
|
ret := tagService.AddOrUpdateTag(c.getUserId(), tag)
|
||||||
return c.RenderJson(ret)
|
return c.RenderJSON(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除标签
|
// 删除标签
|
||||||
@@ -52,5 +52,5 @@ func (c ApiTag) AddTag(tag string) revel.Result {
|
|||||||
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
|
func (c ApiTag) DeleteTag(tag string, usn int) revel.Result {
|
||||||
re := info.NewReUpdate()
|
re := info.NewReUpdate()
|
||||||
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
|
re.Ok, re.Msg, re.Usn = tagService.DeleteTagApi(c.getUserId(), tag, usn)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func (c ApiUser) Info() revel.Result {
|
|||||||
|
|
||||||
userInfo := c.getUserInfo()
|
userInfo := c.getUserInfo()
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
apiUser := info.ApiUser{
|
apiUser := info.ApiUser{
|
||||||
UserId: userInfo.UserId.Hex(),
|
UserId: userInfo.UserId.Hex(),
|
||||||
@@ -37,7 +37,7 @@ func (c ApiUser) Info() revel.Result {
|
|||||||
Logo: userInfo.Logo,
|
Logo: userInfo.Logo,
|
||||||
Verified: userInfo.Verified,
|
Verified: userInfo.Verified,
|
||||||
}
|
}
|
||||||
return c.RenderJson(apiUser)
|
return c.RenderJSON(apiUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改用户名
|
// 修改用户名
|
||||||
@@ -46,15 +46,15 @@ func (c ApiUser) UpdateUsername(username string) revel.Result {
|
|||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
if c.GetUsername() == "demo" {
|
if c.GetUsername() == "demo" {
|
||||||
re.Msg = "cannotUpdateDemo"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
if re.Ok, re.Msg = Vd("username", username); !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
|
re.Ok, re.Msg = userService.UpdateUsername(c.getUserId(), username)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改密码
|
// 修改密码
|
||||||
@@ -63,23 +63,23 @@ func (c ApiUser) UpdatePwd(oldPwd, pwd string) revel.Result {
|
|||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
if c.GetUsername() == "demo" {
|
if c.GetUsername() == "demo" {
|
||||||
re.Msg = "cannotUpdateDemo"
|
re.Msg = "cannotUpdateDemo"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
if re.Ok, re.Msg = Vd("password", oldPwd); !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
|
re.Ok, re.Msg = userService.UpdatePwd(c.getUserId(), oldPwd, pwd)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得同步状态
|
// 获得同步状态
|
||||||
// [OK]
|
// [OK]
|
||||||
func (c ApiUser) GetSyncState() revel.Result {
|
func (c ApiUser) GetSyncState() revel.Result {
|
||||||
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
|
ret := bson.M{"LastSyncUsn": userService.GetUsn(c.getUserId()), "LastSyncTime": time.Now().Unix()}
|
||||||
return c.RenderJson(ret)
|
return c.RenderJSON(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 头像设置
|
// 头像设置
|
||||||
@@ -91,11 +91,11 @@ func (c ApiUser) UpdateLogo() revel.Result {
|
|||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
ok = userService.UpdateAvatar(c.getUserId(), url)
|
ok = userService.UpdateAvatar(c.getUserId(), url)
|
||||||
return c.RenderJson(map[string]string{"Logo": url})
|
return c.RenderJSON(map[string]string{"Logo": url})
|
||||||
} else {
|
} else {
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Msg = msg
|
re.Msg = msg
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
noToken := false
|
noToken := false
|
||||||
if token == "" {
|
if token == "" {
|
||||||
// 若无, 则取sessionId
|
// 若无, 则取sessionId
|
||||||
token = c.Session.Id()
|
token = c.Session.ID()
|
||||||
noToken = true
|
noToken = true
|
||||||
}
|
}
|
||||||
c.Session["_token"] = token
|
c.Session["_token"] = token
|
||||||
@@ -106,7 +106,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
// 没有登录, 返回错误的信息, 需要登录
|
// 没有登录, 返回错误的信息, 需要登录
|
||||||
re := info.NewApiRe()
|
re := info.NewApiRe()
|
||||||
re.Msg = "NOTLOGIN"
|
re.Msg = "NOTLOGIN"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Msg = "NOTLOGIN"
|
re.Msg = "NOTLOGIN"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter
|
|||||||
} else {
|
} else {
|
||||||
isAsc = false
|
isAsc = false
|
||||||
}
|
}
|
||||||
c.RenderArgs["sorter"] = sorter
|
c.ViewArgs["sorter"] = sorter
|
||||||
return sorterField, isAsc
|
return sorterField, isAsc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ type MemberBlog struct {
|
|||||||
func (c MemberBlog) common() info.UserBlog {
|
func (c MemberBlog) common() info.UserBlog {
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
userInfo := userService.GetUserInfo(userId)
|
userInfo := userService.GetUserInfo(userId)
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
// 得到博客设置信息
|
// 得到博客设置信息
|
||||||
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
c.ViewArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
||||||
|
|
||||||
userBlog := blogService.GetUserBlog(userId)
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
c.RenderArgs["userBlog"] = userBlog
|
c.ViewArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
@@ -62,7 +62,7 @@ func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string)
|
|||||||
} else {
|
} else {
|
||||||
isAsc = false
|
isAsc = false
|
||||||
}
|
}
|
||||||
c.RenderArgs["sorter"] = sorter
|
c.ViewArgs["sorter"] = sorter
|
||||||
return sorterField, isAsc
|
return sorterField, isAsc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,18 +72,18 @@ var userPageSize = 15
|
|||||||
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
userInfo := userService.GetUserInfo(userId)
|
userInfo := userService.GetUserInfo(userId)
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.ViewArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
c.RenderArgs["title"] = c.Message("Posts")
|
c.ViewArgs["title"] = c.Message("Posts")
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"})
|
||||||
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc)
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.ViewArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["blogs"] = blogs
|
c.ViewArgs["blogs"] = blogs
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.ViewArgs["keywords"] = keywords
|
||||||
|
|
||||||
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
|
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
|
||||||
c.RenderArgs["userAndBlog"] = userAndBlog
|
c.ViewArgs["userAndBlog"] = userAndBlog
|
||||||
|
|
||||||
c.common()
|
c.common()
|
||||||
|
|
||||||
@@ -94,48 +94,48 @@ func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
|||||||
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
|
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
|
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记的urlTitle
|
// 修改笔记的urlTitle
|
||||||
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Update Post Abstract")
|
c.ViewArgs["title"] = c.Message("Update Post Abstract")
|
||||||
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
|
note := noteService.GetNoteAndContent(noteId, c.GetUserId())
|
||||||
if !note.Note.IsBlog {
|
if !note.Note.IsBlog {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
c.RenderArgs["note"] = note
|
c.ViewArgs["note"] = note
|
||||||
c.RenderArgs["noteId"] = noteId
|
c.ViewArgs["noteId"] = noteId
|
||||||
return c.RenderTemplate("member/blog/update_abstract.html")
|
return c.RenderTemplate("member/blog/update_abstract.html")
|
||||||
}
|
}
|
||||||
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
|
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
|
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基本信息设置
|
// 基本信息设置
|
||||||
func (c MemberBlog) Base() revel.Result {
|
func (c MemberBlog) Base() revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Blog Base Info")
|
c.ViewArgs["title"] = c.Message("Blog Base Info")
|
||||||
return c.RenderTemplate("member/blog/base.html")
|
return c.RenderTemplate("member/blog/base.html")
|
||||||
}
|
}
|
||||||
func (c MemberBlog) Comment() revel.Result {
|
func (c MemberBlog) Comment() revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Comment")
|
c.ViewArgs["title"] = c.Message("Comment")
|
||||||
return c.RenderTemplate("member/blog/comment.html")
|
return c.RenderTemplate("member/blog/comment.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) Paging() revel.Result {
|
func (c MemberBlog) Paging() revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Paging")
|
c.ViewArgs["title"] = c.Message("Paging")
|
||||||
return c.RenderTemplate("member/blog/paging.html")
|
return c.RenderTemplate("member/blog/paging.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) Cate() revel.Result {
|
func (c MemberBlog) Cate() revel.Result {
|
||||||
userBlog := c.common()
|
userBlog := c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Category")
|
c.ViewArgs["title"] = c.Message("Category")
|
||||||
|
|
||||||
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
||||||
notebooksMap := map[string]info.Notebook{}
|
notebooksMap := map[string]info.Notebook{}
|
||||||
@@ -166,7 +166,7 @@ func (c MemberBlog) Cate() revel.Result {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.RenderArgs["notebooks"] = notebooks2
|
c.ViewArgs["notebooks"] = notebooks2
|
||||||
|
|
||||||
return c.RenderTemplate("member/blog/cate.html")
|
return c.RenderTemplate("member/blog/cate.html")
|
||||||
}
|
}
|
||||||
@@ -175,54 +175,54 @@ func (c MemberBlog) Cate() revel.Result {
|
|||||||
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
|
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
|
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
|
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
|
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存之, 包含增加与保存
|
// 保存之, 包含增加与保存
|
||||||
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
|
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
|
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Add Single")
|
c.ViewArgs["title"] = c.Message("Add Single")
|
||||||
c.RenderArgs["singleId"] = singleId
|
c.ViewArgs["singleId"] = singleId
|
||||||
if singleId != "" {
|
if singleId != "" {
|
||||||
c.RenderArgs["title"] = c.Message("Update Single")
|
c.ViewArgs["title"] = c.Message("Update Single")
|
||||||
c.RenderArgs["single"] = blogService.GetSingle(singleId)
|
c.ViewArgs["single"] = blogService.GetSingle(singleId)
|
||||||
}
|
}
|
||||||
return c.RenderTemplate("member/blog/add_single.html")
|
return c.RenderTemplate("member/blog/add_single.html")
|
||||||
}
|
}
|
||||||
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
|
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
|
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
|
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
|
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改页面标题
|
// 修改页面标题
|
||||||
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
|
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
|
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) Single() revel.Result {
|
func (c MemberBlog) Single() revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Single")
|
c.ViewArgs["title"] = c.Message("Single")
|
||||||
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
c.ViewArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
||||||
|
|
||||||
return c.RenderTemplate("member/blog/single.html")
|
return c.RenderTemplate("member/blog/single.html")
|
||||||
}
|
}
|
||||||
@@ -231,12 +231,12 @@ func (c MemberBlog) Single() revel.Result {
|
|||||||
func (c MemberBlog) Theme() revel.Result {
|
func (c MemberBlog) Theme() revel.Result {
|
||||||
c.common()
|
c.common()
|
||||||
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
|
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
|
||||||
c.RenderArgs["activeTheme"] = activeTheme
|
c.ViewArgs["activeTheme"] = activeTheme
|
||||||
c.RenderArgs["otherThemes"] = otherThemes
|
c.ViewArgs["otherThemes"] = otherThemes
|
||||||
|
|
||||||
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
|
c.ViewArgs["optionThemes"] = themeService.GetDefaultThemes()
|
||||||
|
|
||||||
c.RenderArgs["title"] = c.Message("Theme")
|
c.ViewArgs["title"] = c.Message("Theme")
|
||||||
return c.RenderTemplate("member/blog/theme.html")
|
return c.RenderTemplate("member/blog/theme.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,11 +253,11 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.common()
|
c.common()
|
||||||
c.RenderArgs["title"] = c.Message("Update Theme")
|
c.ViewArgs["title"] = c.Message("Update Theme")
|
||||||
c.RenderArgs["isNew"] = isNew
|
c.ViewArgs["isNew"] = isNew
|
||||||
|
|
||||||
// 先复制之
|
// 先复制之
|
||||||
c.RenderArgs["themeId"] = themeId
|
c.ViewArgs["themeId"] = themeId
|
||||||
|
|
||||||
// 得到脚本目录
|
// 得到脚本目录
|
||||||
userId := c.GetUserId()
|
userId := c.GetUserId()
|
||||||
@@ -266,7 +266,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
|||||||
if theme.ThemeId == "" {
|
if theme.ThemeId == "" {
|
||||||
return c.E404()
|
return c.E404()
|
||||||
}
|
}
|
||||||
c.RenderArgs["theme"] = theme
|
c.ViewArgs["theme"] = theme
|
||||||
|
|
||||||
path := revel.BasePath + "/" + theme.Path
|
path := revel.BasePath + "/" + theme.Path
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RenderArgs["myTpls"] = myTpls
|
c.ViewArgs["myTpls"] = myTpls
|
||||||
|
|
||||||
return c.RenderTemplate("member/blog/update_theme.html")
|
return c.RenderTemplate("member/blog/update_theme.html")
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result
|
|||||||
re.Ok = true
|
re.Ok = true
|
||||||
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
|
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
|
||||||
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
|
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
@@ -309,7 +309,7 @@ func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Re
|
|||||||
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
|
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
|
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
||||||
@@ -320,22 +320,22 @@ func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
|||||||
images := ListDir(path)
|
images := ListDir(path)
|
||||||
re.List = images
|
re.List = images
|
||||||
re.Ok = true
|
re.Ok = true
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
|
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
|
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
|
||||||
re.Ok = DeleteFile(path)
|
re.Ok = DeleteFile(path)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传主题图片
|
// 上传主题图片
|
||||||
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
|
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
|
||||||
re := c.uploadImage(themeId)
|
re := c.uploadImage(themeId)
|
||||||
c.RenderArgs["fileUrlPath"] = re.Id
|
c.ViewArgs["fileUrlPath"] = re.Id
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.ViewArgs["resultCode"] = re.Code
|
||||||
c.RenderArgs["resultMsg"] = re.Msg
|
c.ViewArgs["resultMsg"] = re.Msg
|
||||||
return c.RenderTemplate("file/blog_logo.html")
|
return c.RenderTemplate("file/blog_logo.html")
|
||||||
}
|
}
|
||||||
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
||||||
@@ -405,21 +405,21 @@ func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
|||||||
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
|
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
|
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除主题
|
// 删除主题
|
||||||
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
|
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
|
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理员公开主题
|
// 管理员公开主题
|
||||||
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
|
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
|
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出
|
// 导出
|
||||||
@@ -444,7 +444,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
file, handel, err := c.Request.FormFile("file")
|
file, handel, err := c.Request.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
re.Msg = fmt.Sprintf("%v", err)
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
@@ -454,7 +454,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
err = os.MkdirAll(dir, 0755)
|
err = os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
re.Msg = fmt.Sprintf("%v", err)
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
// 生成新的文件名
|
// 生成新的文件名
|
||||||
filename := handel.Filename
|
filename := handel.Filename
|
||||||
@@ -463,26 +463,26 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
_, ext = SplitFilename(filename)
|
_, ext = SplitFilename(filename)
|
||||||
if ext != ".zip" {
|
if ext != ".zip" {
|
||||||
re.Msg = "Please upload zip file"
|
re.Msg = "Please upload zip file"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = filename
|
filename = filename
|
||||||
data, err := ioutil.ReadAll(file)
|
data, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// > 10M?
|
// > 10M?
|
||||||
if len(data) > 10*1024*1024 {
|
if len(data) > 10*1024*1024 {
|
||||||
re.Msg = "File is big than 10M"
|
re.Msg = "File is big than 10M"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
toPath := dir + "/" + filename
|
toPath := dir + "/" + filename
|
||||||
err = ioutil.WriteFile(toPath, data, 0777)
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
re.Msg = fmt.Sprintf("%v", err)
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传好后, 增加之
|
// 上传好后, 增加之
|
||||||
@@ -494,7 +494,7 @@ func (c MemberBlog) ImportTheme() revel.Result {
|
|||||||
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
|
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
|
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新建主题
|
// 新建主题
|
||||||
@@ -508,17 +508,17 @@ func (c MemberBlog) NewTheme() revel.Result {
|
|||||||
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
|
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ type MemberGroup struct {
|
|||||||
func (c MemberGroup) Index() revel.Result {
|
func (c MemberGroup) Index() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("My Group")
|
c.ViewArgs["title"] = c.Message("My Group")
|
||||||
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
|
c.ViewArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
|
||||||
return c.RenderTemplate("member/group/index.html")
|
return c.RenderTemplate("member/group/index.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,13 +23,13 @@ func (c MemberGroup) Index() revel.Result {
|
|||||||
func (c MemberGroup) AddGroup(title string) revel.Result {
|
func (c MemberGroup) AddGroup(title string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
|
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
|
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
|
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
|
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ type MemberIndex struct {
|
|||||||
// admin 主页
|
// admin 主页
|
||||||
func (c MemberIndex) Index() revel.Result {
|
func (c MemberIndex) Index() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.RenderArgs["title"] = c.Message("Leanote Member Center")
|
c.ViewArgs["title"] = c.Message("Leanote Member Center")
|
||||||
|
|
||||||
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
c.ViewArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
||||||
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
c.ViewArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
||||||
|
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ func (c MemberIndex) Index() revel.Result {
|
|||||||
|
|
||||||
// 模板
|
// 模板
|
||||||
func (c MemberIndex) T(t string) revel.Result {
|
func (c MemberIndex) T(t string) revel.Result {
|
||||||
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
c.ViewArgs["str"] = configService.GlobalStringConfigs
|
||||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
c.ViewArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
c.ViewArgs["map"] = configService.GlobalMapConfigs
|
||||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
c.ViewArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||||
return c.RenderTemplate("admin/" + t + ".html")
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,28 +13,28 @@ type MemberUser struct {
|
|||||||
func (c MemberUser) Username() revel.Result {
|
func (c MemberUser) Username() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("Username")
|
c.ViewArgs["title"] = c.Message("Username")
|
||||||
return c.RenderTemplate("member/user/username.html")
|
return c.RenderTemplate("member/user/username.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberUser) Email() revel.Result {
|
func (c MemberUser) Email() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("Email")
|
c.ViewArgs["title"] = c.Message("Email")
|
||||||
return c.RenderTemplate("member/user/email.html")
|
return c.RenderTemplate("member/user/email.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberUser) Password() revel.Result {
|
func (c MemberUser) Password() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("Password")
|
c.ViewArgs["title"] = c.Message("Password")
|
||||||
return c.RenderTemplate("member/user/password.html")
|
return c.RenderTemplate("member/user/password.html")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MemberUser) Avatar() revel.Result {
|
func (c MemberUser) Avatar() revel.Result {
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
c.RenderArgs["title"] = c.Message("Avatar")
|
c.ViewArgs["title"] = c.Message("Avatar")
|
||||||
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
c.ViewArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
return c.RenderTemplate("member/user/avatar.html")
|
return c.RenderTemplate("member/user/avatar.html")
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Msg = "NOTLOGIN"
|
re.Msg = "NOTLOGIN"
|
||||||
return c.RenderJson(re)
|
return c.RenderJSON(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type Note struct {
|
|||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
Desc string `Desc` // 描述, 非html
|
Desc string `Desc` // 描述, 非html
|
||||||
|
|
||||||
|
Src string `Src,omitempty` // 来源, 2016/4/22
|
||||||
|
|
||||||
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
||||||
Tags []string `Tags,omitempty`
|
Tags []string `Tags,omitempty`
|
||||||
|
|
||||||
@@ -92,6 +94,7 @@ type NoteOrContent struct {
|
|||||||
UserId string
|
UserId string
|
||||||
Title string
|
Title string
|
||||||
Desc string
|
Desc string
|
||||||
|
Src string
|
||||||
ImgSrc string
|
ImgSrc string
|
||||||
Tags string
|
Tags string
|
||||||
Content string
|
Content string
|
||||||
@@ -101,3 +104,9 @@ type NoteOrContent struct {
|
|||||||
FromUserId string // 为共享而新建
|
FromUserId string // 为共享而新建
|
||||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分开的
|
||||||
|
type NoteAndContentSep struct {
|
||||||
|
NoteInfo Note
|
||||||
|
NoteContentInfo NoteContent
|
||||||
|
}
|
||||||
+7
-7
@@ -129,7 +129,7 @@ func init() {
|
|||||||
if tags == nil || len(tags) == 0 {
|
if tags == nil || len(tags) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
|
||||||
tagStr := ""
|
tagStr := ""
|
||||||
lenTags := len(tags)
|
lenTags := len(tags)
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
classes += " label-post"
|
classes += " label-post"
|
||||||
var url = tagPostUrl + "/" + url.QueryEscape(tag)
|
var url = tagPostUrl + "/" + tag
|
||||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
||||||
if i != lenTags-1 {
|
if i != lenTags-1 {
|
||||||
tagStr += " "
|
tagStr += " "
|
||||||
@@ -183,7 +183,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
revel.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
|
revel.TemplateFuncs["msg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.HTML {
|
||||||
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
str, ok := renderArgs[revel.CurrentLocaleViewArg].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ func init() {
|
|||||||
|
|
||||||
// 不用revel的msg
|
// 不用revel的msg
|
||||||
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
|
revel.TemplateFuncs["leaMsg"] = func(renderArgs map[string]interface{}, key string) template.HTML {
|
||||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
|
||||||
str := i18n.Message(locale, key)
|
str := i18n.Message(locale, key)
|
||||||
if strings.HasPrefix(str, "???") {
|
if strings.HasPrefix(str, "???") {
|
||||||
str = key
|
str = key
|
||||||
@@ -205,7 +205,7 @@ func init() {
|
|||||||
if tags == nil || len(tags) == 0 {
|
if tags == nil || len(tags) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
locale, _ := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
locale, _ := renderArgs[revel.CurrentLocaleViewArg].(string)
|
||||||
tagStr := ""
|
tagStr := ""
|
||||||
lenTags := len(tags)
|
lenTags := len(tags)
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ func init() {
|
|||||||
classes += " label-default"
|
classes += " label-default"
|
||||||
}
|
}
|
||||||
classes += " label-post"
|
classes += " label-post"
|
||||||
var url = tagPostUrl + url.QueryEscape(tag)
|
var url = tagPostUrl + tag
|
||||||
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
tagStr += "<a class=\"" + classes + "\" href=\"" + url + "\">" + str + "</a>"
|
||||||
if i != lenTags-1 {
|
if i != lenTags-1 {
|
||||||
tagStr += " "
|
tagStr += " "
|
||||||
@@ -307,7 +307,7 @@ func init() {
|
|||||||
|
|
||||||
// http://stackoverflow.com/questions/14226416/go-lang-templates-always-quotes-a-string-and-removes-comments
|
// http://stackoverflow.com/questions/14226416/go-lang-templates-always-quotes-a-string-and-removes-comments
|
||||||
revel.TemplateFuncs["rawMsg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.JS {
|
revel.TemplateFuncs["rawMsg"] = func(renderArgs map[string]interface{}, message string, args ...interface{}) template.JS {
|
||||||
str, ok := renderArgs[revel.CurrentLocaleRenderArg].(string)
|
str, ok := renderArgs[revel.CurrentLocaleViewArg].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -39,7 +39,7 @@ var CloneTemplate *template.Template
|
|||||||
type RenderTemplateResult struct {
|
type RenderTemplateResult struct {
|
||||||
Template *template.Template
|
Template *template.Template
|
||||||
PathContent map[string]string
|
PathContent map[string]string
|
||||||
RenderArgs map[string]interface{}
|
ViewArgs map[string]interface{}
|
||||||
|
|
||||||
IsPreview bool // 是否是预览
|
IsPreview bool // 是否是预览
|
||||||
CurBlogTpl *BlogTpl
|
CurBlogTpl *BlogTpl
|
||||||
@@ -62,7 +62,7 @@ func parseTemplateError(err error) (templateName string, line int, description s
|
|||||||
return templateName, line, description
|
return templateName, line, description
|
||||||
}
|
}
|
||||||
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
|
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
|
||||||
err := r.Template.Execute(wr, r.RenderArgs)
|
err := r.Template.Execute(wr, r.ViewArgs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response,
|
|||||||
// 这里, 错误!!
|
// 这里, 错误!!
|
||||||
// 这里应该导向到本主题的错误页面
|
// 这里应该导向到本主题的错误页面
|
||||||
resp.Status = 500
|
resp.Status = 500
|
||||||
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
|
ErrorResult{r.ViewArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
@@ -162,7 +162,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
r = &RenderTemplateResult{
|
r = &RenderTemplateResult{
|
||||||
Template: t,
|
Template: t,
|
||||||
PathContent: BlogTplObject.PathContent, // 为了显示错误
|
PathContent: BlogTplObject.PathContent, // 为了显示错误
|
||||||
RenderArgs: args, // 把args给它
|
ViewArgs: args, // 把args给它
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 复制一份
|
// 复制一份
|
||||||
@@ -202,7 +202,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
r = &RenderTemplateResult{
|
r = &RenderTemplateResult{
|
||||||
Template: t,
|
Template: t,
|
||||||
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
||||||
RenderArgs: args,
|
ViewArgs: args,
|
||||||
CurBlogTpl: newBlogTplObject,
|
CurBlogTpl: newBlogTplObject,
|
||||||
IsPreview: isPreview,
|
IsPreview: isPreview,
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ func RenderTemplate(name string, args map[string]interface{}, basePath string, i
|
|||||||
//
|
//
|
||||||
|
|
||||||
type ErrorResult struct {
|
type ErrorResult struct {
|
||||||
RenderArgs map[string]interface{}
|
ViewArgs map[string]interface{}
|
||||||
Error error
|
Error error
|
||||||
IsPreview bool
|
IsPreview bool
|
||||||
CurBlogTpl *BlogTpl
|
CurBlogTpl *BlogTpl
|
||||||
@@ -280,18 +280,18 @@ func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
|||||||
panic("no error provided")
|
panic("no error provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.RenderArgs == nil {
|
if r.ViewArgs == nil {
|
||||||
r.RenderArgs = make(map[string]interface{})
|
r.ViewArgs = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
r.RenderArgs["Error"] = revelError
|
r.ViewArgs["Error"] = revelError
|
||||||
r.RenderArgs["Router"] = revel.MainRouter
|
r.ViewArgs["Router"] = revel.MainRouter
|
||||||
|
|
||||||
// 不是preview就不要显示错误了
|
// 不是preview就不要显示错误了
|
||||||
if r.IsPreview {
|
if r.IsPreview {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
out := io.Writer(resp.Out)
|
out := io.Writer(resp.Out)
|
||||||
// out = ioutil.Discard
|
// out = ioutil.Discard
|
||||||
err = tmpl.Execute(&b, r.RenderArgs)
|
err = tmpl.Execute(&b, r.ViewArgs)
|
||||||
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
b.WriteTo(out)
|
b.WriteTo(out)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CurrentLocaleRenderArg = "currentLocale" // The key for the current locale render arg value
|
CurrentLocaleViewArg = "currentLocale" // The key for the current locale render arg value
|
||||||
|
|
||||||
messageFilesDirectory = "messages"
|
messageFilesDirectory = "messages"
|
||||||
messageFilePattern = `^\w+\.conf$`
|
messageFilePattern = `^\w+\.conf$`
|
||||||
@@ -193,7 +193,7 @@ func I18nFilter(c *revel.Controller, fc []revel.Filter) {
|
|||||||
// Set the current locale controller argument (CurrentLocaleControllerArg) with the given locale.
|
// Set the current locale controller argument (CurrentLocaleControllerArg) with the given locale.
|
||||||
func setCurrentLocaleControllerArguments(c *revel.Controller, locale string) {
|
func setCurrentLocaleControllerArguments(c *revel.Controller, locale string) {
|
||||||
c.Request.Locale = locale
|
c.Request.Locale = locale
|
||||||
c.RenderArgs[CurrentLocaleRenderArg] = locale
|
c.ViewArgs[CurrentLocaleViewArg] = locale
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine whether the given request has valid Accept-Language value.
|
// Determine whether the given request has valid Accept-Language value.
|
||||||
|
|||||||
@@ -673,19 +673,18 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
|
|||||||
|
|
||||||
noteIdO := bson.ObjectIdHex(noteId)
|
noteIdO := bson.ObjectIdHex(noteId)
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
var n int
|
|
||||||
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
|
if !db.Has(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO}) {
|
||||||
n = 1
|
|
||||||
// 添加之
|
// 添加之
|
||||||
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
|
db.Insert(db.BlogLikes, info.BlogLike{LikeId: bson.NewObjectId(), NoteId: noteIdO, UserId: userIdO, CreatedTime: time.Now()})
|
||||||
isLike = true
|
isLike = true
|
||||||
} else {
|
} else {
|
||||||
// 已点过, 那么删除之
|
// 已点过, 那么删除之
|
||||||
n = -1
|
|
||||||
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
|
db.Delete(db.BlogLikes, bson.M{"NoteId": noteIdO, "UserId": userIdO})
|
||||||
isLike = false
|
isLike = false
|
||||||
}
|
}
|
||||||
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
|
|
||||||
|
count := db.Count(db.BlogLikes, bson.M{"NoteId": noteIdO})
|
||||||
|
ok = db.UpdateByQI(db.Notes, bson.M{"_id": noteIdO}, bson.M{"LikeNum": count})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -606,5 +606,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ConfigService) GetVersion() string {
|
func (this *ConfigService) GetVersion() string {
|
||||||
return "2.2"
|
return "2.5"
|
||||||
}
|
}
|
||||||
@@ -62,6 +62,35 @@ func (this *NoteService) GetNoteAndContent(noteId, userId string) (noteAndConten
|
|||||||
return info.NoteAndContent{note, noteContent}
|
return info.NoteAndContent{note, noteContent}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *NoteService) GetNoteBySrc(src, userId string) (note info.Note) {
|
||||||
|
note = info.Note{}
|
||||||
|
if src == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
notes := []info.Note{}
|
||||||
|
q := db.Notes.Find(bson.M{
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"Src": src,
|
||||||
|
})
|
||||||
|
q.Sort("-Usn").Limit(1).All(¬es)
|
||||||
|
if len(notes) > 0 {
|
||||||
|
return notes[0]
|
||||||
|
}
|
||||||
|
// db.GetByQ(db.Notes, bson.M{"Src": src, "UserId": bson.ObjectIdHex(userId), "IsDeleted": false}, ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NoteService) GetNoteAndContentBySrc(src, userId string) (noteId string, noteAndContent info.NoteAndContentSep) {
|
||||||
|
note := this.GetNoteBySrc(src, userId)
|
||||||
|
if (note.NoteId != "") {
|
||||||
|
noteId = note.NoteId.Hex()
|
||||||
|
noteContent := this.GetNoteContent(note.NoteId.Hex(), userId)
|
||||||
|
return noteId, info.NoteAndContentSep{note, noteContent}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 获取同步的笔记
|
// 获取同步的笔记
|
||||||
// > afterUsn的笔记
|
// > afterUsn的笔记
|
||||||
func (this *NoteService) GetSyncNotes(userId string, afterUsn, maxEntry int) []info.ApiNote {
|
func (this *NoteService) GetSyncNotes(userId string, afterUsn, maxEntry int) []info.ApiNote {
|
||||||
@@ -863,7 +892,13 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
|||||||
notes2 := this.ListNotesByNoteIds(noteIds2)
|
notes2 := this.ListNotesByNoteIds(noteIds2)
|
||||||
|
|
||||||
// 合并之
|
// 合并之
|
||||||
notes = append(notes, notes2...)
|
// 不能是删除的
|
||||||
|
for _, n := range notes2 {
|
||||||
|
if !n.IsDeleted && !n.IsTrash {
|
||||||
|
// notes = append(notes, notes2...)
|
||||||
|
notes = append(notes, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
return notes
|
return notes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -61,6 +61,14 @@ func (this *TagService) AddOrUpdateTag(userId string, tag string) info.NoteTag {
|
|||||||
noteTag.Count = count
|
noteTag.Count = count
|
||||||
noteTag.UpdatedTime = time.Now()
|
noteTag.UpdatedTime = time.Now()
|
||||||
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
|
// noteTag.Usn = userService.IncrUsn(userId), 更新count而已
|
||||||
|
|
||||||
|
// 之前删除过的, 现在要添加回来了
|
||||||
|
if noteTag.IsDeleted {
|
||||||
|
Log("之前删除过的, 现在要添加回来了: " + tag)
|
||||||
|
noteTag.Usn = userService.IncrUsn(userId)
|
||||||
|
noteTag.IsDeleted = false
|
||||||
|
}
|
||||||
|
|
||||||
db.UpdateByIdAndUserId(db.NoteTags, noteTag.TagId.Hex(), userId, noteTag)
|
db.UpdateByIdAndUserId(db.NoteTags, noteTag.TagId.Hex(), userId, noteTag)
|
||||||
return noteTag
|
return noteTag
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-8">
|
||||||
<form id="add_user_form">
|
<form id="add_user_form">
|
||||||
<section class="panel panel-default">
|
<section class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Wkhtmltopdf Binary Path</label>
|
<label>Wkhtmltopdf Binary Path</label>
|
||||||
<input type="text" class="form-control" placeholder="/usr/local/bin/wkhtmltopdf" name="path" value="{{.str.exportPdfBinPath}}">
|
<input type="text" class="form-control" placeholder="/usr/local/bin/wkhtmltopdf or C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe" name="path" value="{{.str.exportPdfBinPath}}">
|
||||||
Leanote use <a target="_blank" href="http://wkhtmltopdf.org">wkhtmltopdf</a> to export pdf. You should install it on your server.
|
Leanote use <a target="_blank" href="http://wkhtmltopdf.org">wkhtmltopdf</a> to export pdf. You should install it on your server.
|
||||||
<br />
|
<br />
|
||||||
Please input the path that wkhtmltopdf installed, e.g. <code>/usr/local/bin/wkhtmltopdf</code>
|
Please input the path that wkhtmltopdf installed, e.g. <code>/usr/local/bin/wkhtmltopdf</code> on mac os/linux or <code>C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe</code> on windows.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ function log(o) {
|
|||||||
<a data-lang="zh-cn">简体中文</a>
|
<a data-lang="zh-cn">简体中文</a>
|
||||||
<a data-lang="zh-hk">繁体中文</a>
|
<a data-lang="zh-hk">繁体中文</a>
|
||||||
<a data-lang="pt-pt">Português</a>
|
<a data-lang="pt-pt">Português</a>
|
||||||
|
<a data-lang="es-co">Spanish</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-left">
|
<ul class="nav navbar-nav navbar-left">
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
name="sortField"
|
name="sortField"
|
||||||
value="">
|
value="">
|
||||||
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>{{msg $ "publicTime"}}</option>
|
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>{{msg $ "publicTime"}}</option>
|
||||||
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTimeTime"}}selected{{end}}>{{msg $ "createdTime"}}</option>
|
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTime"}}selected{{end}}>{{msg $ "createdTime"}}</option>
|
||||||
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>{{msg $ "updatedTime"}}</option>
|
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>{{msg $ "updatedTime"}}</option>
|
||||||
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>{{msg . "title"}}</option>
|
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>{{msg . "title"}}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -345,63 +345,74 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
<div id="noteList">
|
<div id="noteList">
|
||||||
<div class="clearfix" id="notesAndSort" style="position: relative">
|
<div class="clearfix" id="notesAndSort" style="position: relative">
|
||||||
|
|
||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
<!-- 我的笔记本 -->
|
<!-- 我的笔记本 -->
|
||||||
<div class="dropdown" id="myNotebookNavForListNav">
|
<div class="dropdown" id="myNotebookNavForListNav">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown">
|
<a class="ios7-a">
|
||||||
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
||||||
<!--
|
|
||||||
<i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<!-- 如果notebook过多, 则会产生滚动 弃用
|
|
||||||
<div class="dropdown-menu dropdown-list" style="left: 5px;">
|
|
||||||
<ul role="menu" aria-labelledby="dropdownMenu1" id="notebookNavForListNote"></ul>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 共享的笔记本 -->
|
<!-- 共享的笔记本 -->
|
||||||
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu2" data-toggle="dropdown">
|
<a class="ios7-a">
|
||||||
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
||||||
<!--
|
|
||||||
<i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" role="menu"
|
</div>
|
||||||
aria-labelledby="dropdownMenu2" style="left: 5px;" id="sharedNotebookNavForListNote">
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- tag search -->
|
||||||
|
<div class="pull-left" id="tagSearch"></div>
|
||||||
|
|
||||||
<div class="pull-left" id="tagSearch" style="line-height: 38px">
|
<!-- sort type -->
|
||||||
</div>
|
|
||||||
<div id="sortType">
|
<div id="sortType">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<!--
|
</i><i class="fa fa-th-list"></i>
|
||||||
<i class="fa fa-sort-alpha-asc">
|
|
||||||
</i>Sort <i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<!--
|
|
||||||
<ul class="dropdown-menu" role="menu"
|
<ul class="dropdown-menu" role="menu"
|
||||||
aria-labelledby="dropdownMenu1"
|
aria-labelledby="dropdownMenu1"
|
||||||
style="right: 3px; ! important; left: -100px; min-width: 100px;">
|
>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
|
||||||
href="#">创建日期</a></li>
|
<li role="presentation"><a data-view="snippet" class="view-style view-snippet" role="menuitem">
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
<i class="fa fa-check"></i>
|
||||||
href="#">修改日期</a></li>
|
{{leaMsg . "Snippet View"}}
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
</a></li>
|
||||||
href="#">标题</a></li>
|
<li role="presentation"><a data-view="list" class="view-style view-list" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "List View"}}
|
||||||
|
</a></li>
|
||||||
<li role="presentation" class="divider"></li>
|
<li role="presentation" class="divider"></li>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
<li role="presentation"><a data-sorter="dateCreatedASC" class="sorter-style sorter-dateCreatedASC" role="menuitem">
|
||||||
href="#">Separated </a></li>
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Created"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateCreatedDESC" class="sorter-style sorter-dateCreatedDESC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Created"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateUpdatedASC" class="sorter-style sorter-dateUpdatedASC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Updated"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateUpdatedDESC" class="sorter-style sorter-dateUpdatedDESC checked" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Updated"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
<li role="presentation"><a data-sorter="titleASC" class="sorter-style sorter-titleASC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Title"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="titleDESC" class="sorter-style sorter-titleDESC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Title"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -856,7 +867,7 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var LEA = {};
|
var LEA = {sPath: ''};
|
||||||
LEA.locale = "{{.locale}}";
|
LEA.locale = "{{.locale}}";
|
||||||
var UrlPrefix = '{{.siteUrl}}';
|
var UrlPrefix = '{{.siteUrl}}';
|
||||||
var UserInfo = {{.userInfo|jsonJs}};
|
var UserInfo = {{.userInfo|jsonJs}};
|
||||||
@@ -882,7 +893,7 @@ var GlobalConfigs = {{.globalConfigs|jsonJs}};
|
|||||||
<!-- dev -->
|
<!-- dev -->
|
||||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
<script src="/js/jquery.ztree.all-3.5.js"></script>
|
<script src="/js/jquery.ztree.all-3.5.js"></script>
|
||||||
<script src="/js/object_id-min.js"></script>
|
<script src="/js/object_id.js"></script>
|
||||||
<!-- /dev -->
|
<!-- /dev -->
|
||||||
|
|
||||||
<script src="/tinymce/tinymce.js"></script>
|
<script src="/tinymce/tinymce.js"></script>
|
||||||
|
|||||||
+43
-34
@@ -333,58 +333,67 @@ function log(o) {
|
|||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
<!-- 我的笔记本 -->
|
<!-- 我的笔记本 -->
|
||||||
<div class="dropdown" id="myNotebookNavForListNav">
|
<div class="dropdown" id="myNotebookNavForListNav">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown">
|
<a class="ios7-a">
|
||||||
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
||||||
<!--
|
|
||||||
<i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<!-- 如果notebook过多, 则会产生滚动 弃用
|
|
||||||
<div class="dropdown-menu dropdown-list" style="left: 5px;">
|
|
||||||
<ul role="menu" aria-labelledby="dropdownMenu1" id="notebookNavForListNote"></ul>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 共享的笔记本 -->
|
<!-- 共享的笔记本 -->
|
||||||
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu2" data-toggle="dropdown">
|
<a class="ios7-a">
|
||||||
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
||||||
<!--
|
|
||||||
<i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" role="menu"
|
|
||||||
aria-labelledby="dropdownMenu2" style="left: 5px;" id="sharedNotebookNavForListNote">
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-left" id="tagSearch" style="line-height: 38px">
|
<!-- tag search -->
|
||||||
</div>
|
<div class="pull-left" id="tagSearch"></div>
|
||||||
|
<!-- sort type -->
|
||||||
<div id="sortType">
|
<div id="sortType">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<!--
|
</i><i class="fa fa-th-list"></i>
|
||||||
<i class="fa fa-sort-alpha-asc">
|
|
||||||
</i>Sort <i class="fa fa-angle-down"></i>
|
|
||||||
-->
|
|
||||||
</a>
|
</a>
|
||||||
<!--
|
|
||||||
<ul class="dropdown-menu" role="menu"
|
<ul class="dropdown-menu" role="menu"
|
||||||
aria-labelledby="dropdownMenu1"
|
aria-labelledby="dropdownMenu1"
|
||||||
style="right: 3px; ! important; left: -100px; min-width: 100px;">
|
>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
<li role="presentation"><a data-view="snippet" class="view-style view-snippet" role="menuitem">
|
||||||
href="#">创建日期</a></li>
|
<i class="fa fa-check"></i>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
{{leaMsg . "Snippet View"}}
|
||||||
href="#">修改日期</a></li>
|
</a></li>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
<li role="presentation"><a data-view="list" class="view-style view-list" role="menuitem">
|
||||||
href="#">标题</a></li>
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "List View"}}
|
||||||
|
</a></li>
|
||||||
<li role="presentation" class="divider"></li>
|
<li role="presentation" class="divider"></li>
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
<li role="presentation"><a data-sorter="dateCreatedASC" class="sorter-style sorter-dateCreatedASC" role="menuitem">
|
||||||
href="#">Separated </a></li>
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Created"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateCreatedDESC" class="sorter-style sorter-dateCreatedDESC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Created"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateUpdatedASC" class="sorter-style sorter-dateUpdatedASC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Updated"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="dateUpdatedDESC" class="sorter-style sorter-dateUpdatedDESC checked" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Date Updated"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation" class="divider"></li>
|
||||||
|
<li role="presentation"><a data-sorter="titleASC" class="sorter-style sorter-titleASC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Title"}} <i class="fa fa-sort-alpha-asc"></i>
|
||||||
|
|
||||||
|
</a></li>
|
||||||
|
<li role="presentation"><a data-sorter="titleDESC" class="sorter-style sorter-titleDESC" role="menuitem">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
{{leaMsg . "Title"}} <i class="fa fa-sort-alpha-desc"></i>
|
||||||
|
</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -828,7 +837,7 @@ function log(o) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var LEA = {};
|
var LEA = {sPath: ''};
|
||||||
LEA.locale = "{{.locale}}";
|
LEA.locale = "{{.locale}}";
|
||||||
var UrlPrefix = '{{.siteUrl}}';
|
var UrlPrefix = '{{.siteUrl}}';
|
||||||
var UserInfo = {{.userInfo|jsonJs}};
|
var UserInfo = {{.userInfo|jsonJs}};
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ SP=$(cd "$(dirname "$0")"; pwd)
|
|||||||
tmp="/Users/life/Desktop/leanote_release"
|
tmp="/Users/life/Desktop/leanote_release"
|
||||||
|
|
||||||
# version
|
# version
|
||||||
V="v2.2"
|
V="v2.5"
|
||||||
|
|
||||||
##=================================
|
##=================================
|
||||||
# 1. 先build 成 3个平台, 2种bit = 6种
|
# 1. 先build 成 3个平台, 2种bit = 6种
|
||||||
|
|||||||
+4
-4
@@ -4,13 +4,13 @@ cd..
|
|||||||
set SCRIPTPATH=%cd%
|
set SCRIPTPATH=%cd%
|
||||||
|
|
||||||
: top src directory
|
: top src directory
|
||||||
set path="%SCRIPTPATH%\bin\src\github.com\leanote"
|
set leanotePath="%SCRIPTPATH%\bin\src\github.com\leanote"
|
||||||
|
|
||||||
if not exist "%path%" mkdir "%path%"
|
if not exist "%leanotePath%" mkdir "%leanotePath%"
|
||||||
|
|
||||||
: create software link
|
: create software link
|
||||||
if exist "%path%\leanote" del /Q "%path%\leanote"
|
if exist "%leanotePath%\leanote" del /Q "%leanotePath%\leanote"
|
||||||
mklink /D "%path%\leanote" %SCRIPTPATH%
|
mklink /D "%leanotePath%\leanote" %SCRIPTPATH%
|
||||||
|
|
||||||
: set GOPATH
|
: set GOPATH
|
||||||
set GOPATH="%SCRIPTPATH%\bin"
|
set GOPATH="%SCRIPTPATH%\bin"
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
modules
|
||||||
|
=======
|
||||||
|
|
||||||
|
Set of officially supported modules for Revel applications
|
||||||
|
|
||||||
|
### Caution
|
||||||
|
this is a work in progress
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
modules/auth
|
||||||
|
===============
|
||||||
|
|
||||||
|
Basic user/auth module
|
||||||
|
|
||||||
|
This should be modeled after [flask-security](https://github.com/mattupstate/flask-security)
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Store StorageDriver
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store = gormauth.NewGormAuthDriver()
|
||||||
|
|
||||||
|
type UserAuth interface {
|
||||||
|
// getters/setters implemented by the app-level model
|
||||||
|
UserId() string
|
||||||
|
Secret() string
|
||||||
|
HashedSecret() string
|
||||||
|
SetHashedSecret(string)
|
||||||
|
|
||||||
|
SecretDriver
|
||||||
|
// // implemented by secret driver
|
||||||
|
// Authenticate() (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretDriver interface {
|
||||||
|
Authenticate() (bool, error)
|
||||||
|
HashSecret(args ...interface{}) (string, error)
|
||||||
|
|
||||||
|
// stuff for documentation
|
||||||
|
// UserContext is expected in these?
|
||||||
|
|
||||||
|
// Secret expects 0 or non-0 arguments
|
||||||
|
// When no parameter is passed, it acts as a getter
|
||||||
|
// When one or more parameters are passed, it acts as a setter
|
||||||
|
// A driver should specify the expected arguments and their meanings
|
||||||
|
|
||||||
|
// Register()
|
||||||
|
// Login()
|
||||||
|
// Logout()
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageDriver interface {
|
||||||
|
Save(user interface{}) error
|
||||||
|
// Load should take a partially filled struct
|
||||||
|
// (with values needed to look up)
|
||||||
|
// and fills in the rest
|
||||||
|
Load(user interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// func init() {
|
||||||
|
// // auth.Store = gorm...
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (c App) Login(email, password string) {
|
||||||
|
|
||||||
|
// u := User {
|
||||||
|
// Email ...
|
||||||
|
// }
|
||||||
|
|
||||||
|
// good, err := auth.Authenticate(email, password)
|
||||||
|
|
||||||
|
// user, err := user_info.GetUserByEmail(email)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Bycrypt Authenticate() expects a single string argument of the plaintext password
|
||||||
|
// It returns true on success and false if error or password mismatch
|
||||||
|
// func Authenticate(attemptedUser UserAuth) (bool, error) {
|
||||||
|
// // check user in Store
|
||||||
|
// loadedUser, err := Store.Load(attemptedUser.UserId())
|
||||||
|
// if err != nil {
|
||||||
|
// return false, errors.New("User Not Found")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// loadedUser.Authenticate(attemptedUser.Secret())
|
||||||
|
|
||||||
|
// // successfully authenticated
|
||||||
|
// return true, nil
|
||||||
|
// }
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package auth_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/revel/modules/auth"
|
||||||
|
"github.com/revel/modules/auth/driver/secret"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
email string
|
||||||
|
password string
|
||||||
|
hashpass string
|
||||||
|
|
||||||
|
secret.BcryptAuth // SecurityDriver for testing
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUser(email, pass string) *User {
|
||||||
|
u := &User{
|
||||||
|
email: email,
|
||||||
|
password: pass,
|
||||||
|
}
|
||||||
|
u.UserContext = u
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *User) UserId() string {
|
||||||
|
return self.email
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *User) Secret() string {
|
||||||
|
return self.password
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *User) HashedSecret() string {
|
||||||
|
return self.hashpass
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *User) SetHashedSecret(hpass string) {
|
||||||
|
self.hashpass = hpass
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (self *User) Load() string
|
||||||
|
|
||||||
|
type TestStore struct {
|
||||||
|
data map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TestStore) Save(user interface{}) error {
|
||||||
|
u, ok := user.(*User)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("TestStore.Save() expected arg of type User")
|
||||||
|
}
|
||||||
|
|
||||||
|
hPass, err := u.HashSecret(u.Secret())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
self.data[u.UserId()] = hPass
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (self *TestStore) Load(user interface{}) error {
|
||||||
|
u, ok := user.(*User)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("TestStore.Load() expected arg of type User")
|
||||||
|
}
|
||||||
|
|
||||||
|
hpass, ok := self.data[u.UserId()]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Record Not Found")
|
||||||
|
}
|
||||||
|
u.SetHashedSecret(hpass)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPasswordHash(t *testing.T) {
|
||||||
|
auth.Store = &TestStore{
|
||||||
|
data: make(map[string]string),
|
||||||
|
}
|
||||||
|
u := NewUser("demo@domain.com", "demopass")
|
||||||
|
fail := NewUser("demo@domain.com", "")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
u.hashpass, err = u.HashSecret(u.password)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Should have hashed password, get error: %v\n", err)
|
||||||
|
}
|
||||||
|
fail.hashpass, err = fail.HashSecret(fail.password)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Should have failed hashing\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuthenticate(t *testing.T) {
|
||||||
|
auth.Store = &TestStore{
|
||||||
|
data: make(map[string]string),
|
||||||
|
}
|
||||||
|
|
||||||
|
// user registered a long time ago
|
||||||
|
u := NewUser("demo@domain.com", "demopass")
|
||||||
|
err := auth.Store.Save(u)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Should have saved user: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// users now logging in
|
||||||
|
pass := NewUser("demo@domain.com", "demopass")
|
||||||
|
fail := NewUser("demo@domain.com", "invalid")
|
||||||
|
|
||||||
|
// valid user is now trying to login
|
||||||
|
// check user in DB
|
||||||
|
err = auth.Store.Load(pass)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Should have loaded pass user: %v\n", err)
|
||||||
|
}
|
||||||
|
// check credentials
|
||||||
|
ok, err := pass.Authenticate()
|
||||||
|
if !ok || err != nil {
|
||||||
|
t.Errorf("Should have authenticated user")
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid user is now trying to login
|
||||||
|
err = auth.Store.Load(fail)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Should have loaded fail user")
|
||||||
|
}
|
||||||
|
// this should fail
|
||||||
|
ok, err = fail.Authenticate()
|
||||||
|
if ok || err != nil {
|
||||||
|
t.Errorf("Should have failed to authenticate user: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/* A basic user authentication module for Revel
|
||||||
|
|
||||||
|
list of concerns:
|
||||||
|
- Separating out the interface and driver
|
||||||
|
- Removing DB/Storage dependency
|
||||||
|
- UUID as default identifier?
|
||||||
|
- how to deal with password/secret or generally, method of authorization
|
||||||
|
- default {views,controllers,routes} for register/login/logut ?
|
||||||
|
- reset password in most basic ?
|
||||||
|
- activation (and other features) in a second / more sophisticated driver
|
||||||
|
- filter for checking that user is authenticated
|
||||||
|
|
||||||
|
|
||||||
|
I think a driver is made up of 2 parts
|
||||||
|
data prep and data storage
|
||||||
|
register and password reset are part of data prep
|
||||||
|
as is the auth hash method
|
||||||
|
they don't care how the data is stored
|
||||||
|
|
||||||
|
then there is the data store
|
||||||
|
|
||||||
|
perhaps each auth user model should instantiate 2 drivers instead of 1?
|
||||||
|
one for data prep components and one for storage
|
||||||
|
so the security driver and the storage driver
|
||||||
|
|
||||||
|
*/
|
||||||
|
package auth
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package secret
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"github.com/revel/modules/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// example implementation of a Revel auth security driver
|
||||||
|
// This driver should be embedded into your app-level User model
|
||||||
|
// It expects your User model to have `Password` and `HashedPassword` string fields
|
||||||
|
//
|
||||||
|
// Your User model also needs to set itself as the UserContext for the BcryptAuth driver
|
||||||
|
//
|
||||||
|
// func NewUser(email, pass string) *User {
|
||||||
|
// u := &User{
|
||||||
|
// email: email,
|
||||||
|
// password: pass,
|
||||||
|
// }
|
||||||
|
// u.UserContext = u
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type BcryptAuth struct {
|
||||||
|
UserContext auth.UserAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bcrypt Secret() returns the hashed version of the password.
|
||||||
|
// It expects an argument of type string, which is the plain text password
|
||||||
|
func (self *BcryptAuth) HashSecret(args ...interface{}) (string, error) {
|
||||||
|
if auth.Store == nil {
|
||||||
|
return "", errors.New("Auth module StorageDriver not set")
|
||||||
|
}
|
||||||
|
argLen := len(args)
|
||||||
|
if argLen == 0 {
|
||||||
|
// we are getting
|
||||||
|
return string(self.UserContext.HashedSecret()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if argLen == 1 {
|
||||||
|
// we are setting
|
||||||
|
password, ok := args[0].(string)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("Wrong argument type provided, expected plaintext password as string")
|
||||||
|
}
|
||||||
|
hPass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.UserContext.SetHashedSecret(string(hPass))
|
||||||
|
return self.UserContext.HashedSecret(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad argument count
|
||||||
|
return "", errors.New("Too many arguments provided, expected one")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bycrypt Authenticate() expects a single string argument of the plaintext password
|
||||||
|
// It returns true on success and false if error or password mismatch
|
||||||
|
func (self *BcryptAuth) Authenticate() (bool, error) {
|
||||||
|
// check password
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(self.UserContext.HashedSecret()), []byte(self.UserContext.Secret()))
|
||||||
|
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// successfully authenticated
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Mysql Auth driver
|
||||||
|
==================
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Postgresql Auth driver
|
||||||
|
==================
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Sqlite Auth driver
|
||||||
|
==================
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
// var storageDriver auth.StorageDriver // postgres in example
|
||||||
|
|
||||||
|
// type AuthUserModel struct {
|
||||||
|
// userId string
|
||||||
|
// security *SecurityDriver // bcrypt in example
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (self *AuthUserModel) UserId() string {
|
||||||
|
// return self.userId
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (self *AuthUserModel) Secret() string {
|
||||||
|
// return self.security.Secret()
|
||||||
|
// }
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package csrf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/subtle"
|
||||||
|
"encoding/hex"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// allowMethods are HTTP methods that do NOT require a token
|
||||||
|
var allowedMethods = map[string]bool{
|
||||||
|
"GET": true,
|
||||||
|
"HEAD": true,
|
||||||
|
"OPTIONS": true,
|
||||||
|
"TRACE": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandomString(length int) (string, error) {
|
||||||
|
buffer := make([]byte, int(math.Ceil(float64(length)/2)))
|
||||||
|
if _, err := io.ReadFull(rand.Reader, buffer); err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
str := hex.EncodeToString(buffer)
|
||||||
|
return str[:length], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RefreshToken(c *revel.Controller) {
|
||||||
|
token, err := RandomString(64)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.Session["csrf_token"] = token
|
||||||
|
}
|
||||||
|
|
||||||
|
// CsrfFilter enables CSRF request token creation and verification.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// 1) Add `csrf.CsrfFilter` to the app's filters (it must come after the revel.SessionFilter).
|
||||||
|
// 2) Add CSRF fields to a form with the template tag `{{ csrftoken . }}`. The filter adds a function closure to the `RenderArgs` that can pull out the secret and make the token as-needed, caching the value in the request. Ajax support provided through the `X-CSRFToken` header.
|
||||||
|
func CsrfFilter(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
token, foundToken := c.Session["csrf_token"]
|
||||||
|
|
||||||
|
if !foundToken {
|
||||||
|
RefreshToken(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
referer, refErr := url.Parse(c.Request.Header.Get("Referer"))
|
||||||
|
isSameOrigin := sameOrigin(c.Request.URL, referer)
|
||||||
|
|
||||||
|
// If the Request method isn't in the white listed methods
|
||||||
|
if !allowedMethods[c.Request.Method] && !IsExempt(c) {
|
||||||
|
// Token wasn't present at all
|
||||||
|
if !foundToken {
|
||||||
|
c.Result = c.Forbidden("REVEL CSRF: Session token missing.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Referer header is invalid
|
||||||
|
if refErr != nil {
|
||||||
|
c.Result = c.Forbidden("REVEL CSRF: HTTP Referer malformed.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same origin
|
||||||
|
if !isSameOrigin {
|
||||||
|
c.Result = c.Forbidden("REVEL CSRF: Same origin mismatch.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestToken string
|
||||||
|
// First check for token in post data
|
||||||
|
if c.Request.Method == "POST" {
|
||||||
|
requestToken = c.Request.FormValue("csrftoken")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then check for token in custom headers, as with AJAX
|
||||||
|
if requestToken == "" {
|
||||||
|
requestToken = c.Request.Header.Get("X-CSRFToken")
|
||||||
|
}
|
||||||
|
|
||||||
|
if requestToken == "" || !compareToken(requestToken, token) {
|
||||||
|
c.Result = c.Forbidden("REVEL CSRF: Invalid token.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fc[0](c, fc[1:])
|
||||||
|
|
||||||
|
// Only add token to RenderArgs if the request is: not AJAX, not missing referer header, and is same origin.
|
||||||
|
if c.Request.Header.Get("X-CSRFToken") == "" && isSameOrigin {
|
||||||
|
c.RenderArgs["_csrftoken"] = token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareToken(requestToken, token string) bool {
|
||||||
|
// ConstantTimeCompare will panic if the []byte aren't the same length
|
||||||
|
if len(requestToken) != len(token) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return subtle.ConstantTimeCompare([]byte(requestToken), []byte(token)) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates same origin policy
|
||||||
|
func sameOrigin(u1, u2 *url.URL) bool {
|
||||||
|
return u1.Scheme == u2.Scheme && u1.Host == u2.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.TemplateFuncs["csrftoken"] = func(renderArgs map[string]interface{}) template.HTML {
|
||||||
|
if tokenFunc, ok := renderArgs["_csrftoken"]; !ok {
|
||||||
|
panic("REVEL CSRF: _csrftoken missing from RenderArgs.")
|
||||||
|
} else {
|
||||||
|
return template.HTML(tokenFunc.(func() string)())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
package csrf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testFilters = []revel.Filter{
|
||||||
|
CsrfFilter,
|
||||||
|
func(c *revel.Controller, fc []revel.Filter) {
|
||||||
|
c.RenderHtml("{{ csrftoken . }}")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTokenInSession(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
getRequest, _ := http.NewRequest("GET", "http://www.example.com/", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(getRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if _, ok := c.Session["csrf_token"]; !ok {
|
||||||
|
t.Fatal("token should be present in session")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostWithoutToken(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status != 403 {
|
||||||
|
t.Fatal("post without token should be forbidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoReferrer(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
RefreshToken(c)
|
||||||
|
token := c.Session["csrf_token"]
|
||||||
|
|
||||||
|
// make a new request with the token
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("csrftoken", token)
|
||||||
|
formPostRequest, _ := http.NewRequest("POST", "http://www.example.com/", bytes.NewBufferString(data.Encode()))
|
||||||
|
formPostRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
formPostRequest.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
|
||||||
|
|
||||||
|
// and replace the old request
|
||||||
|
c.Request = revel.NewRequest(formPostRequest)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status != 403 {
|
||||||
|
t.Fatal("post without referer should be forbidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRefererHttps(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
RefreshToken(c)
|
||||||
|
token := c.Session["csrf_token"]
|
||||||
|
|
||||||
|
// make a new request with the token
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("csrftoken", token)
|
||||||
|
formPostRequest, _ := http.NewRequest("POST", "https://www.example.com/", bytes.NewBufferString(data.Encode()))
|
||||||
|
formPostRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
formPostRequest.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
|
||||||
|
formPostRequest.Header.Add("Referer", "http://www.example.com/")
|
||||||
|
|
||||||
|
// and replace the old request
|
||||||
|
c.Request = revel.NewRequest(formPostRequest)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status != 403 {
|
||||||
|
t.Fatal("posts to https should have an https referer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHeaderWithToken(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
RefreshToken(c)
|
||||||
|
token := c.Session["csrf_token"]
|
||||||
|
|
||||||
|
// make a new request with the token
|
||||||
|
formPostRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
formPostRequest.Header.Add("X-CSRFToken", token)
|
||||||
|
formPostRequest.Header.Add("Referer", "http://www.example.com/")
|
||||||
|
|
||||||
|
// and replace the old request
|
||||||
|
c.Request = revel.NewRequest(formPostRequest)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status == 403 {
|
||||||
|
t.Fatal("post with http header token should be allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormPostWithToken(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
RefreshToken(c)
|
||||||
|
token := c.Session["csrf_token"]
|
||||||
|
|
||||||
|
// make a new request with the token
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("csrftoken", token)
|
||||||
|
formPostRequest, _ := http.NewRequest("POST", "http://www.example.com/", bytes.NewBufferString(data.Encode()))
|
||||||
|
formPostRequest.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
formPostRequest.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
|
||||||
|
formPostRequest.Header.Add("Referer", "http://www.example.com/")
|
||||||
|
|
||||||
|
// and replace the old request
|
||||||
|
c.Request = revel.NewRequest(formPostRequest)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status == 403 {
|
||||||
|
t.Fatal("form post with token should be allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoTokenInArgsWhenCORs(t *testing.T) {
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
|
||||||
|
getRequest, _ := http.NewRequest("GET", "http://www.example1.com/", nil)
|
||||||
|
getRequest.Header.Add("Referer", "http://www.example2.com/")
|
||||||
|
|
||||||
|
c := revel.NewController(revel.NewRequest(getRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if _, ok := c.RenderArgs["_csrftoken"]; ok {
|
||||||
|
t.Fatal("RenderArgs should not contain token when not same origin")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package csrf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
exemptPath = make(map[string]bool)
|
||||||
|
exemptAction = make(map[string]bool)
|
||||||
|
)
|
||||||
|
|
||||||
|
func MarkExempt(route string) {
|
||||||
|
if strings.HasPrefix(route, "/") {
|
||||||
|
// e.g. "/controller/action"
|
||||||
|
exemptPath[strings.ToLower(route)] = true
|
||||||
|
} else if routeParts := strings.Split(route, "."); len(routeParts) == 2 {
|
||||||
|
// e.g. "ControllerName.ActionName"
|
||||||
|
exemptAction[route] = true
|
||||||
|
} else {
|
||||||
|
err := fmt.Sprintf("csrf.MarkExempt() received invalid argument \"%v\". Either provide a path prefixed with \"/\" or controller action in the form of \"ControllerName.ActionName\".", route)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsExempt(c *revel.Controller) bool {
|
||||||
|
if _, ok := exemptPath[strings.ToLower(c.Request.Request.URL.Path)]; ok {
|
||||||
|
return true
|
||||||
|
} else if _, ok := exemptAction[c.Action]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package csrf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExemptPath(t *testing.T) {
|
||||||
|
MarkExempt("/Controller/Action")
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/Controller/Action", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status == 403 {
|
||||||
|
t.Fatal("post to csrf exempt action should pass")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExemptPathCaseInsensitive(t *testing.T) {
|
||||||
|
MarkExempt("/Controller/Action")
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/controller/action", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status == 403 {
|
||||||
|
t.Fatal("post to csrf exempt action should pass")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExemptAction(t *testing.T) {
|
||||||
|
MarkExempt("Controller.Action")
|
||||||
|
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
postRequest, _ := http.NewRequest("POST", "http://www.example.com/Controller/Action", nil)
|
||||||
|
c := revel.NewController(revel.NewRequest(postRequest), revel.NewResponse(resp))
|
||||||
|
c.Session = make(revel.Session)
|
||||||
|
c.Action = "Controller.Action"
|
||||||
|
|
||||||
|
testFilters[0](c, testFilters)
|
||||||
|
|
||||||
|
if c.Response.Status == 403 {
|
||||||
|
t.Fatal("post to csrf exempt action should pass")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
// This module configures a database connection for the application.
|
||||||
|
//
|
||||||
|
// Developers use this module by importing and calling db.Init().
|
||||||
|
// A "Transactional" controller type is provided as a way to import interceptors
|
||||||
|
// that manage the transaction
|
||||||
|
//
|
||||||
|
// In particular, a transaction is begun before each request and committed on
|
||||||
|
// success. If a panic occurred during the request, the transaction is rolled
|
||||||
|
// back. (The application may also roll the transaction back itself.)
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Db *sql.DB
|
||||||
|
Driver string
|
||||||
|
Spec string
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
// Read configuration.
|
||||||
|
var found bool
|
||||||
|
if Driver, found = revel.Config.String("db.driver"); !found {
|
||||||
|
revel.ERROR.Fatal("No db.driver found.")
|
||||||
|
}
|
||||||
|
if Spec, found = revel.Config.String("db.spec"); !found {
|
||||||
|
revel.ERROR.Fatal("No db.spec found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a connection.
|
||||||
|
var err error
|
||||||
|
Db, err = sql.Open(Driver, Spec)
|
||||||
|
if err != nil {
|
||||||
|
revel.ERROR.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Transactional struct {
|
||||||
|
*revel.Controller
|
||||||
|
Txn *sql.Tx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin a transaction
|
||||||
|
func (c *Transactional) Begin() revel.Result {
|
||||||
|
txn, err := Db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.Txn = txn
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rollback if it's still going (must have panicked).
|
||||||
|
func (c *Transactional) Rollback() revel.Result {
|
||||||
|
if c.Txn != nil {
|
||||||
|
if err := c.Txn.Rollback(); err != nil {
|
||||||
|
if err != sql.ErrTxDone {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Txn = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the transaction.
|
||||||
|
func (c *Transactional) Commit() revel.Result {
|
||||||
|
if c.Txn != nil {
|
||||||
|
if err := c.Txn.Commit(); err != nil {
|
||||||
|
if err != sql.ErrTxDone {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Txn = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.InterceptMethod((*Transactional).Begin, revel.BEFORE)
|
||||||
|
revel.InterceptMethod((*Transactional).Commit, revel.AFTER)
|
||||||
|
revel.InterceptMethod((*Transactional).Rollback, revel.FINALLY)
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/revel/modules/jobs/app/jobs"
|
||||||
|
"github.com/robfig/cron"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Jobs struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Jobs) Status() revel.Result {
|
||||||
|
remoteAddress := c.Request.RemoteAddr
|
||||||
|
if revel.Config.BoolDefault("jobs.acceptproxyaddress", false) {
|
||||||
|
if proxiedAddress, isProxied := c.Request.Header["X-Forwarded-For"]; isProxied {
|
||||||
|
remoteAddress = proxiedAddress[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(remoteAddress, "127.0.0.1") && !strings.HasPrefix(remoteAddress, "::1") {
|
||||||
|
return c.Forbidden("%s is not local", remoteAddress)
|
||||||
|
}
|
||||||
|
entries := jobs.MainCron.Entries()
|
||||||
|
return c.Render(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.TemplateFuncs["castjob"] = func(job cron.Job) *jobs.Job {
|
||||||
|
return job.(*jobs.Job)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/robfig/cron"
|
||||||
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
Name string
|
||||||
|
inner cron.Job
|
||||||
|
status uint32
|
||||||
|
running sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
const UNNAMED = "(unnamed)"
|
||||||
|
|
||||||
|
func New(job cron.Job) *Job {
|
||||||
|
name := reflect.TypeOf(job).Name()
|
||||||
|
if name == "Func" {
|
||||||
|
name = UNNAMED
|
||||||
|
}
|
||||||
|
return &Job{
|
||||||
|
Name: name,
|
||||||
|
inner: job,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Job) Status() string {
|
||||||
|
if atomic.LoadUint32(&j.status) > 0 {
|
||||||
|
return "RUNNING"
|
||||||
|
}
|
||||||
|
return "IDLE"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Job) Run() {
|
||||||
|
// If the job panics, just print a stack trace.
|
||||||
|
// Don't let the whole process die.
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
if revelError := revel.NewErrorFromPanic(err); revelError != nil {
|
||||||
|
revel.ERROR.Print(err, "\n", revelError.Stack)
|
||||||
|
} else {
|
||||||
|
revel.ERROR.Print(err, "\n", string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if !selfConcurrent {
|
||||||
|
j.running.Lock()
|
||||||
|
defer j.running.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if workPermits != nil {
|
||||||
|
workPermits <- struct{}{}
|
||||||
|
defer func() { <-workPermits }()
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.StoreUint32(&j.status, 1)
|
||||||
|
defer atomic.StoreUint32(&j.status, 0)
|
||||||
|
|
||||||
|
j.inner.Run()
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
// A job runner for executing scheduled or ad-hoc tasks asynchronously from HTTP requests.
|
||||||
|
//
|
||||||
|
// It adds a couple of features on top of the cron package to make it play nicely with Revel:
|
||||||
|
// 1. Protection against job panics. (They print to ERROR instead of take down the process)
|
||||||
|
// 2. (Optional) Limit on the number of jobs that may run simulatenously, to
|
||||||
|
// limit resource consumption.
|
||||||
|
// 3. (Optional) Protection against multiple instances of a single job running
|
||||||
|
// concurrently. If one execution runs into the next, the next will be queued.
|
||||||
|
// 4. Cron expressions may be defined in app.conf and are reusable across jobs.
|
||||||
|
// 5. Job status reporting.
|
||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/robfig/cron"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callers can use jobs.Func to wrap a raw func.
|
||||||
|
// (Copying the type to this package makes it more visible)
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// jobs.Schedule("cron.frequent", jobs.Func(myFunc))
|
||||||
|
type Func func()
|
||||||
|
|
||||||
|
func (r Func) Run() { r() }
|
||||||
|
|
||||||
|
func Schedule(spec string, job cron.Job) error {
|
||||||
|
// Look to see if given spec is a key from the Config.
|
||||||
|
if strings.HasPrefix(spec, "cron.") {
|
||||||
|
confSpec, found := revel.Config.String(spec)
|
||||||
|
if !found {
|
||||||
|
panic("Cron spec not found: " + spec)
|
||||||
|
}
|
||||||
|
spec = confSpec
|
||||||
|
}
|
||||||
|
sched, err := cron.Parse(spec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
MainCron.Schedule(sched, New(job))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the given job at a fixed interval.
|
||||||
|
// The interval provided is the time between the job ending and the job being run again.
|
||||||
|
// The time that the job takes to run is not included in the interval.
|
||||||
|
func Every(duration time.Duration, job cron.Job) {
|
||||||
|
MainCron.Schedule(cron.Every(duration), New(job))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the given job right now.
|
||||||
|
func Now(job cron.Job) {
|
||||||
|
go New(job).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the given job once, after the given delay.
|
||||||
|
func In(duration time.Duration, job cron.Job) {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(duration)
|
||||||
|
New(job).Run()
|
||||||
|
}()
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/robfig/cron"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DEFAULT_JOB_POOL_SIZE = 10
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Singleton instance of the underlying job scheduler.
|
||||||
|
MainCron *cron.Cron
|
||||||
|
|
||||||
|
// This limits the number of jobs allowed to run concurrently.
|
||||||
|
workPermits chan struct{}
|
||||||
|
|
||||||
|
// Is a single job allowed to run concurrently with itself?
|
||||||
|
selfConcurrent bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
MainCron = cron.New()
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
if size := revel.Config.IntDefault("jobs.pool", DEFAULT_JOB_POOL_SIZE); size > 0 {
|
||||||
|
workPermits = make(chan struct{}, size)
|
||||||
|
}
|
||||||
|
selfConcurrent = revel.Config.BoolDefault("jobs.selfconcurrent", false)
|
||||||
|
MainCron.Start()
|
||||||
|
fmt.Println("Go to /@jobs to see job status.")
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
table td, table th {
|
||||||
|
padding: 4 10px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
table tr:nth-child(odd) {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Scheduled Jobs</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Name</th><th>Status</th><th>Last run</th><th>Next run</th></tr>
|
||||||
|
{{range .entries}}
|
||||||
|
{{$job := castjob .Job}}
|
||||||
|
<tr>
|
||||||
|
<td>{{$job.Name}}</td>
|
||||||
|
<td>{{$job.Status}}</td>
|
||||||
|
<td>{{if not .Prev.IsZero}}{{.Prev.Format "2006-01-02 15:04:05"}}{{end}}</td>
|
||||||
|
<td>{{if not .Next.IsZero}}{{.Next.Format "2006-01-02 15:04:05"}}{{end}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
GET /@jobs Jobs.Status
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Revel pprof module
|
||||||
|
============
|
||||||
|
|
||||||
|
#### How to use:
|
||||||
|
|
||||||
|
1. Open your app.conf file and add the following line:
|
||||||
|
`module.pprof=github.com/revel/modules/pprof`
|
||||||
|
This will enable the pprof module.
|
||||||
|
|
||||||
|
2. Next, open your routes file and add:
|
||||||
|
`module:pprof` **Note:** Do not change these routes. The pprof command-line tool by default assumes these routes.
|
||||||
|
|
||||||
|
Congrats! You can now profile your application. To use the web interface, visit `http://<host>:<port>/debug/pprof`. You can also use the `go tool pprof` command to profile your application and get a little deeper. Use the command by running `go tool pprof <binary> http://<host>:<port>`. For example, if you modified the booking sample, you would run: `go tool pprof $GOPATH/bin/booking http://localhost:9000` (assuming you used the default `revel run` arguments.
|
||||||
|
|
||||||
|
The command-line tool will take a 30-second CPU profile, and save the results to a temporary file in your `$HOME/pprof` directory. You can reference this file at a later time by using the same command as above, but by specifying the filename instead of the server address.
|
||||||
|
|
||||||
|
In order to fully utilize the command-line tool, you may need the graphviz utilities. If you're on OS X, you can install these easily using Homebrew: `brew install graphviz`.
|
||||||
|
|
||||||
|
To read more about profiling Go programs, here is some reading material: [The Go Blog](http://blog.golang.org/profiling-go-programs) : [net/pprof package documentation](http://golang.org/pkg/net/http/pprof/)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pprof struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// The PprofHandler type makes it easy to call the net/http/pprof handler methods
|
||||||
|
// since they all have the same method signature
|
||||||
|
type PprofHandler func(http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
func (r PprofHandler) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
r(resp.Out, req.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Pprof) Profile() revel.Result {
|
||||||
|
return PprofHandler(pprof.Profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Pprof) Symbol() revel.Result {
|
||||||
|
return PprofHandler(pprof.Symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Pprof) Cmdline() revel.Result {
|
||||||
|
return PprofHandler(pprof.Cmdline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Pprof) Trace() revel.Result {
|
||||||
|
return PprofHandler(pprof.Trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Pprof) Index() revel.Result {
|
||||||
|
return PprofHandler(pprof.Index)
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
GET /pprof/profile Pprof.Profile
|
||||||
|
GET /pprof/symbol Pprof.Symbol
|
||||||
|
GET /debug/pprof/cmdline Pprof.Cmdline
|
||||||
|
GET /debug/pprof/trace Pprof.Trace
|
||||||
|
GET /debug/pprof/* Pprof.Index
|
||||||
|
GET /debug/pprof/ Pprof.Index
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"os"
|
||||||
|
fpath "path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Static struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method handles requests for files. The supplied prefix may be absolute
|
||||||
|
// or relative. If the prefix is relative it is assumed to be relative to the
|
||||||
|
// application directory. The filepath may either be just a file or an
|
||||||
|
// additional filepath to search for the given file. This response may return
|
||||||
|
// the following responses in the event of an error or invalid request;
|
||||||
|
// 403(Forbidden): If the prefix filepath combination results in a directory.
|
||||||
|
// 404(Not found): If the prefix and filepath combination results in a non-existent file.
|
||||||
|
// 500(Internal Server Error): There are a few edge cases that would likely indicate some configuration error outside of revel.
|
||||||
|
//
|
||||||
|
// Note that when defining routes in routes/conf the parameters must not have
|
||||||
|
// spaces around the comma.
|
||||||
|
// Bad: Static.Serve("public/img", "favicon.png")
|
||||||
|
// Good: Static.Serve("public/img","favicon.png")
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// Serving a directory
|
||||||
|
// Route (conf/routes):
|
||||||
|
// GET /public/{<.*>filepath} Static.Serve("public")
|
||||||
|
// Request:
|
||||||
|
// public/js/sessvars.js
|
||||||
|
// Calls
|
||||||
|
// Static.Serve("public","js/sessvars.js")
|
||||||
|
//
|
||||||
|
// Serving a file
|
||||||
|
// Route (conf/routes):
|
||||||
|
// GET /favicon.ico Static.Serve("public/img","favicon.png")
|
||||||
|
// Request:
|
||||||
|
// favicon.ico
|
||||||
|
// Calls:
|
||||||
|
// Static.Serve("public/img", "favicon.png")
|
||||||
|
func (c Static) Serve(prefix, filepath string) revel.Result {
|
||||||
|
// Fix for #503.
|
||||||
|
prefix = c.Params.Fixed.Get("prefix")
|
||||||
|
if prefix == "" {
|
||||||
|
return c.NotFound("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return serve(c, prefix, filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method allows modules to serve binary files. The parameters are the same
|
||||||
|
// as Static.Serve with the additional module name pre-pended to the list of
|
||||||
|
// arguments.
|
||||||
|
func (c Static) ServeModule(moduleName, prefix, filepath string) revel.Result {
|
||||||
|
// Fix for #503.
|
||||||
|
prefix = c.Params.Fixed.Get("prefix")
|
||||||
|
if prefix == "" {
|
||||||
|
return c.NotFound("")
|
||||||
|
}
|
||||||
|
|
||||||
|
var basePath string
|
||||||
|
for _, module := range revel.Modules {
|
||||||
|
if module.Name == moduleName {
|
||||||
|
basePath = module.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
absPath := fpath.Join(basePath, fpath.FromSlash(prefix))
|
||||||
|
|
||||||
|
return serve(c, absPath, filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This method allows static serving of application files in a verified manner.
|
||||||
|
func serve(c Static, prefix, filepath string) revel.Result {
|
||||||
|
var basePath string
|
||||||
|
if !fpath.IsAbs(prefix) {
|
||||||
|
basePath = revel.BasePath
|
||||||
|
}
|
||||||
|
|
||||||
|
basePathPrefix := fpath.Join(basePath, fpath.FromSlash(prefix))
|
||||||
|
fname := fpath.Join(basePathPrefix, fpath.FromSlash(filepath))
|
||||||
|
// Verify the request file path is within the application's scope of access
|
||||||
|
if !strings.HasPrefix(fname, basePathPrefix) {
|
||||||
|
revel.WARN.Printf("Attempted to read file outside of base path: %s", fname)
|
||||||
|
return c.NotFound("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify file path is accessible
|
||||||
|
finfo, err := os.Stat(fname)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) || err.(*os.PathError).Err == syscall.ENOTDIR {
|
||||||
|
revel.WARN.Printf("File not found (%s): %s ", fname, err)
|
||||||
|
return c.NotFound("File not found")
|
||||||
|
}
|
||||||
|
revel.ERROR.Printf("Error trying to get fileinfo for '%s': %s", fname, err)
|
||||||
|
return c.RenderError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow directory listing
|
||||||
|
if finfo.Mode().IsDir() {
|
||||||
|
revel.WARN.Printf("Attempted directory listing of %s", fname)
|
||||||
|
return c.Forbidden("Directory listing not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open request file path
|
||||||
|
file, err := os.Open(fname)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
revel.WARN.Printf("File not found (%s): %s ", fname, err)
|
||||||
|
return c.NotFound("File not found")
|
||||||
|
}
|
||||||
|
revel.ERROR.Printf("Error opening '%s': %s", fname, err)
|
||||||
|
return c.RenderError(err)
|
||||||
|
}
|
||||||
|
return c.RenderFile(file, revel.Inline)
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/revel/revel/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestRunner is a controller which is used for running application tests in browser.
|
||||||
|
type TestRunner struct {
|
||||||
|
*revel.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSuiteDesc is used for storing information about a single test suite.
|
||||||
|
// This structure is required by revel test cmd.
|
||||||
|
type TestSuiteDesc struct {
|
||||||
|
Name string
|
||||||
|
Tests []TestDesc
|
||||||
|
|
||||||
|
// Elem is reflect.Type which can be used for accessing methods
|
||||||
|
// of the test suite.
|
||||||
|
Elem reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDesc is used for describing a single test of some test suite.
|
||||||
|
// This structure is required by revel test cmd.
|
||||||
|
type TestDesc struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSuiteResult stores the results the whole test suite.
|
||||||
|
// This structure is required by revel test cmd.
|
||||||
|
type TestSuiteResult struct {
|
||||||
|
Name string
|
||||||
|
Passed bool
|
||||||
|
Results []TestResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestResult represents the results of running a single test of some test suite.
|
||||||
|
// This structure is required by revel test cmd.
|
||||||
|
type TestResult struct {
|
||||||
|
Name string
|
||||||
|
Passed bool
|
||||||
|
ErrorHTML template.HTML
|
||||||
|
ErrorSummary string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testSuites []TestSuiteDesc // A list of all available tests.
|
||||||
|
|
||||||
|
none = []reflect.Value{} // It is used as input for reflect call in a few places.
|
||||||
|
|
||||||
|
// registeredTests simplifies the search of test suites by their name.
|
||||||
|
// "TestSuite.TestName" is used as a key. Value represents index in testSuites.
|
||||||
|
registeredTests map[string]int
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Controller's action methods are below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Index is an action which renders the full list of available test suites and their tests.
|
||||||
|
func (c TestRunner) Index() revel.Result {
|
||||||
|
return c.Render(testSuites)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs a single test, given by the argument.
|
||||||
|
func (c TestRunner) Run(suite, test string) revel.Result {
|
||||||
|
// Check whether requested test exists.
|
||||||
|
suiteIndex, ok := registeredTests[suite+"."+test]
|
||||||
|
if !ok {
|
||||||
|
return c.NotFound("Test %s.%s does not exist", suite, test)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := TestResult{Name: test}
|
||||||
|
|
||||||
|
// Found the suite, create a new instance and run the named method.
|
||||||
|
t := testSuites[suiteIndex].Elem
|
||||||
|
v := reflect.New(t)
|
||||||
|
func() {
|
||||||
|
// When the function stops executing try to recover from panic.
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
// If panic error is empty, exit.
|
||||||
|
panicErr := revel.NewErrorFromPanic(err)
|
||||||
|
if panicErr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, prepare and format the response of server if possible.
|
||||||
|
testSuite := v.Elem().FieldByName("TestSuite").Interface().(testing.TestSuite)
|
||||||
|
res := formatResponse(testSuite)
|
||||||
|
|
||||||
|
// Render the error and save to the result structure.
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
tmpl, _ := revel.MainTemplateLoader.Template("TestRunner/FailureDetail.html")
|
||||||
|
tmpl.Render(&buffer, map[string]interface{}{
|
||||||
|
"error": panicErr,
|
||||||
|
"response": res,
|
||||||
|
"postfix": suite + "_" + test,
|
||||||
|
})
|
||||||
|
result.ErrorSummary = errorSummary(panicErr)
|
||||||
|
result.ErrorHTML = template.HTML(buffer.String())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Initialize the test suite with a NewTestSuite()
|
||||||
|
testSuiteInstance := v.Elem().FieldByName("TestSuite")
|
||||||
|
testSuiteInstance.Set(reflect.ValueOf(testing.NewTestSuite()))
|
||||||
|
|
||||||
|
// Make sure After method will be executed at the end.
|
||||||
|
if m := v.MethodByName("After"); m.IsValid() {
|
||||||
|
defer m.Call(none)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start from running Before method of test suite if exists.
|
||||||
|
if m := v.MethodByName("Before"); m.IsValid() {
|
||||||
|
m.Call(none)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the test method itself.
|
||||||
|
v.MethodByName(test).Call(none)
|
||||||
|
|
||||||
|
// No panic means success.
|
||||||
|
result.Passed = true
|
||||||
|
}()
|
||||||
|
|
||||||
|
return c.RenderJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a JSON list of test suites and tests.
|
||||||
|
// It is used by revel test command line tool.
|
||||||
|
func (c TestRunner) List() revel.Result {
|
||||||
|
return c.RenderJson(testSuites)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Below are helper functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// describeSuite expects testsuite interface as input parameter
|
||||||
|
// and returns its description in a form of TestSuiteDesc structure.
|
||||||
|
func describeSuite(testSuite interface{}) TestSuiteDesc {
|
||||||
|
t := reflect.TypeOf(testSuite)
|
||||||
|
|
||||||
|
// Get a list of methods of the embedded test type.
|
||||||
|
// It will be used to make sure the same tests are not included in multiple test suites.
|
||||||
|
super := t.Elem().Field(0).Type
|
||||||
|
superMethods := map[string]bool{}
|
||||||
|
for i := 0; i < super.NumMethod(); i++ {
|
||||||
|
// Save the current method's name.
|
||||||
|
superMethods[super.Method(i).Name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of methods on the test suite that take no parameters, return
|
||||||
|
// no results, and were not part of the embedded type's method set.
|
||||||
|
var tests []TestDesc
|
||||||
|
for i := 0; i < t.NumMethod(); i++ {
|
||||||
|
m := t.Method(i)
|
||||||
|
mt := m.Type
|
||||||
|
|
||||||
|
// Make sure the test method meets the criterias:
|
||||||
|
// - method of testSuite without input parameters;
|
||||||
|
// - nothing is returned;
|
||||||
|
// - has "Test" prefix;
|
||||||
|
// - doesn't belong to the embedded structure.
|
||||||
|
methodWithoutParams := (mt.NumIn() == 1 && mt.In(0) == t)
|
||||||
|
nothingReturned := (mt.NumOut() == 0)
|
||||||
|
hasTestPrefix := (strings.HasPrefix(m.Name, "Test"))
|
||||||
|
if methodWithoutParams && nothingReturned && hasTestPrefix && !superMethods[m.Name] {
|
||||||
|
// Register the test suite's index so we can quickly find it by test's name later.
|
||||||
|
registeredTests[t.Elem().Name()+"."+m.Name] = len(testSuites)
|
||||||
|
|
||||||
|
// Add test to the list of tests.
|
||||||
|
tests = append(tests, TestDesc{m.Name})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TestSuiteDesc{
|
||||||
|
Name: t.Elem().Name(),
|
||||||
|
Tests: tests,
|
||||||
|
Elem: t.Elem(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorSummary gets an error and returns its summary in human readable format.
|
||||||
|
func errorSummary(err *revel.Error) (message string) {
|
||||||
|
message = fmt.Sprintf("%4sStatus: %s\n%4sIn %s", "", err.Description, "", err.Path)
|
||||||
|
|
||||||
|
// If line of error isn't known return the message as is.
|
||||||
|
if err.Line == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, include info about the line number and the relevant
|
||||||
|
// source code lines.
|
||||||
|
message += fmt.Sprintf(" (around line %d): ", err.Line)
|
||||||
|
for _, line := range err.ContextSource() {
|
||||||
|
if line.IsError {
|
||||||
|
message += line.Source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatResponse gets *revel.TestSuite as input parameter and
|
||||||
|
// transform response related info into a readable format.
|
||||||
|
func formatResponse(t testing.TestSuite) map[string]string {
|
||||||
|
if t.Response == nil {
|
||||||
|
return map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beautify the response JSON to make it human readable.
|
||||||
|
resp, err := json.MarshalIndent(t.Response, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
revel.ERROR.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove extra new line symbols so they do not take too much space on a result page.
|
||||||
|
// Allow no more than 1 line break at a time.
|
||||||
|
body := strings.Replace(string(t.ResponseBody), "\n\n", "\n", -1)
|
||||||
|
body = strings.Replace(body, "\r\n\r\n", "\r\n", -1)
|
||||||
|
|
||||||
|
return map[string]string{
|
||||||
|
"Headers": string(resp),
|
||||||
|
"Body": strings.TrimSpace(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Every time app is restarted convert the list of available test suites
|
||||||
|
// provided by the revel testing package into a format which will be used by
|
||||||
|
// the testrunner module and revel test cmd.
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
// Extracting info about available test suites from revel/testing package.
|
||||||
|
registeredTests = map[string]int{}
|
||||||
|
for _, testSuite := range testing.TestSuites {
|
||||||
|
testSuites = append(testSuites, describeSuite(testSuite))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
fmt.Println("Go to /@tests to run the tests.")
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<b>{{.error.Description}}</b>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<li class="active"><a href="#error_{{.postfix}}" role="tab" data-toggle="tab">Error</a></li>
|
||||||
|
<li><a href="#stack_{{.postfix}}" role="tab" data-toggle="tab">Stack</a></li>
|
||||||
|
{{if .response}}
|
||||||
|
<li><a href="#headers_{{.postfix}}" role="tab" data-toggle="tab">Headers</a></li>
|
||||||
|
<li><a href="#body_{{.postfix}}" role="tab" data-toggle="tab">Response Body</a></li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="result_{{.postfix}}">
|
||||||
|
<div class="tab-pane active" id="error_{{.postfix}}">
|
||||||
|
<div class="panel panel-danger">
|
||||||
|
<div class="panel-heading">
|
||||||
|
In {{.error.Path}}{{if .error.Line}} (around {{if .error.Line}}line {{.error.Line}}{{end}}{{if .error.Column}} column {{.error.Column}}{{end}}){{end}}:
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{range .error.ContextSource}}
|
||||||
|
{{if .IsError}}
|
||||||
|
<pre><code class="go">{{.Source}}</code></pre>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="stack_{{.postfix}}">
|
||||||
|
<pre><code class="bash">{{.error.Stack}}</code></pre>
|
||||||
|
</div>
|
||||||
|
{{if .response}}
|
||||||
|
<div class="tab-pane" id="headers_{{.postfix}}">
|
||||||
|
<pre><code class="json">{{.response.Headers}}</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="body_{{.postfix}}">
|
||||||
|
<pre><code class="html">{{.response.Body}}</code></pre>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Revel Test Runner</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<link href="{{url `Root`}}/@tests/public/css/bootstrap.min.css" type="text/css" rel="stylesheet"></link>
|
||||||
|
<link href="{{url `Root`}}/@tests/public/css/github.css" type="text/css" rel="stylesheet"></link>
|
||||||
|
<script src="{{url `Root`}}/@tests/public/js/jquery-1.9.1.min.js" type="text/javascript"></script>
|
||||||
|
<script src="{{url `Root`}}/@tests/public/js/bootstrap.min.js" type="text/javascript"></script>
|
||||||
|
<script src="{{url `Root`}}/@tests/public/js/highlight.pack.js" type="text/javascript"></script>
|
||||||
|
<style>
|
||||||
|
header { padding:20px 0; background-color:#ADD8E6 }
|
||||||
|
.passed td { background-color: #90EE90 !important; }
|
||||||
|
.failed td { background-color: #FFB6C1 !important; }
|
||||||
|
.tests td.name, .tests td.result { padding-top: 13px; }
|
||||||
|
pre { font-size:10px; white-space: pre; }
|
||||||
|
.name { width: 25%; }
|
||||||
|
.w100 { width: 100%; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<table class="w100"><tr><td>
|
||||||
|
<h1>Test Runner</h1>
|
||||||
|
<p class="lead">Run all of your application's tests from here.</p>
|
||||||
|
</td><td style="padding-left:150px;" class="text-right">
|
||||||
|
<button class="btn btn-lg btn-success" all-tests="">Run All Tests</button>
|
||||||
|
</td></tr></table>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{{range .testSuites}}
|
||||||
|
<p class="lead" style="margin-top:20px;">{{.Name}}</p>
|
||||||
|
<table class="table table-striped tests" suite="{{.Name}}">
|
||||||
|
{{range .Tests}}
|
||||||
|
<tr>
|
||||||
|
<td class="name">{{.Name}}</td>
|
||||||
|
<td class="result">
|
||||||
|
</td>
|
||||||
|
<td class="text-right"><button test="{{.Name}}" class="btn btn-success">Run</button></td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var buttons = [];
|
||||||
|
var running;
|
||||||
|
|
||||||
|
$("button[test]").click(function() {
|
||||||
|
var button = $(this).addClass("disabled").text("Running");
|
||||||
|
addToQueue(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("button[all-tests]").click(function() {
|
||||||
|
var button = $(this).addClass("disabled").text("Running");
|
||||||
|
$("button[test]").click();
|
||||||
|
});
|
||||||
|
|
||||||
|
function addToQueue(button) {
|
||||||
|
buttons.push(button);
|
||||||
|
if (!running) {
|
||||||
|
running = true;
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextTest() {
|
||||||
|
if (buttons.length == 0) {
|
||||||
|
running = false;
|
||||||
|
} else {
|
||||||
|
var next = buttons.shift();
|
||||||
|
runTest(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest(button) {
|
||||||
|
var suite = button.parents("table").attr("suite");
|
||||||
|
var test = button.attr("test");
|
||||||
|
var row = button.parents("tr");
|
||||||
|
var resultCell = row.children(".result");
|
||||||
|
$.ajax({
|
||||||
|
dataType: "json",
|
||||||
|
url: "{{url `Root`}}/@tests/"+suite+"/"+test,
|
||||||
|
success: function(result) {
|
||||||
|
row.attr("class", result.Passed ? "passed" : "failed");
|
||||||
|
if (result.Passed) {
|
||||||
|
resultCell.html("");
|
||||||
|
} else {
|
||||||
|
resultCell.html(result.ErrorHTML);
|
||||||
|
|
||||||
|
$("#result_" + suite + "_" + test + " pre code").each(function(i, block) {
|
||||||
|
hljs.highlightBlock(block);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
button.removeClass("disabled").text("Run");
|
||||||
|
if (buttons.length == 0) {
|
||||||
|
$("button[all-tests]").removeClass("disabled").text("Run All Tests");
|
||||||
|
}
|
||||||
|
nextTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Revel Test Runner</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #333333;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
header { padding:20px 0; }
|
||||||
|
header.passed { background-color: #90EE90 !important; }
|
||||||
|
header.failed { background-color: #FFB6C1 !important; }
|
||||||
|
table { margin-top: 20px; padding: 8px; line-height: 20px; }
|
||||||
|
td { vertical-align: top; padding-right:20px; }
|
||||||
|
a { color: #0088cc; }
|
||||||
|
.container { margin-left: auto; margin-right: auto; width: 940px; overflow: hidden; }
|
||||||
|
.result h2 { font-size: 16px; border-bottom: 1px solid #f0f0f0; padding-bottom: 0.2em; }
|
||||||
|
.result.failed b { font-weight:bold; color: #C00; font-size: 14px; }
|
||||||
|
.result.failed h2 { color: #C00; }
|
||||||
|
.result .info { font-size: 12px; }
|
||||||
|
.result .info pre { overflow: auto; background-color: #f0f0f0; width: 100%; max-height: 500px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="{{if .Passed}}passed{{else}}failed{{end}}">
|
||||||
|
<div class="container">
|
||||||
|
<h1>{{.Name}}</h1>
|
||||||
|
<p>{{if .Passed}}PASSED{{else}}FAILED{{end}}</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{{range .Results}}
|
||||||
|
<div class="result {{if .Passed}}passed{{else}}failed{{end}}">
|
||||||
|
<div><h2>{{.Name}}</h2></div>
|
||||||
|
<div class="info">{{if .ErrorHTML}}{{.ErrorHTML}}{{else}}PASSED{{end}}</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
GET /@tests TestRunner.Index
|
||||||
|
GET /@tests.list TestRunner.List
|
||||||
|
GET /@tests/public/*filepath Static.ServeModule(testrunner,public)
|
||||||
|
GET /@tests/:suite/:test TestRunner.Run
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap v3.2.0 (http://getbootstrap.com)
|
||||||
|
* Copyright 2011-2014 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
*//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-Line truncated
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #333;
|
||||||
|
background: #f8f8f8;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-template_comment,
|
||||||
|
.diff .hljs-header,
|
||||||
|
.hljs-javadoc {
|
||||||
|
color: #998;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.css .rule .hljs-keyword,
|
||||||
|
.hljs-winutils,
|
||||||
|
.javascript .hljs-title,
|
||||||
|
.nginx .hljs-title,
|
||||||
|
.hljs-subst,
|
||||||
|
.hljs-request,
|
||||||
|
.hljs-status {
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-hexcolor,
|
||||||
|
.ruby .hljs-constant {
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-tag .hljs-value,
|
||||||
|
.hljs-phpdoc,
|
||||||
|
.hljs-dartdoc,
|
||||||
|
.tex .hljs-formula {
|
||||||
|
color: #d14;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-id,
|
||||||
|
.scss .hljs-preprocessor {
|
||||||
|
color: #900;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.javascript .hljs-title,
|
||||||
|
.hljs-list .hljs-keyword,
|
||||||
|
.hljs-subst {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-class .hljs-title,
|
||||||
|
.hljs-type,
|
||||||
|
.vhdl .hljs-literal,
|
||||||
|
.tex .hljs-command {
|
||||||
|
color: #458;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-tag .hljs-title,
|
||||||
|
.hljs-rules .hljs-property,
|
||||||
|
.django .hljs-tag .hljs-keyword {
|
||||||
|
color: #000080;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-variable,
|
||||||
|
.lisp .hljs-body {
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp {
|
||||||
|
color: #009926;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-symbol,
|
||||||
|
.ruby .hljs-symbol .hljs-string,
|
||||||
|
.lisp .hljs-keyword,
|
||||||
|
.clojure .hljs-keyword,
|
||||||
|
.scheme .hljs-keyword,
|
||||||
|
.tex .hljs-special,
|
||||||
|
.hljs-prompt {
|
||||||
|
color: #990073;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-preprocessor,
|
||||||
|
.hljs-pragma,
|
||||||
|
.hljs-pi,
|
||||||
|
.hljs-doctype,
|
||||||
|
.hljs-shebang,
|
||||||
|
.hljs-cdata {
|
||||||
|
color: #999;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
background: #fdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
background: #dfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff .hljs-change {
|
||||||
|
background: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-chunk {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap v3.2.0 (http://getbootstrap.com)
|
||||||
|
* Copyright 2011-2014 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.Line truncated
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
var hljs=new function(){function j(v){return v.replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">")}function t(v){return v.nodeName.toLowerCase()}function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^lang(uage)?-/,"")});return v.filter(function(x){return i(x)||/no(-?)highlight/.test(x)})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);if(!t(A).match(/br|hr|img|input/)){v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset<y[0].offset)?w:y}return y[0].event=="start"?w:y}function A(H){function G(I){return" "+I.nodeName+'="'+j(I.value)+'"'}F+="<"+t(H)+Array.prototype.map.call(H.attributes,G).join("")+">"}function E(G){F+="</"+t(G)+">"}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=j(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+j(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};var E=function(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})};if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b="\\b("+D.bK.split(" ").join("|")+")\\b"}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?("+F.b+")\\.?":F.b}).concat([D.tE,D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}}}x(y)}function c(T,L,J,R){function v(V,W){for(var U=0;U<W.c.length;U++){if(h(W.c[U].bR,V)){return W.c[U]}}}function z(V,U){if(h(V.eR,U)){return V}if(V.eW){return z(V.parent,U)}}function A(U,V){return !J&&h(V.iR,U)}function E(W,U){var V=M.cI?U[0].toLowerCase():U[0];return W.k.hasOwnProperty(V)&&W.k[V]}function w(aa,Y,X,W){var U=W?"":b.classPrefix,V='<span class="'+U,Z=X?"":"</span>";V+=aa+'">';return V+Y+Z}function N(){if(!I.k){return j(C)}var U="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(C);while(V){U+=j(C.substr(X,V.index-X));var W=E(I,V);if(W){H+=W[1];U+=w(W[0],j(V[0]))}else{U+=j(V[0])}X=I.lR.lastIndex;V=I.lR.exec(C)}return U+j(C.substr(X))}function F(){if(I.sL&&!f[I.sL]){return j(C)}var U=I.sL?c(I.sL,C,true,S):e(C);if(I.r>0){H+=U.r}if(I.subLanguageMode=="continuous"){S=U.top}return w(U.language,U.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(W,V){var U=W.cN?w(W.cN,"",true):"";if(W.rB){D+=U;C=""}else{if(W.eB){D+=j(V)+U;C=""}else{D+=U;C=V}}I=Object.create(W,{parent:{value:I}})}function G(U,Y){C+=U;if(Y===undefined){D+=Q();return 0}var W=v(Y,I);if(W){D+=Q();P(W,Y);return W.rB?0:Y.length}var X=z(I,Y);if(X){var V=I;if(!(V.rE||V.eE)){C+=Y}D+=Q();do{if(I.cN){D+="</span>"}H+=I.r;I=I.parent}while(I!=X.parent);if(V.eE){D+=j(Y)}C="";if(X.starts){P(X.starts,"")}return V.rE?0:Y.length}if(A(Y,I)){throw new Error('Illegal lexeme "'+Y+'" for mode "'+(I.cN||"<unnamed>")+'"')}C+=Y;return Y.length||1}var M=i(T);if(!M){throw new Error('Unknown language: "'+T+'"')}m(M);var I=R||M;var S;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,"",true)+D}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+="</span>"}}return{r:H,value:D,language:T,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:j(L)}}else{throw O}}}function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};var w=v;x.forEach(function(z){if(!i(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"<br>")}return v}function p(A){var B=r(A);if(/no(-?)highlight/.test(B)){retuLine truncated
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
||||||
|
//@ sourceMappingURL=jquery.min.map
|
||||||
|
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
||||||
|
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
||||||
|
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
||||||
@@ -34,6 +34,7 @@ cookie.httponly=false
|
|||||||
cookie.prefix=LEANOTE
|
cookie.prefix=LEANOTE
|
||||||
cookie.domain= # for share cookie with sub-domain
|
cookie.domain= # for share cookie with sub-domain
|
||||||
cookie.secure=false
|
cookie.secure=false
|
||||||
|
session.expires=3h # 3 hour. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||||
format.date=2006-01-02
|
format.date=2006-01-02
|
||||||
format.datetime=2006-01-02 15:04:05 # 必须这样配置
|
format.datetime=2006-01-02 15:04:05 # 必须这样配置
|
||||||
results.chunked=false
|
results.chunked=false
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ POST /findPasswordUpdate Auth.FindPasswordUpdate
|
|||||||
* /note/setNote2Blog Note.SetNote2Blog
|
* /note/setNote2Blog Note.SetNote2Blog
|
||||||
* /note/exportPdf Note.ExportPDF
|
* /note/exportPdf Note.ExportPDF
|
||||||
* /note/toPdf Note.ToPdf
|
* /note/toPdf Note.ToPdf
|
||||||
|
* /note/getNoteAndContentBySrc Note.GetNoteAndContentBySrc
|
||||||
# pjax
|
# pjax
|
||||||
GET /note/:noteId Note.Index
|
GET /note/:noteId Note.Index
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Cut=Cut
|
Cut=Cut
|
||||||
Header 2=Header 2
|
Header 2=Header 2
|
||||||
Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.=Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.
|
Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.=Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.
|
||||||
Div=Div
|
Div=Div
|
||||||
Paste=Paste
|
Paste=Paste
|
||||||
Close=Close
|
Close=Close
|
||||||
@@ -73,7 +73,7 @@ Language=Language
|
|||||||
Fullscreen=Full-screen
|
Fullscreen=Full-screen
|
||||||
Horizontal line=Horizontal line
|
Horizontal line=Horizontal line
|
||||||
Horizontal space=Horizontal space
|
Horizontal space=Horizontal space
|
||||||
Insert\/edit image=Insert\/edit image
|
Insert/edit image=Insert/edit image
|
||||||
General=General
|
General=General
|
||||||
Advanced=Advanced
|
Advanced=Advanced
|
||||||
Source=Source
|
Source=Source
|
||||||
@@ -84,7 +84,7 @@ Image description=Image description
|
|||||||
Style=Style
|
Style=Style
|
||||||
Dimensions=Dimensions
|
Dimensions=Dimensions
|
||||||
Insert image=Insert image
|
Insert image=Insert image
|
||||||
Insert date\/time=Insert date\/time
|
Insert date/time=Insert date/time
|
||||||
Remove link=Remove link
|
Remove link=Remove link
|
||||||
Url=URL
|
Url=URL
|
||||||
Text to display=Text to display
|
Text to display=Text to display
|
||||||
@@ -92,11 +92,11 @@ Anchors=Anchors
|
|||||||
Insert link=Insert link
|
Insert link=Insert link
|
||||||
New window=New window
|
New window=New window
|
||||||
None=None
|
None=None
|
||||||
The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?=The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
|
The URL you entered seems to be an external link. Do you want to add the required http:// prefix?=The URL you entered seems to be an external link. Do you want to add the required http:// prefix?
|
||||||
Target=Target
|
Target=Target
|
||||||
The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?=The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
|
The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?=The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
|
||||||
Insert\/edit link=Insert\/edit link
|
Insert/edit link=Insert/edit link
|
||||||
Insert\/edit video=Insert\/edit video
|
Insert/edit video=Insert/edit video
|
||||||
Poster=Poster
|
Poster=Poster
|
||||||
Alternative source=Alternative source
|
Alternative source=Alternative source
|
||||||
Paste your embed code below:=Paste your embed code below:
|
Paste your embed code below:=Paste your embed code below:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Cut=Cut
|
Cut=Cut
|
||||||
Header 2=Header 2
|
Header 2=Header 2
|
||||||
Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.=Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.
|
Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.=Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.
|
||||||
Div=Div
|
Div=Div
|
||||||
Paste=Paste
|
Paste=Paste
|
||||||
Close=Close
|
Close=Close
|
||||||
@@ -73,7 +73,7 @@ Language=Language
|
|||||||
Fullscreen=Full-screen
|
Fullscreen=Full-screen
|
||||||
Horizontal line=Horizontal line
|
Horizontal line=Horizontal line
|
||||||
Horizontal space=Horizontal space
|
Horizontal space=Horizontal space
|
||||||
Insert\/edit image=Insert\/edit image
|
Insert/edit image=Insert/edit image
|
||||||
General=General
|
General=General
|
||||||
Advanced=Advanced
|
Advanced=Advanced
|
||||||
Source=Source
|
Source=Source
|
||||||
@@ -84,7 +84,7 @@ Image description=Image description
|
|||||||
Style=Style
|
Style=Style
|
||||||
Dimensions=Dimensions
|
Dimensions=Dimensions
|
||||||
Insert image=Insert image
|
Insert image=Insert image
|
||||||
Insert date\/time=Insert date\/time
|
Insert date/time=Insert date/time
|
||||||
Remove link=Remove link
|
Remove link=Remove link
|
||||||
Url=URL
|
Url=URL
|
||||||
Text to display=Text to display
|
Text to display=Text to display
|
||||||
@@ -92,11 +92,11 @@ Anchors=Anchors
|
|||||||
Insert link=Insert link
|
Insert link=Insert link
|
||||||
New window=New window
|
New window=New window
|
||||||
None=None
|
None=None
|
||||||
The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?=The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
|
The URL you entered seems to be an external link. Do you want to add the required http:// prefix?=The URL you entered seems to be an external link. Do you want to add the required http:// prefix?
|
||||||
Target=Target
|
Target=Target
|
||||||
The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?=The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
|
The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?=The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
|
||||||
Insert\/edit link=Insert\/edit link
|
Insert/edit link=Insert/edit link
|
||||||
Insert\/edit video=Insert\/edit video
|
Insert/edit video=Insert/edit video
|
||||||
Poster=Poster
|
Poster=Poster
|
||||||
Alternative source=Alternative source
|
Alternative source=Alternative source
|
||||||
Paste your embed code below:=Paste your embed code below:
|
Paste your embed code below:=Paste your embed code below:
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
# album image
|
||||||
|
Images=Imágenes
|
||||||
|
Upload=Subir
|
||||||
|
Image URL=URL de imágen
|
||||||
|
Albums=Álbumes
|
||||||
|
Default=Predeterminado
|
||||||
|
File title search=Búsqueda de título de archivo
|
||||||
|
Go to upload images=Ir a cargar imágenes
|
||||||
|
Rename=Renombrar
|
||||||
|
Add=Añadir
|
||||||
|
Add Album=Añadir álbum
|
||||||
|
Add Image=Añadir imagen
|
||||||
|
Can't load this url=No puede leer esta URL
|
||||||
|
No Images=Sin imágenes
|
||||||
|
Click to upload images Or Drop images to here=Haz clic para cargar imágenes o suelta imágenes aquí
|
||||||
|
|
||||||
|
Cannot delete default album=No puede eliminar el álbum predeterminado
|
||||||
|
Cannot rename default album=No puede renombrar el álbum predeterminado
|
||||||
|
This album has images, please delete it's images at first.=Este álbum tiene imágenes, por favor, primero debe borrar sus imágenes.
|
||||||
|
|
||||||
|
Rename Album=Renombrar álbum
|
||||||
|
Add Success!=Añadido correctamente!
|
||||||
|
Rename Success!=Renombrado correctamente!
|
||||||
|
Delete Success!=Eliminado correctamente!
|
||||||
|
Are you sure to delete this image ?=Está seguro que desea eliminar esta imagen?
|
||||||
|
click to remove this image=clic para eliminar esta imagem
|
||||||
|
error=error
|
||||||
|
Error=Error
|
||||||
|
Prev=Anterior
|
||||||
|
Next=Siguiente
|
||||||
Loaded 100 of 306 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user