Compare commits

...
34 Commits
Author SHA1 Message Date
lealife 64a3177978 vendor 2017-07-27 14:45:11 +08:00
lealife ed2ad19341 go vendor release 2017-06-22 17:12:39 +08:00
lealife b140cd538f vendor 2017-06-22 13:18:16 +08:00
lealife 2654b684df upgrade revel to 0.16 2017-06-21 18:24:42 +08:00
life d424395d85 Update .travis.yml 2017-06-21 18:09:53 +08:00
life 54810b3458 Merge pull request #628 from samtux/master
Translation to Spanish
2017-06-21 17:57:56 +08:00
Samuel Mesa 1cf66ad6c0 Translation to Spanish 2017-06-19 21:10:49 -05:00
lealife 6dc334ca51 Chrome 58 cannot select image 2017-05-19 11:50:50 +08:00
life f9b4ead6be Merge pull request #590 from sundev126/patch-1
修复arm 32下/adminUser/index假死的bug
2017-04-16 21:36:13 +08:00
lealife 3bf6703929 blog paging configuration 2017-04-16 15:27:35 +08:00
Sunpy ec657b9dcb 修复arm 32下/adminUser/index假死的bug
如果pageSize为0,则计算页数的时候会造成浮点数除0.0,由于浮点数除0得到的结果是`+Inf`,转换为整数后的结果是`2,147,483,647`,所以在渲染page.html模板时需要很长时间。
2017-04-13 18:00:42 +08:00
lealife 4ffd048b2a Form submission canceled because the form is not connected 2017-04-12 15:58:55 +08:00
lealife 6af19670da Upgrade revel from 0.13 to 0.14
https://github.com/revel/revel/releases/tag/v0.14.0
2017-04-08 18:55:42 +08:00
lealife 721e375d76 mind map 2017-03-07 13:38:04 +08:00
lealife 41f95cf0e5 2.4 released 2017-02-20 13:57:24 +08:00
lealife ba411ef580 2.4 released 2017-02-20 13:51:07 +08:00
lealife 9dcf0ed53e delete unused 2017-02-20 13:48:26 +08:00
lealife d5d853ffd3 Support note list view and sorter 2017-02-18 20:01:43 +08:00
lealife ae29119664 set session.expires to 3h 2017-02-18 20:01:26 +08:00
lealife ad644258f5 Support for leanote-chrome plugin 2017-02-18 20:01:14 +08:00
lealife 8c98f4da5c markdown remove smartypants; support table align 2017-02-09 11:39:30 +08:00
lealife e2585bf695 2.3 released 2017-01-23 22:41:31 +08:00
lealife 3b9bc687c4 theme 2017-01-23 18:26:56 +08:00
lealife 2db182db1b 2.3 released 2017-01-23 17:43:41 +08:00
lealife f3e1eb6c3f Add leaui mind map plugin 2017-01-23 17:43:13 +08:00
lealife 956e1ba2bb fix upload image error [api] 2017-01-23 17:42:38 +08:00
lealife f294fa4124 fix cannot add deleted tags 2017-01-23 17:42:21 +08:00
lealife cabf89f9b8 like bug 2017-01-23 17:42:04 +08:00
lealife d183cd5a77 https://github.com/leanote/leanote/issues/513 2017-01-16 11:49:30 +08:00
lealife 000dfea92d 2.2.2 2017-01-07 15:55:31 +08:00
lealife a53398ebb4 Fix export note image to pdf error 2017-01-07 15:53:22 +08:00
lealife b23592229a update travis 2016-12-31 12:16:17 +08:00
lealife 584bde247e fix search deleted note 2016-12-31 12:10:27 +08:00
lealife 6774392807 2.2.1 2016-12-28 11:19:09 +08:00
812 changed files with 281577 additions and 1873 deletions

No files matched your search

+5 -6
View File
@@ -1,5 +1,5 @@
language: go language: go
go: 1.4 go: 1.7
services: services:
- mongodb # 2.4.12 - mongodb # 2.4.12
@@ -7,8 +7,9 @@ services:
install: install:
- export PATH=$PATH:$HOME/gopath/bin - export PATH=$PATH:$HOME/gopath/bin
- go get -v github.com/leanote/leanote/app - go get -v github.com/leanote/leanote/app
- go get -u github.com/revel/cmd/revel - go get -v github.com/leanote/leanote/cmd
- ls $GOPATH/src/github.com/revel/ # - go get -u github.com/revel/cmd/revel
# - ls $GOPATH/src/github.com/revel/
# - go get github.com/revel/moudle/revel # - go get github.com/revel/moudle/revel
# - go install github.com/revel/cmd/revel # - go install github.com/revel/cmd/revel
- pwd - pwd
@@ -18,8 +19,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
@@ -34,4 +33,4 @@ script:
- curl http://localhost:9000/demo - curl http://localhost:9000/demo
# - revel build github.com/leanote/leanote tmp # - revel build github.com/leanote/leanote tmp
# OK # OK
+2 -2
View File
@@ -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);
+20
View File
@@ -0,0 +1,20 @@
# Modifications
* revel.go
```
RevelImportPath = "github.com/leanote/leanote/vendor/github.com/revel/revel"
```
# RUN
```
go install github.com/leanote/leanote/cmd/leanote_revel
leanote_revel run github.com/leanote/leanote
```
# build leanote, 在当前目录生成了leanote二进制文件
go build -o ./leanote github.com/leanote/leanote/app/tmp
# 运行leanote, 其中-importPath是必须的
./leanote -importPath=github.com/leanote/leanote -runMode=prod -port=9000
+5 -5
View File
@@ -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))
} }
+3 -3
View File
@@ -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)
} }
// 下载附件 // 下载附件
+29 -29
View File
@@ -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")
} }
+11 -11
View File
@@ -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)
} }
+97 -97
View File
@@ -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)
} }
+16 -16
View File
@@ -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)
} }
+3 -3
View File
@@ -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)
} }
+49 -36
View File
@@ -36,7 +36,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 +58,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 +97,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 +106,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 +142,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 +187,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 +201,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 +248,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 +258,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 +279,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 +292,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 +305,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 +313,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 +349,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 +397,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")
} }
@@ -475,5 +488,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)
} }
+9 -9
View File
@@ -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)
} }
+12 -12
View File
@@ -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(""))
} }
+27 -27
View File
@@ -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)
} }
// 更新, 也是一样, 先删后加 // 更新, 也是一样, 先删后加
+2 -2
View File
@@ -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)
} }
+16 -16
View File
@@ -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)
} }
+1 -1
View File
@@ -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
} }
+4 -4
View File
@@ -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)
} }
+9 -9
View File
@@ -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")
} }
+5 -5
View File
@@ -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)
+28 -28
View File
@@ -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")
} }
+21 -21
View File
@@ -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)
} }
+5 -5
View File
@@ -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")
} }
+1 -1
View File
@@ -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")
+7 -7
View File
@@ -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)
} }
+4 -4
View File
@@ -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)
+4 -4
View 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)
} }
*/ */
+33 -33
View File
@@ -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链接是
@@ -207,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)
} }
// 添加笔记 // 添加笔记
@@ -233,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()
@@ -259,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 {
// 建立映射 // 建立映射
@@ -271,7 +271,7 @@ func (c ApiNote) AddNote(noteOrContent info.ApiNote) revel.Result {
} }
} }
} else { } else {
return c.RenderJson(re) return c.RenderJSON(re)
} }
} }
} }
@@ -282,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,
@@ -318,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)
} }
// 添加需要返回的 // 添加需要返回的
@@ -332,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)
} }
// 更新笔记 // 更新笔记
@@ -347,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("_____________")
@@ -368,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("没有冲突")
@@ -402,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)
} }
} }
} }
@@ -490,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)
} }
} }
@@ -528,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 = ""
@@ -539,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)
} }
// 得到历史列表 // 得到历史列表
@@ -558,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)
} }
*/ */
@@ -569,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()
@@ -584,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)
} }
} }
@@ -594,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
@@ -623,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
+7 -7
View File
@@ -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(&notebook)) return c.RenderJSON(c.fixNotebook(&notebook))
} }
// 修改笔记 // 修改笔记
@@ -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(&notebook)) return c.RenderJSON(c.fixNotebook(&notebook))
} }
// 删除笔记本 // 删除笔记本
@@ -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)
} }
+3 -3
View File
@@ -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)
} }
+12 -12
View File
@@ -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)
} }
} }
+2 -2
View File
@@ -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() {
+1 -1
View File
@@ -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
} }
+61 -61
View File
@@ -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")
} }
+1 -1
View File
@@ -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")
+9
View File
@@ -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
View File
@@ -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
View File
@@ -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)
} }
+2 -2
View File
@@ -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.
+3 -4
View File
@@ -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
} }
+1 -1
View File
@@ -606,5 +606,5 @@ func (this *ConfigService) HomePageIsAdminsBlog() bool {
} }
func (this *ConfigService) GetVersion() string { func (this *ConfigService) GetVersion() string {
return "2.2" return "2.4"
} }
+36 -1
View File
@@ -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(&notes)
if len(notes) > 0 {
return notes[0]
}
// db.GetByQ(db.Notes, bson.M{"Src": src, "UserId": bson.ObjectIdHex(userId), "IsDeleted": false}, &note)
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
} }
+9 -1
View File
@@ -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
} }
+1
View File
@@ -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&ecirc;s</a> <a data-lang="pt-pt">Portugu&ecirc;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">
+2 -2
View File
@@ -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>
@@ -49,7 +49,7 @@
{{template "member/footer.html" .}} {{template "member/footer.html" .}}
<script> <script>
var urlPrefix = "{{.siteUrl}}"; var urlPrefix = "{{.siteUrl}}";
$(function() { $(function() {
// domain // domain
$("#baseBtn").click(function(e) { $("#baseBtn").click(function(e) {
e.preventDefault(); e.preventDefault();
+47 -36
View File
@@ -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"
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"
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
View File
@@ -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}};
+7 -3
View File
@@ -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种
@@ -32,7 +32,7 @@ function build()
suffix=".exe" suffix=".exe"
fi fi
GOOS=$1 GOARCH=$2 go build -o leanote-$1-$2$suffix ../app/tmp GOOS=$1 GOARCH=$2 go build -o leanote-$1-$2$suffix github.com/leanote/leanote/app/tmp
} }
build "linux" "386"; build "linux" "386";
@@ -62,12 +62,16 @@ cd $SP
cd ../ cd ../
# bin # bin
cp -r ./bin/src $tmp/leanote/bin/ # cp -r ./bin/src $tmp/leanote/bin/
mkdir -p $tmp/leanote/bin/src/github.com/leanote
cp ./bin/run.sh $tmp/leanote/bin/ cp ./bin/run.sh $tmp/leanote/bin/
cp ./bin/run.bat $tmp/leanote/bin/ cp ./bin/run.bat $tmp/leanote/bin/
# views # views
cp -r ./app/views $tmp/leanote/app cp -r ./app/views $tmp/leanote/app
# vendor
cp -r ./vendor $tmp/leanote/
# 可不要, 源码 # 可不要, 源码
#cp -r ./app/service $tmp/leanote/app/service #cp -r ./app/service $tmp/leanote/app/service
#cp -r ./app/controllers $tmp/leanote/app/controllers #cp -r ./app/controllers $tmp/leanote/app/controllers
+11
View File
@@ -0,0 +1,11 @@
# Revel command line tools
Provides the `revel` command, used to create and run Revel apps.
- More info at http://revel.github.io/manual/tool.html
Install
------------
```bash
go get github.com/revel/cmd/revel
```
+127
View File
@@ -0,0 +1,127 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/exec"
"time"
"github.com/revel/revel"
)
// App contains the configuration for running a Revel app. (Not for the app itself)
// Its only purpose is constructing the command to execute.
type App struct {
BinaryPath string // Path to the app executable
Port int // Port to pass as a command line argument.
cmd AppCmd // The last cmd returned.
}
// NewApp returns app instance with binary path in it
func NewApp(binPath string) *App {
return &App{BinaryPath: binPath}
}
// Cmd returns a command to run the app server using the current configuration.
func (a *App) Cmd() AppCmd {
a.cmd = NewAppCmd(a.BinaryPath, a.Port)
return a.cmd
}
// Kill the last app command returned.
func (a *App) Kill() {
a.cmd.Kill()
}
// AppCmd manages the running of a Revel app server.
// It requires revel.Init to have been called previously.
type AppCmd struct {
*exec.Cmd
}
// NewAppCmd returns the AppCmd with parameters initialized for running app
func NewAppCmd(binPath string, port int) AppCmd {
cmd := exec.Command(binPath,
fmt.Sprintf("-port=%d", port),
fmt.Sprintf("-importPath=%s", revel.ImportPath),
fmt.Sprintf("-runMode=%s", revel.RunMode))
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
return AppCmd{cmd}
}
// Start the app server, and wait until it is ready to serve requests.
func (cmd AppCmd) Start() error {
listeningWriter := startupListeningWriter{os.Stdout, make(chan bool)}
cmd.Stdout = listeningWriter
revel.TRACE.Println("Exec app:", cmd.Path, cmd.Args)
if err := cmd.Cmd.Start(); err != nil {
revel.ERROR.Fatalln("Error running:", err)
}
select {
case <-cmd.waitChan():
return errors.New("revel/harness: app died")
case <-time.After(30 * time.Second):
cmd.Kill()
return errors.New("revel/harness: app timed out")
case <-listeningWriter.notifyReady:
return nil
}
// TODO remove this unreachable code and document it
panic("Impossible")
}
// Run the app server inline. Never returns.
func (cmd AppCmd) Run() {
revel.TRACE.Println("Exec app:", cmd.Path, cmd.Args)
if err := cmd.Cmd.Run(); err != nil {
revel.ERROR.Fatalln("Error running:", err)
}
}
// Kill terminates the app server if it's running.
func (cmd AppCmd) Kill() {
if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
revel.TRACE.Println("Killing revel server pid", cmd.Process.Pid)
err := cmd.Process.Kill()
if err != nil {
revel.ERROR.Fatalln("Failed to kill revel server:", err)
}
}
}
// Return a channel that is notified when Wait() returns.
func (cmd AppCmd) waitChan() <-chan struct{} {
ch := make(chan struct{}, 1)
go func() {
_ = cmd.Wait()
ch <- struct{}{}
}()
return ch
}
// A io.Writer that copies to the destination, and listens for "Listening on.."
// in the stream. (Which tells us when the revel server has finished starting up)
// This is super ghetto, but by far the simplest thing that should work.
type startupListeningWriter struct {
dest io.Writer
notifyReady chan bool
}
func (w startupListeningWriter) Write(p []byte) (n int, err error) {
if w.notifyReady != nil && bytes.Contains(p, []byte("Listening")) {
w.notifyReady <- true
w.notifyReady = nil
}
return w.dest.Write(p)
}
+451
View File
@@ -0,0 +1,451 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
"fmt"
"go/build"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"text/template"
"time"
"github.com/revel/revel"
)
var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"")
// Build the app:
// 1. Generate the the main.go file.
// 2. Run the appropriate "go build" command.
// Requires that revel.Init has been called previously.
// Returns the path to the built binary, and an error if there was a problem building it.
func Build(buildFlags ...string) (app *App, compileError *revel.Error) {
// First, clear the generated files (to avoid them messing with ProcessSource).
cleanSource("tmp", "routes")
sourceInfo, compileError := ProcessSource(revel.CodePaths)
if compileError != nil {
return nil, compileError
}
// Add the db.import to the import paths.
if dbImportPath, found := revel.Config.String("db.import"); found {
sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths, dbImportPath)
}
// Generate two source files.
templateArgs := map[string]interface{}{
"Controllers": sourceInfo.ControllerSpecs(),
"ValidationKeys": sourceInfo.ValidationKeys,
"ImportPaths": calcImportAliases(sourceInfo),
"TestSuites": sourceInfo.TestSuites(),
}
// fmt.Println("revel.CodePaths", revel.CodePaths)
// fmt.Println("----genSource tmp")
genSource("tmp", "main.go", RevelMainTemplate, templateArgs)
// fmt.Println("-----genSource routes", templateArgs)
genSource("routes", "routes.go", RevelRoutesTemplate, templateArgs)
// Read build config.
buildTags := revel.Config.StringDefault("build.tags", "")
// Build the user program (all code under app).
// It relies on the user having "go" installed.
goPath, err := exec.LookPath("go")
if err != nil {
revel.ERROR.Fatalf("Go executable not found in PATH.")
}
pkg, err := build.Default.Import(revel.ImportPath, "", build.FindOnly)
if err != nil {
revel.ERROR.Fatalln("Failure importing", revel.ImportPath)
}
// Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name.
binName := filepath.Join(pkg.BinDir, "revel.d", revel.ImportPath, filepath.Base(revel.BasePath))
// Change binary path for Windows build
goos := runtime.GOOS
if goosEnv := os.Getenv("GOOS"); goosEnv != "" {
goos = goosEnv
}
if goos == "windows" {
binName += ".exe"
}
gotten := make(map[string]struct{})
for {
appVersion := getAppVersion()
buildTime := time.Now().UTC().Format(time.RFC3339)
versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s",
revel.ImportPath, appVersion, revel.ImportPath, buildTime)
// TODO remove version check for versionLinkerFlags after Revel becomes Go min version to go1.5
goVersion, err := strconv.ParseFloat(runtime.Version()[2:5], 64)
// runtime.Version() may return commit hash, we assume it is above 1.5
if goVersion < 1.5 && err == nil {
versionLinkerFlags = fmt.Sprintf("-X %s/app.AppVersion \"%s\" -X %s/app.BuildTime \"%s\"",
revel.ImportPath, appVersion, revel.ImportPath, buildTime)
}
flags := []string{
"build",
"-i",
"-ldflags", versionLinkerFlags,
"-tags", buildTags,
"-o", binName}
// Add in build flags
flags = append(flags, buildFlags...)
// This is Go main path
// Note: It's not applicable for filepath.* usage
flags = append(flags, path.Join(revel.ImportPath, "app", "tmp"))
buildCmd := exec.Command(goPath, flags...)
revel.TRACE.Println("Exec:", buildCmd.Args)
output, err := buildCmd.CombinedOutput()
// If the build succeeded, we're done.
if err == nil {
return NewApp(binName), nil
}
revel.ERROR.Println(string(output))
// See if it was an import error that we can go get.
matches := importErrorPattern.FindStringSubmatch(string(output))
if matches == nil {
return nil, newCompileError(output)
}
// Ensure we haven't already tried to go get it.
pkgName := matches[1]
if _, alreadyTried := gotten[pkgName]; alreadyTried {
return nil, newCompileError(output)
}
gotten[pkgName] = struct{}{}
// Execute "go get <pkg>"
getCmd := exec.Command(goPath, "get", pkgName)
revel.TRACE.Println("Exec:", getCmd.Args)
getOutput, err := getCmd.CombinedOutput()
if err != nil {
revel.ERROR.Println(string(getOutput))
return nil, newCompileError(output)
}
// Success getting the import, attempt to build again.
}
// TODO remove this unreachable code and document it
revel.ERROR.Fatalf("Not reachable")
return nil, nil
}
// Try to define a version string for the compiled app
// The following is tried (first match returns):
// - Read a version explicitly specified in the APP_VERSION environment
// variable
// - Read the output of "git describe" if the source is in a git repository
// If no version can be determined, an empty string is returned.
func getAppVersion() string {
if version := os.Getenv("APP_VERSION"); version != "" {
return version
}
// Check for the git binary
if gitPath, err := exec.LookPath("git"); err == nil {
// Check for the .git directory
gitDir := filepath.Join(revel.BasePath, ".git")
info, err := os.Stat(gitDir)
if (err != nil && os.IsNotExist(err)) || !info.IsDir() {
return ""
}
gitCmd := exec.Command(gitPath, "--git-dir="+gitDir, "describe", "--always", "--dirty")
revel.TRACE.Println("Exec:", gitCmd.Args)
output, err := gitCmd.Output()
if err != nil {
revel.WARN.Println("Cannot determine git repository version:", err)
return ""
}
return "git-" + strings.TrimSpace(string(output))
}
return ""
}
func cleanSource(dirs ...string) {
for _, dir := range dirs {
cleanDir(dir)
}
}
func cleanDir(dir string) {
revel.INFO.Println("Cleaning dir " + dir)
tmpPath := filepath.Join(revel.AppPath, dir)
f, err := os.Open(tmpPath)
if err != nil {
if !os.IsNotExist(err) {
revel.ERROR.Println("Failed to clean dir:", err)
}
} else {
defer func() {
_ = f.Close()
}()
infos, err := f.Readdir(0)
if err != nil {
if !os.IsNotExist(err) {
revel.ERROR.Println("Failed to clean dir:", err)
}
} else {
for _, info := range infos {
path := filepath.Join(tmpPath, info.Name())
if info.IsDir() {
err := os.RemoveAll(path)
if err != nil {
revel.ERROR.Println("Failed to remove dir:", err)
}
} else {
err := os.Remove(path)
if err != nil {
revel.ERROR.Println("Failed to remove file:", err)
}
}
}
}
}
}
// genSource renders the given template to produce source code, which it writes
// to the given directory and file.
func genSource(dir, filename, templateSource string, args map[string]interface{}) {
sourceCode := revel.ExecuteTemplate(
template.Must(template.New("").Parse(templateSource)),
args)
// Create a fresh dir.
cleanSource(dir)
tmpPath := filepath.Join(revel.AppPath, dir)
err := os.Mkdir(tmpPath, 0777)
if err != nil && !os.IsExist(err) {
revel.ERROR.Fatalf("Failed to make '%v' directory: %v", dir, err)
}
// Create the file
file, err := os.Create(filepath.Join(tmpPath, filename))
if err != nil {
revel.ERROR.Fatalf("Failed to create file: %v", err)
}
defer func() {
_ = file.Close()
}()
if _, err = file.WriteString(sourceCode); err != nil {
revel.ERROR.Fatalf("Failed to write to file: %v", err)
}
}
// Looks through all the method args and returns a set of unique import paths
// that cover all the method arg types.
// Additionally, assign package aliases when necessary to resolve ambiguity.
func calcImportAliases(src *SourceInfo) map[string]string {
aliases := make(map[string]string)
typeArrays := [][]*TypeInfo{src.ControllerSpecs(), src.TestSuites()}
for _, specs := range typeArrays {
for _, spec := range specs {
addAlias(aliases, spec.ImportPath, spec.PackageName)
for _, methSpec := range spec.MethodSpecs {
for _, methArg := range methSpec.Args {
if methArg.ImportPath == "" {
continue
}
addAlias(aliases, methArg.ImportPath, methArg.TypeExpr.PkgName)
}
}
}
}
// Add the "InitImportPaths", with alias "_"
for _, importPath := range src.InitImportPaths {
if _, ok := aliases[importPath]; !ok {
aliases[importPath] = "_"
}
}
return aliases
}
func addAlias(aliases map[string]string, importPath, pkgName string) {
alias, ok := aliases[importPath]
if ok {
return
}
alias = makePackageAlias(aliases, pkgName)
aliases[importPath] = alias
}
func makePackageAlias(aliases map[string]string, pkgName string) string {
i := 0
alias := pkgName
for containsValue(aliases, alias) || alias=="revel" {
alias = fmt.Sprintf("%s%d", pkgName, i)
i++
}
return alias
}
func containsValue(m map[string]string, val string) bool {
for _, v := range m {
if v == val {
return true
}
}
return false
}
// Parse the output of the "go build" command.
// Return a detailed Error.
func newCompileError(output []byte) *revel.Error {
errorMatch := regexp.MustCompile(`(?m)^([^:#]+):(\d+):(\d+:)? (.*)$`).
FindSubmatch(output)
if errorMatch == nil {
errorMatch = regexp.MustCompile(`(?m)^(.*?)\:(\d+)\:\s(.*?)$`).FindSubmatch(output)
if errorMatch == nil {
revel.ERROR.Println("Failed to parse build errors:\n", string(output))
return &revel.Error{
SourceType: "Go code",
Title: "Go Compilation Error",
Description: "See console for build error.",
}
}
errorMatch = append(errorMatch, errorMatch[3])
revel.ERROR.Println("Build errors:\n", string(output))
}
// Read the source for the offending file.
var (
relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go"
absFilename, _ = filepath.Abs(relFilename)
line, _ = strconv.Atoi(string(errorMatch[2]))
description = string(errorMatch[4])
compileError = &revel.Error{
SourceType: "Go code",
Title: "Go Compilation Error",
Path: relFilename,
Description: description,
Line: line,
}
)
errorLink := revel.Config.StringDefault("error.link", "")
if errorLink != "" {
compileError.SetLink(errorLink)
}
fileStr, err := revel.ReadLines(absFilename)
if err != nil {
compileError.MetaError = absFilename + ": " + err.Error()
revel.ERROR.Println(compileError.MetaError)
return compileError
}
compileError.SourceLines = fileStr
return compileError
}
// RevelMainTemplate template for app/tmp/main.go
const RevelMainTemplate = `// GENERATED CODE - DO NOT EDIT
package main
import (
"flag"
"reflect"
"github.com/revel/revel"{{range $k, $v := $.ImportPaths}}
{{$v}} "{{$k}}"{{end}}
"github.com/revel/revel/testing"
)
var (
runMode *string = flag.String("runMode", "", "Run mode.")
port *int = flag.Int("port", 0, "By default, read from app.conf")
importPath *string = flag.String("importPath", "", "Go Import Path for the app.")
srcPath *string = flag.String("srcPath", "", "Path to the source root.")
// So compiler won't complain if the generated code doesn't reference reflect package...
_ = reflect.Invalid
)
func main() {
flag.Parse()
revel.Init(*runMode, *importPath, *srcPath)
revel.INFO.Println("Running revel server")
{{range $i, $c := .Controllers}}
revel.RegisterController((*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),
[]*revel.MethodType{
{{range .MethodSpecs}}&revel.MethodType{
Name: "{{.Name}}",
Args: []*revel.MethodArg{ {{range .Args}}
&revel.MethodArg{Name: "{{.Name}}", Type: reflect.TypeOf((*{{index $.ImportPaths .ImportPath | .TypeExpr.TypeName}})(nil)) },{{end}}
},
RenderArgNames: map[int][]string{ {{range .RenderCalls}}
{{.Line}}: []string{ {{range .Names}}
"{{.}}",{{end}}
},{{end}}
},
},
{{end}}
})
{{end}}
revel.DefaultValidationKeys = map[string]map[int]string{ {{range $path, $lines := .ValidationKeys}}
"{{$path}}": { {{range $line, $key := $lines}}
{{$line}}: "{{$key}}",{{end}}
},{{end}}
}
testing.TestSuites = []interface{}{ {{range .TestSuites}}
(*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),{{end}}
}
revel.Run(*port)
}
`
// RevelRoutesTemplate template for app/conf/routes
const RevelRoutesTemplate = `// GENERATED CODE - DO NOT EDIT
package routes
import "github.com/revel/revel"
{{range $i, $c := .Controllers}}
type t{{.StructName}} struct {}
var {{.StructName}} t{{.StructName}}
{{range .MethodSpecs}}
func (_ t{{$c.StructName}}) {{.Name}}({{range .Args}}
{{.Name}} {{if .ImportPath}}interface{}{{else}}{{.TypeExpr.TypeName ""}}{{end}},{{end}}
) string {
args := make(map[string]string)
{{range .Args}}
revel.Unbind(args, "{{.Name}}", {{.Name}}){{end}}
return revel.MainRouter.Reverse("{{$c.StructName}}.{{.Name}}", args).URL
}
{{end}}
{{end}}
`
+271
View File
@@ -0,0 +1,271 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// Package harness for a Revel Framework.
//
// It has a following responsibilities:
// 1. Parse the user program, generating a main.go file that registers
// controller classes and starts the user's server.
// 2. Build and run the user program. Show compile errors.
// 3. Monitor the user source and re-build / restart the program when necessary.
//
// Source files are generated in the app/tmp directory.
package harness
import (
"crypto/tls"
"fmt"
"go/build"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"sync/atomic"
"github.com/revel/revel"
)
var (
watcher *revel.Watcher
doNotWatch = []string{"tmp", "views", "routes"}
lastRequestHadError int32
)
// Harness reverse proxies requests to the application server.
// It builds / runs / rebuilds / restarts the server when code is changed.
type Harness struct {
app *App
serverHost string
port int
proxy *httputil.ReverseProxy
}
func renderError(w http.ResponseWriter, r *http.Request, err error) {
req, resp := revel.NewRequest(r), revel.NewResponse(w)
c := revel.NewController(req, resp)
c.RenderError(err).Apply(req, resp)
}
// ServeHTTP handles all requests.
// It checks for changes to app, rebuilds if necessary, and forwards the request.
func (h *Harness) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Don't rebuild the app for favicon requests.
if lastRequestHadError > 0 && r.URL.Path == "/favicon.ico" {
return
}
// Flush any change events and rebuild app if necessary.
// Render an error page if the rebuild / restart failed.
err := watcher.Notify()
if err != nil {
atomic.CompareAndSwapInt32(&lastRequestHadError, 0, 1)
renderError(w, r, err)
return
}
atomic.CompareAndSwapInt32(&lastRequestHadError, 1, 0)
// Reverse proxy the request.
// (Need special code for websockets, courtesy of bradfitz)
if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") {
proxyWebsocket(w, r, h.serverHost)
} else {
h.proxy.ServeHTTP(w, r)
}
}
// NewHarness method returns a reverse proxy that forwards requests
// to the given port.
func NewHarness() *Harness {
// Get a template loader to render errors.
// Prefer the app's views/errors directory, and fall back to the stock error pages.
revel.MainTemplateLoader = revel.NewTemplateLoader(
[]string{filepath.Join(revel.RevelPath, "templates")})
if err := revel.MainTemplateLoader.Refresh(); err != nil {
revel.ERROR.Println(err)
}
// fmt.Println("-----revel.RevelPath", revel.RevelPath)
addr := revel.HTTPAddr
port := revel.Config.IntDefault("harness.port", 0)
scheme := "http"
if revel.HTTPSsl {
scheme = "https"
}
// If the server is running on the wildcard address, use "localhost"
if addr == "" {
addr = "localhost"
}
if port == 0 {
port = getFreePort()
}
serverURL, _ := url.ParseRequestURI(fmt.Sprintf(scheme+"://%s:%d", addr, port))
harness := &Harness{
port: port,
serverHost: serverURL.String()[len(scheme+"://"):],
proxy: httputil.NewSingleHostReverseProxy(serverURL),
}
if revel.HTTPSsl {
harness.proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}
return harness
}
// Refresh method rebuilds the Revel application and run it on the given port.
func (h *Harness) Refresh() (err *revel.Error) {
if h.app != nil {
h.app.Kill()
}
revel.TRACE.Println("Rebuild")
h.app, err = Build()
if err != nil {
return
}
h.app.Port = h.port
if err2 := h.app.Cmd().Start(); err2 != nil {
return &revel.Error{
Title: "App failed to start up",
Description: err2.Error(),
}
}
return
}
// WatchDir method returns false to file matches with doNotWatch
// otheriwse true
func (h *Harness) WatchDir(info os.FileInfo) bool {
return !revel.ContainsString(doNotWatch, info.Name())
}
// WatchFile method returns true given filename HasSuffix of ".go"
// otheriwse false
func (h *Harness) WatchFile(filename string) bool {
return strings.HasSuffix(filename, ".go")
}
// Run the harness, which listens for requests and proxies them to the app
// server, which it runs and rebuilds as necessary.
func (h *Harness) Run() {
var paths []string
if revel.Config.BoolDefault("watch.gopath", false) {
gopaths := filepath.SplitList(build.Default.GOPATH)
paths = append(paths, gopaths...)
}
paths = append(paths, revel.CodePaths...)
watcher = revel.NewWatcher()
watcher.Listen(h, paths...)
go func() {
addr := fmt.Sprintf("%s:%d", revel.HTTPAddr, revel.HTTPPort)
revel.INFO.Printf("Listening on %s", addr)
var err error
if revel.HTTPSsl {
err = http.ListenAndServeTLS(
addr,
revel.HTTPSslCert,
revel.HTTPSslKey,
h)
} else {
err = http.ListenAndServe(addr, h)
}
if err != nil {
revel.ERROR.Fatalln("Failed to start reverse proxy:", err)
}
}()
// Kill the app on signal.
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, os.Kill)
<-ch
if h.app != nil {
h.app.Kill()
}
os.Exit(1)
}
// Find an unused port
func getFreePort() (port int) {
conn, err := net.Listen("tcp", ":0")
if err != nil {
revel.ERROR.Fatal(err)
}
port = conn.Addr().(*net.TCPAddr).Port
err = conn.Close()
if err != nil {
revel.ERROR.Fatal(err)
}
return port
}
// proxyWebsocket copies data between websocket client and server until one side
// closes the connection. (ReverseProxy doesn't work with websocket requests.)
func proxyWebsocket(w http.ResponseWriter, r *http.Request, host string) {
var (
d net.Conn
err error
)
if revel.HTTPSsl {
// since this proxy isn't used in production,
// it's OK to set InsecureSkipVerify to true
// no need to add another configuration option.
d, err = tls.Dial("tcp", host, &tls.Config{InsecureSkipVerify: true})
} else {
d, err = net.Dial("tcp", host)
}
if err != nil {
http.Error(w, "Error contacting backend server.", 500)
revel.ERROR.Printf("Error dialing websocket backend %s: %v", host, err)
return
}
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Not a hijacker?", 500)
return
}
nc, _, err := hj.Hijack()
if err != nil {
revel.ERROR.Printf("Hijack error: %v", err)
return
}
defer func() {
if err = nc.Close(); err != nil {
revel.ERROR.Println(err)
}
if err = d.Close(); err != nil {
revel.ERROR.Println(err)
}
}()
err = r.Write(d)
if err != nil {
revel.ERROR.Printf("Error copying request to target: %v", err)
return
}
errc := make(chan error, 2)
cp := func(dst io.Writer, src io.Reader) {
_, err := io.Copy(dst, src)
errc <- err
}
go cp(d, nc)
go cp(nc, d)
<-errc
}
+804
View File
@@ -0,0 +1,804 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
// This file handles the app code introspection.
// It catalogs the controllers, their methods, and their arguments.
import (
"go/ast"
"go/build"
"go/parser"
"go/scanner"
"go/token"
"log"
"os"
"path/filepath"
"strings"
"github.com/revel/revel"
// "fmt"
)
// life
var MRevelImportPath = "github.com/revel/revel"
// SourceInfo is the top-level struct containing all extracted information
// about the app source code, used to generate main.go.
type SourceInfo struct {
// StructSpecs lists type info for all structs found under the code paths.
// They may be queried to determine which ones (transitively) embed certain types.
StructSpecs []*TypeInfo
// ValidationKeys provides a two-level lookup. The keys are:
// 1. The fully-qualified function name,
// e.g. "github.com/revel/examples/chat/app/controllers.(*Application).Action"
// 2. Within that func's file, the line number of the (overall) expression statement.
// e.g. the line returned from runtime.Caller()
// The result of the lookup the name of variable being validated.
ValidationKeys map[string]map[int]string
// A list of import paths.
// Revel notices files with an init() function and imports that package.
InitImportPaths []string
// controllerSpecs lists type info for all structs found under
// app/controllers/... that embed (directly or indirectly) revel.Controller
controllerSpecs []*TypeInfo
// testSuites list the types that constitute the set of application tests.
testSuites []*TypeInfo
}
// TypeInfo summarizes information about a struct type in the app source code.
type TypeInfo struct {
StructName string // e.g. "Application"
ImportPath string // e.g. "github.com/revel/examples/chat/app/controllers"
PackageName string // e.g. "controllers"
MethodSpecs []*MethodSpec
// Used internally to identify controllers that indirectly embed *revel.Controller.
embeddedTypes []*embeddedTypeName
}
// methodCall describes a call to c.Render(..)
// It documents the argument names used, in order to propagate them to RenderArgs.
type methodCall struct {
Path string // e.g. "myapp/app/controllers.(*Application).Action"
Line int
Names []string
}
// MethodSpec holds the information of one Method
type MethodSpec struct {
Name string // Name of the method, e.g. "Index"
Args []*MethodArg // Argument descriptors
RenderCalls []*methodCall // Descriptions of Render() invocations from this Method.
}
// MethodArg holds the information of one argument
type MethodArg struct {
Name string // Name of the argument.
TypeExpr TypeExpr // The name of the type, e.g. "int", "*pkg.UserType"
ImportPath string // If the arg is of an imported type, this is the import path.
}
type embeddedTypeName struct {
ImportPath, StructName string
}
// Maps a controller simple name (e.g. "Login") to the methods for which it is a
// receiver.
type methodMap map[string][]*MethodSpec
// ProcessSource parses the app controllers directory and
// returns a list of the controller types found.
// Otherwise CompileError if the parsing fails.
func ProcessSource(roots []string) (*SourceInfo, *revel.Error) {
var (
srcInfo *SourceInfo
compileError *revel.Error
)
// fmt.Println("****roots", roots)
for _, root := range roots {
rootImportPath := importPathFromPath(root)
if rootImportPath == "" {
revel.WARN.Println("Skipping code path", root)
continue
}
// Start walking the directory tree.
_ = revel.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Println("Error scanning app source:", err)
return nil
}
if !info.IsDir() || info.Name() == "tmp" {
return nil
}
// Get the import path of the package.
pkgImportPath := rootImportPath
if root != path {
pkgImportPath = rootImportPath + "/" + filepath.ToSlash(path[len(root)+1:])
}
// Parse files within the path.
var pkgs map[string]*ast.Package
fset := token.NewFileSet()
pkgs, err = parser.ParseDir(fset, path, func(f os.FileInfo) bool {
return !f.IsDir() && !strings.HasPrefix(f.Name(), ".") && strings.HasSuffix(f.Name(), ".go")
}, 0)
if err != nil {
if errList, ok := err.(scanner.ErrorList); ok {
var pos = errList[0].Pos
compileError = &revel.Error{
SourceType: ".go source",
Title: "Go Compilation Error",
Path: pos.Filename,
Description: errList[0].Msg,
Line: pos.Line,
Column: pos.Column,
SourceLines: revel.MustReadLines(pos.Filename),
}
errorLink := revel.Config.StringDefault("error.link", "")
if errorLink != "" {
compileError.SetLink(errorLink)
}
return compileError
}
// This is exception, err alredy checked above. Here just a print
ast.Print(nil, err)
log.Fatalf("Failed to parse dir: %s", err)
}
// Skip "main" packages.
delete(pkgs, "main")
// If there is no code in this directory, skip it.
if len(pkgs) == 0 {
return nil
}
// There should be only one package in this directory.
if len(pkgs) > 1 {
log.Println("Most unexpected! Multiple packages in a single directory:", pkgs)
}
var pkg *ast.Package
for _, v := range pkgs {
pkg = v
}
srcInfo = appendSourceInfo(srcInfo, processPackage(fset, pkgImportPath, path, pkg))
return nil
})
}
return srcInfo, compileError
}
func appendSourceInfo(srcInfo1, srcInfo2 *SourceInfo) *SourceInfo {
if srcInfo1 == nil {
return srcInfo2
}
srcInfo1.StructSpecs = append(srcInfo1.StructSpecs, srcInfo2.StructSpecs...)
srcInfo1.InitImportPaths = append(srcInfo1.InitImportPaths, srcInfo2.InitImportPaths...)
for k, v := range srcInfo2.ValidationKeys {
if _, ok := srcInfo1.ValidationKeys[k]; ok {
log.Println("Key conflict when scanning validation calls:", k)
continue
}
srcInfo1.ValidationKeys[k] = v
}
return srcInfo1
}
func processPackage(fset *token.FileSet, pkgImportPath, pkgPath string, pkg *ast.Package) *SourceInfo {
var (
structSpecs []*TypeInfo
initImportPaths []string
methodSpecs = make(methodMap)
validationKeys = make(map[string]map[int]string)
scanControllers = strings.HasSuffix(pkgImportPath, "/controllers") ||
strings.Contains(pkgImportPath, "/controllers/")
scanTests = strings.HasSuffix(pkgImportPath, "/tests") ||
strings.Contains(pkgImportPath, "/tests/")
)
// For each source file in the package...
for _, file := range pkg.Files {
// Imports maps the package key to the full import path.
// e.g. import "sample/app/models" => "models": "sample/app/models"
imports := map[string]string{}
// For each declaration in the source file...
for _, decl := range file.Decls {
addImports(imports, decl, pkgPath)
if scanControllers {
// Match and add both structs and methods
structSpecs = appendStruct(structSpecs, pkgImportPath, pkg, decl, imports, fset)
appendAction(fset, methodSpecs, decl, pkgImportPath, pkg.Name, imports)
} else if scanTests {
structSpecs = appendStruct(structSpecs, pkgImportPath, pkg, decl, imports, fset)
}
// If this is a func...
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
// Scan it for validation calls
lineKeys := getValidationKeys(fset, funcDecl, imports)
if len(lineKeys) > 0 {
validationKeys[pkgImportPath+"."+getFuncName(funcDecl)] = lineKeys
}
// Check if it's an init function.
if funcDecl.Name.Name == "init" {
initImportPaths = []string{pkgImportPath}
}
}
}
}
// Add the method specs to the struct specs.
for _, spec := range structSpecs {
spec.MethodSpecs = methodSpecs[spec.StructName]
}
return &SourceInfo{
StructSpecs: structSpecs,
ValidationKeys: validationKeys,
InitImportPaths: initImportPaths,
}
}
// getFuncName returns a name for this func or method declaration.
// e.g. "(*Application).SayHello" for a method, "SayHello" for a func.
func getFuncName(funcDecl *ast.FuncDecl) string {
prefix := ""
if funcDecl.Recv != nil {
recvType := funcDecl.Recv.List[0].Type
if recvStarType, ok := recvType.(*ast.StarExpr); ok {
prefix = "(*" + recvStarType.X.(*ast.Ident).Name + ")"
} else {
prefix = recvType.(*ast.Ident).Name
}
prefix += "."
}
return prefix + funcDecl.Name.Name
}
func addImports(imports map[string]string, decl ast.Decl, srcDir string) {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
return
}
if genDecl.Tok != token.IMPORT {
return
}
for _, spec := range genDecl.Specs {
importSpec := spec.(*ast.ImportSpec)
var pkgAlias string
if importSpec.Name != nil {
pkgAlias = importSpec.Name.Name
if pkgAlias == "_" {
continue
}
}
quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes
// If the package was not aliased (common case), we have to import it
// to see what the package name is.
// TODO: Can improve performance here a lot:
// 1. Do not import everything over and over again. Keep a cache.
// 2. Exempt the standard library; their directories always match the package name.
// 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly
if pkgAlias == "" {
pkg, err := build.Import(fullPath, srcDir, 0)
if err != nil {
// We expect this to happen for apps using reverse routing (since we
// have not yet generated the routes). Don't log that.
if !strings.HasSuffix(fullPath, "/app/routes") {
revel.TRACE.Println("Could not find import:", fullPath)
}
continue
}
pkgAlias = pkg.Name
}
imports[pkgAlias] = fullPath
}
}
// If this Decl is a struct type definition, it is summarized and added to specs.
// Else, specs is returned unchanged.
func appendStruct(specs []*TypeInfo, pkgImportPath string, pkg *ast.Package, decl ast.Decl, imports map[string]string, fset *token.FileSet) []*TypeInfo {
// Filter out non-Struct type declarations.
spec, found := getStructTypeDecl(decl, fset)
if !found {
return specs
}
structType := spec.Type.(*ast.StructType)
// At this point we know it's a type declaration for a struct.
// Fill in the rest of the info by diving into the fields.
// Add it provisionally to the Controller list -- it's later filtered using field info.
controllerSpec := &TypeInfo{
StructName: spec.Name.Name,
ImportPath: pkgImportPath,
PackageName: pkg.Name,
}
for _, field := range structType.Fields.List {
// If field.Names is set, it's not an embedded type.
if field.Names != nil {
continue
}
// A direct "sub-type" has an ast.Field as either:
// Ident { "AppController" }
// SelectorExpr { "rev", "Controller" }
// Additionally, that can be wrapped by StarExprs.
fieldType := field.Type
pkgName, typeName := func() (string, string) {
// Drill through any StarExprs.
for {
if starExpr, ok := fieldType.(*ast.StarExpr); ok {
fieldType = starExpr.X
continue
}
break
}
// If the embedded type is in the same package, it's an Ident.
if ident, ok := fieldType.(*ast.Ident); ok {
return "", ident.Name
}
if selectorExpr, ok := fieldType.(*ast.SelectorExpr); ok {
if pkgIdent, ok := selectorExpr.X.(*ast.Ident); ok {
return pkgIdent.Name, selectorExpr.Sel.Name
}
}
return "", ""
}()
// If a typename wasn't found, skip it.
if typeName == "" {
continue
}
// Find the import path for this type.
// If it was referenced without a package name, use the current package import path.
// Else, look up the package's import path by name.
var importPath string
if pkgName == "" {
importPath = pkgImportPath
} else {
var ok bool
if importPath, ok = imports[pkgName]; !ok {
log.Print("Failed to find import path for ", pkgName, ".", typeName)
continue
}
}
controllerSpec.embeddedTypes = append(controllerSpec.embeddedTypes, &embeddedTypeName{
ImportPath: importPath,
StructName: typeName,
})
}
return append(specs, controllerSpec)
}
// If decl is a Method declaration, it is summarized and added to the array
// underneath its receiver type.
// e.g. "Login" => {MethodSpec, MethodSpec, ..}
func appendAction(fset *token.FileSet, mm methodMap, decl ast.Decl, pkgImportPath, pkgName string, imports map[string]string) {
// Func declaration?
funcDecl, ok := decl.(*ast.FuncDecl)
if !ok {
return
}
// Have a receiver?
if funcDecl.Recv == nil {
return
}
// Is it public?
if !funcDecl.Name.IsExported() {
return
}
// Does it return a Result?
if funcDecl.Type.Results == nil || len(funcDecl.Type.Results.List) != 1 {
return
}
selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr)
if !ok {
return
}
if selExpr.Sel.Name != "Result" {
return
}
if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || imports[pkgIdent.Name] != MRevelImportPath {
return
}
method := &MethodSpec{
Name: funcDecl.Name.Name,
}
// Add a description of the arguments to the method.
for _, field := range funcDecl.Type.Params.List {
for _, name := range field.Names {
var importPath string
typeExpr := NewTypeExpr(pkgName, field.Type)
if !typeExpr.Valid {
log.Printf("Didn't understand argument '%s' of action %s. Ignoring.\n", name, getFuncName(funcDecl))
return // We didn't understand one of the args. Ignore this action.
}
if typeExpr.PkgName != "" {
var ok bool
if importPath, ok = imports[typeExpr.PkgName]; !ok {
log.Println("Failed to find import for arg of type:", typeExpr.TypeName(""))
}
}
method.Args = append(method.Args, &MethodArg{
Name: name.Name,
TypeExpr: typeExpr,
ImportPath: importPath,
})
}
}
// Add a description of the calls to Render from the method.
// Inspect every node (e.g. always return true).
method.RenderCalls = []*methodCall{}
ast.Inspect(funcDecl.Body, func(node ast.Node) bool {
// Is it a function call?
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
// Is it calling (*Controller).Render?
selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
// The type of the receiver is not easily available, so just store every
// call to any method called Render.
if selExpr.Sel.Name != "Render" {
return true
}
// Add this call's args to the renderArgs.
pos := fset.Position(callExpr.Rparen)
methodCall := &methodCall{
Line: pos.Line,
Names: []string{},
}
for _, arg := range callExpr.Args {
argIdent, ok := arg.(*ast.Ident)
if !ok {
continue
}
methodCall.Names = append(methodCall.Names, argIdent.Name)
}
method.RenderCalls = append(method.RenderCalls, methodCall)
return true
})
var recvTypeName string
var recvType = funcDecl.Recv.List[0].Type
if recvStarType, ok := recvType.(*ast.StarExpr); ok {
recvTypeName = recvStarType.X.(*ast.Ident).Name
} else {
recvTypeName = recvType.(*ast.Ident).Name
}
mm[recvTypeName] = append(mm[recvTypeName], method)
}
// Scan app source code for calls to X.Y(), where X is of type *Validation.
//
// Recognize these scenarios:
// - "Y" = "Validation" and is a member of the receiver.
// (The common case for inline validation)
// - "X" is passed in to the func as a parameter.
// (For structs implementing Validated)
//
// The line number to which a validation call is attributed is that of the
// surrounding ExprStmt. This is so that it matches what runtime.Callers()
// reports.
//
// The end result is that we can set the default validation key for each call to
// be the same as the local variable.
func getValidationKeys(fset *token.FileSet, funcDecl *ast.FuncDecl, imports map[string]string) map[int]string {
var (
lineKeys = make(map[int]string)
// Check the func parameters and the receiver's members for the *revel.Validation type.
validationParam = getValidationParameter(funcDecl, imports)
)
ast.Inspect(funcDecl.Body, func(node ast.Node) bool {
// e.g. c.Validation.Required(arg) or v.Required(arg)
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
// e.g. c.Validation.Required or v.Required
funcSelector, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
switch x := funcSelector.X.(type) {
case *ast.SelectorExpr: // e.g. c.Validation
if x.Sel.Name != "Validation" {
return true
}
case *ast.Ident: // e.g. v
if validationParam == nil || x.Obj != validationParam {
return true
}
default:
return true
}
if len(callExpr.Args) == 0 {
return true
}
// Given the validation expression, extract the key.
key := callExpr.Args[0]
switch expr := key.(type) {
case *ast.BinaryExpr:
// If the argument is a binary expression, take the first expression.
// (e.g. c.Validation.Required(myName != ""))
key = expr.X
case *ast.UnaryExpr:
// If the argument is a unary expression, drill in.
// (e.g. c.Validation.Required(!myBool)
key = expr.X
case *ast.BasicLit:
// If it's a literal, skip it.
return true
}
if typeExpr := NewTypeExpr("", key); typeExpr.Valid {
lineKeys[fset.Position(callExpr.End()).Line] = typeExpr.TypeName("")
}
return true
})
return lineKeys
}
// Check to see if there is a *revel.Validation as an argument.
func getValidationParameter(funcDecl *ast.FuncDecl, imports map[string]string) *ast.Object {
for _, field := range funcDecl.Type.Params.List {
starExpr, ok := field.Type.(*ast.StarExpr) // e.g. *revel.Validation
if !ok {
continue
}
selExpr, ok := starExpr.X.(*ast.SelectorExpr) // e.g. revel.Validation
if !ok {
continue
}
xIdent, ok := selExpr.X.(*ast.Ident) // e.g. rev
if !ok {
continue
}
if selExpr.Sel.Name == "Validation" && imports[xIdent.Name] == MRevelImportPath {
return field.Names[0].Obj
}
}
return nil
}
func (s *TypeInfo) String() string {
return s.ImportPath + "." + s.StructName
}
func (s *embeddedTypeName) String() string {
return s.ImportPath + "." + s.StructName
}
// getStructTypeDecl checks if the given decl is a type declaration for a
// struct. If so, the TypeSpec is returned.
func getStructTypeDecl(decl ast.Decl, fset *token.FileSet) (spec *ast.TypeSpec, found bool) {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
return
}
if genDecl.Tok != token.TYPE {
return
}
if len(genDecl.Specs) == 0 {
revel.WARN.Printf("Surprising: %s:%d Decl contains no specifications", fset.Position(decl.Pos()).Filename, fset.Position(decl.Pos()).Line)
return
}
spec = genDecl.Specs[0].(*ast.TypeSpec)
_, found = spec.Type.(*ast.StructType)
return
}
// TypesThatEmbed returns all types that (directly or indirectly) embed the
// target type, which must be a fully qualified type name,
// e.g. "github.com/revel/revel.Controller"
func (s *SourceInfo) TypesThatEmbed(targetType string) (filtered []*TypeInfo) {
// Do a search in the "embedded type graph", starting with the target type.
var (
nodeQueue = []string{targetType}
processed []string
)
for len(nodeQueue) > 0 {
controllerSimpleName := nodeQueue[0]
nodeQueue = nodeQueue[1:]
processed = append(processed, controllerSimpleName)
// Look through all known structs.
for _, spec := range s.StructSpecs {
// If this one has been processed or is already in nodeQueue, then skip it.
if revel.ContainsString(processed, spec.String()) ||
revel.ContainsString(nodeQueue, spec.String()) {
continue
}
// Look through the embedded types to see if the current type is among them.
for _, embeddedType := range spec.embeddedTypes {
// If so, add this type's simple name to the nodeQueue, and its spec to
// the filtered list.
if controllerSimpleName == embeddedType.String() {
nodeQueue = append(nodeQueue, spec.String())
filtered = append(filtered, spec)
break
}
}
}
}
return
}
// ControllerSpecs returns the all the contollers that embeds
// `revel.Controller`
func (s *SourceInfo) ControllerSpecs() []*TypeInfo {
// fmt.Println("_____RevelImportPath", MRevelImportPath)
if s.controllerSpecs == nil {
// fmt.Println("_____RevelImportPath", MRevelImportPath)
s.controllerSpecs = s.TypesThatEmbed(MRevelImportPath + ".Controller")
}
return s.controllerSpecs
}
// TestSuites returns the all the Application tests that embeds
// `testing.TestSuite`
func (s *SourceInfo) TestSuites() []*TypeInfo {
if s.testSuites == nil {
s.testSuites = s.TypesThatEmbed(MRevelImportPath + "/testing.TestSuite")
}
return s.testSuites
}
// TypeExpr provides a type name that may be rewritten to use a package name.
type TypeExpr struct {
Expr string // The unqualified type expression, e.g. "[]*MyType"
PkgName string // The default package idenifier
pkgIndex int // The index where the package identifier should be inserted.
Valid bool
}
// TypeName returns the fully-qualified type name for this expression.
// The caller may optionally specify a package name to override the default.
func (e TypeExpr) TypeName(pkgOverride string) string {
pkgName := revel.FirstNonEmpty(pkgOverride, e.PkgName)
if pkgName == "" {
return e.Expr
}
return e.Expr[:e.pkgIndex] + pkgName + "." + e.Expr[e.pkgIndex:]
}
// NewTypeExpr returns the syntactic expression for referencing this type in Go.
func NewTypeExpr(pkgName string, expr ast.Expr) TypeExpr {
switch t := expr.(type) {
case *ast.Ident:
if IsBuiltinType(t.Name) {
pkgName = ""
}
return TypeExpr{t.Name, pkgName, 0, true}
case *ast.SelectorExpr:
e := NewTypeExpr(pkgName, t.X)
return TypeExpr{t.Sel.Name, e.Expr, 0, e.Valid}
case *ast.StarExpr:
e := NewTypeExpr(pkgName, t.X)
return TypeExpr{"*" + e.Expr, e.PkgName, e.pkgIndex + 1, e.Valid}
case *ast.ArrayType:
e := NewTypeExpr(pkgName, t.Elt)
return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid}
case *ast.Ellipsis:
e := NewTypeExpr(pkgName, t.Elt)
return TypeExpr{"[]" + e.Expr, e.PkgName, e.pkgIndex + 2, e.Valid}
default:
log.Println("Failed to generate name for field. Make sure the field name is valid.")
}
return TypeExpr{Valid: false}
}
var builtInTypes = map[string]struct{}{
"bool": {},
"byte": {},
"complex128": {},
"complex64": {},
"error": {},
"float32": {},
"float64": {},
"int": {},
"int16": {},
"int32": {},
"int64": {},
"int8": {},
"rune": {},
"string": {},
"uint": {},
"uint16": {},
"uint32": {},
"uint64": {},
"uint8": {},
"uintptr": {},
}
// IsBuiltinType checks the given type is built-in types of Go
func IsBuiltinType(name string) bool {
_, ok := builtInTypes[name]
return ok
}
func importPathFromPath(root string) string {
vendoringPath := revel.BasePath + "/vendor/"
if strings.HasPrefix(root, vendoringPath) {
return filepath.ToSlash(root[len(vendoringPath):])
}
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
srcPath := filepath.Join(gopath, "src")
if strings.HasPrefix(root, srcPath) {
return filepath.ToSlash(root[len(srcPath)+1:])
}
}
srcPath := filepath.Join(build.Default.GOROOT, "src", "pkg")
if strings.HasPrefix(root, srcPath) {
revel.WARN.Println("Code path should be in GOPATH, but is in GOROOT:", root)
return filepath.ToSlash(root[len(srcPath)+1:])
}
revel.ERROR.Println("Unexpected! Code path is not in GOPATH:", root)
return ""
}
+195
View File
@@ -0,0 +1,195 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package harness
import (
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"log"
"reflect"
"strings"
"testing"
"github.com/revel/revel"
)
const validationKeysSource = `
package test
func (c *Application) testFunc(a, b int, user models.User) revel.Result {
// Line 5
c.Validation.Required(a)
c.Validation.Required(a).Message("Error message")
c.Validation.Required(a).
Message("Error message")
// Line 11
c.Validation.Required(user.Name)
c.Validation.Required(user.Name).Message("Error message")
// Line 15
c.Validation.MinSize(b, 12)
c.Validation.MinSize(b, 12).Message("Error message")
c.Validation.MinSize(b,
12)
// Line 21
c.Validation.Required(b == 5)
}
func (m Model) Validate(v *revel.Validation) {
// Line 26
v.Required(m.name)
v.Required(m.name == "something").
Message("Error Message")
v.Required(!m.bool)
}
`
var expectedValidationKeys = []map[int]string{
{
6: "a",
7: "a",
8: "a",
12: "user.Name",
13: "user.Name",
16: "b",
17: "b",
19: "b",
22: "b",
}, {
27: "m.name",
28: "m.name",
30: "m.bool",
},
}
// This tests the recording of line number to validation key of the preceeding
// example source.
func TestGetValidationKeys(t *testing.T) {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "validationKeysSource", validationKeysSource, 0)
if err != nil {
t.Fatal(err)
}
if len(file.Decls) != 2 {
t.Fatal("Expected 2 decl in the source, found", len(file.Decls))
}
for i, decl := range file.Decls {
lineKeys := getValidationKeys(fset, decl.(*ast.FuncDecl), map[string]string{"revel": revel.RevelImportPath})
for k, v := range expectedValidationKeys[i] {
if lineKeys[k] != v {
t.Errorf("Not found - %d: %v - Actual Map: %v", k, v, lineKeys)
}
}
if len(lineKeys) != len(expectedValidationKeys[i]) {
t.Error("Validation key map not the same size as expected:", lineKeys)
}
}
}
var TypeExprs = map[string]TypeExpr{
"int": {"int", "", 0, true},
"*int": {"*int", "", 1, true},
"[]int": {"[]int", "", 2, true},
"...int": {"[]int", "", 2, true},
"[]*int": {"[]*int", "", 3, true},
"...*int": {"[]*int", "", 3, true},
"MyType": {"MyType", "pkg", 0, true},
"*MyType": {"*MyType", "pkg", 1, true},
"[]MyType": {"[]MyType", "pkg", 2, true},
"...MyType": {"[]MyType", "pkg", 2, true},
"[]*MyType": {"[]*MyType", "pkg", 3, true},
"...*MyType": {"[]*MyType", "pkg", 3, true},
}
func TestTypeExpr(t *testing.T) {
for typeStr, expected := range TypeExprs {
// Handle arrays and ... myself, since ParseExpr() does not.
array := strings.HasPrefix(typeStr, "[]")
if array {
typeStr = typeStr[2:]
}
ellipsis := strings.HasPrefix(typeStr, "...")
if ellipsis {
typeStr = typeStr[3:]
}
expr, err := parser.ParseExpr(typeStr)
if err != nil {
t.Error("Failed to parse test expr:", typeStr)
continue
}
if array {
expr = &ast.ArrayType{Lbrack: expr.Pos(), Len: nil, Elt: expr}
}
if ellipsis {
expr = &ast.Ellipsis{Ellipsis: expr.Pos(), Elt: expr}
}
actual := NewTypeExpr("pkg", expr)
if !reflect.DeepEqual(expected, actual) {
t.Error("Fail, expected", expected, ", was", actual)
}
}
}
func TestProcessBookingSource(t *testing.T) {
revel.Init("prod", "github.com/revel/examples/booking", "")
sourceInfo, err := ProcessSource([]string{revel.AppPath})
if err != nil {
t.Fatal("Failed to process booking source with error:", err)
}
controllerPackage := "github.com/revel/examples/booking/app/controllers"
expectedControllerSpecs := []*TypeInfo{
{"GorpController", controllerPackage, "controllers", nil, nil},
{"Application", controllerPackage, "controllers", nil, nil},
{"Hotels", controllerPackage, "controllers", nil, nil},
}
if len(sourceInfo.ControllerSpecs()) != len(expectedControllerSpecs) {
t.Errorf("Unexpected number of controllers found. Expected %d, Found %d",
len(expectedControllerSpecs), len(sourceInfo.ControllerSpecs()))
}
NEXT_TEST:
for _, expected := range expectedControllerSpecs {
for _, actual := range sourceInfo.ControllerSpecs() {
if actual.StructName == expected.StructName {
if actual.ImportPath != expected.ImportPath {
t.Errorf("%s expected to have import path %s, actual %s",
actual.StructName, expected.ImportPath, actual.ImportPath)
}
if actual.PackageName != expected.PackageName {
t.Errorf("%s expected to have package name %s, actual %s",
actual.StructName, expected.PackageName, actual.PackageName)
}
continue NEXT_TEST
}
}
t.Errorf("Expected to find controller %s, but did not. Actuals: %s",
expected.StructName, sourceInfo.ControllerSpecs())
}
}
func BenchmarkProcessBookingSource(b *testing.B) {
revel.Init("", "github.com/revel/examples/booking", "")
revel.TRACE = log.New(ioutil.Discard, "", 0)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := ProcessSource(revel.CodePaths)
if err != nil {
b.Error("Unexpected error:", err)
}
}
}
+130
View File
@@ -0,0 +1,130 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/leanote/leanote/cmd/harness"
"github.com/revel/revel"
)
var cmdBuild = &Command{
UsageLine: "build [import path] [target path] [run mode]",
Short: "build a Revel application (e.g. for deployment)",
Long: `
Build the Revel web application named by the given import path.
This allows it to be deployed and run on a machine that lacks a Go installation.
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
Run mode defaults to "dev".
WARNING: The target path will be completely deleted, if it already exists!
For example:
revel build github.com/revel/examples/chat /tmp/chat
`,
}
func init() {
cmdBuild.Run = buildApp
}
func buildApp(args []string) {
if len(args) < 2 {
fmt.Fprintf(os.Stderr, "%s\n%s", cmdBuild.UsageLine, cmdBuild.Long)
return
}
appImportPath, destPath, mode := args[0], args[1], DefaultRunMode
if len(args) >= 3 {
mode = args[2]
}
if !revel.Initialized {
revel.Init(mode, appImportPath, "")
}
// First, verify that it is either already empty or looks like a previous
// build (to avoid clobbering anything)
if exists(destPath) && !empty(destPath) && !exists(filepath.Join(destPath, "run.sh")) {
errorf("Abort: %s exists and does not look like a build directory.", destPath)
}
if err := os.RemoveAll(destPath); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatalln(err)
}
if err := os.MkdirAll(destPath, 0777); err != nil {
revel.ERROR.Fatalln(err)
}
app, reverr := harness.Build()
panicOnError(reverr, "Failed to build")
// Included are:
// - run scripts
// - binary
// - revel
// - app
// Revel and the app are in a directory structure mirroring import path
srcPath := filepath.Join(destPath, "src")
destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath))
tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(revel.RevelImportPath))
mustCopyFile(destBinaryPath, app.BinaryPath)
mustChmod(destBinaryPath, 0755)
_ = mustCopyDir(filepath.Join(tmpRevelPath, "conf"), filepath.Join(revel.RevelPath, "conf"), nil)
_ = mustCopyDir(filepath.Join(tmpRevelPath, "templates"), filepath.Join(revel.RevelPath, "templates"), nil)
_ = mustCopyDir(filepath.Join(srcPath, filepath.FromSlash(appImportPath)), revel.BasePath, nil)
// Find all the modules used and copy them over.
config := revel.Config.Raw()
modulePaths := make(map[string]string) // import path => filesystem path
for _, section := range config.Sections() {
options, _ := config.SectionOptions(section)
for _, key := range options {
if !strings.HasPrefix(key, "module.") {
continue
}
moduleImportPath, _ := config.String(section, key)
if moduleImportPath == "" {
continue
}
modulePath, err := revel.ResolveImportPath(moduleImportPath)
if err != nil {
revel.ERROR.Fatalln("Failed to load module %s: %s", key[len("module."):], err)
}
modulePaths[moduleImportPath] = modulePath
}
}
for importPath, fsPath := range modulePaths {
_ = mustCopyDir(filepath.Join(srcPath, importPath), fsPath, nil)
}
tmplData, runShPath := map[string]interface{}{
"BinName": filepath.Base(app.BinaryPath),
"ImportPath": appImportPath,
"Mode": mode,
}, filepath.Join(destPath, "run.sh")
mustRenderTemplate(
runShPath,
filepath.Join(revel.RevelPath, "..", "cmd", "revel", "package_run.sh.template"),
tmplData)
mustChmod(runShPath, 0755)
mustRenderTemplate(
filepath.Join(destPath, "run.bat"),
filepath.Join(revel.RevelPath, "..", "cmd", "revel", "package_run.bat.template"),
tmplData)
}
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"go/build"
"os"
"path/filepath"
)
var cmdClean = &Command{
UsageLine: "clean [import path]",
Short: "clean a Revel application's temp files",
Long: `
Clean the Revel web application named by the given import path.
For example:
revel clean github.com/revel/examples/chat
It removes the app/tmp and app/routes directory.
`,
}
func init() {
cmdClean.Run = cleanApp
}
func cleanApp(args []string) {
if len(args) == 0 {
fmt.Fprintf(os.Stderr, cmdClean.Long)
return
}
appPkg, err := build.Import(args[0], "", build.FindOnly)
if err != nil {
fmt.Fprintln(os.Stderr, "Abort: Failed to find import path:", err)
return
}
purgeDirs := []string{
filepath.Join(appPkg.Dir, "app", "tmp"),
filepath.Join(appPkg.Dir, "app", "routes"),
}
for _, dir := range purgeDirs {
fmt.Println("Removing:", dir)
err = os.RemoveAll(dir)
if err != nil {
fmt.Fprintln(os.Stderr, "Abort:", err)
return
}
}
}
+223
View File
@@ -0,0 +1,223 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"go/build"
"log"
"math/rand"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/revel/revel"
)
var cmdNew = &Command{
UsageLine: "new [path] [skeleton]",
Short: "create a skeleton Revel application",
Long: `
New creates a few files to get a new Revel application running quickly.
It puts all of the files in the given import path, taking the final element in
the path to be the app name.
Skeleton is an optional argument, provided as an import path
For example:
revel new import/path/helloworld
revel new import/path/helloworld import/path/skeleton
`,
}
func init() {
cmdNew.Run = newApp
}
var (
// go related paths
gopath string
gocmd string
srcRoot string
// revel related paths
revelPkg *build.Package
revelCmdPkg *build.Package
appPath string
appName string
basePath string
importPath string
skeletonPath string
)
func newApp(args []string) {
// check for proper args by count
if len(args) == 0 {
errorf("No import path given.\nRun 'revel help new' for usage.\n")
}
if len(args) > 2 {
errorf("Too many arguments provided.\nRun 'revel help new' for usage.\n")
}
revel.ERROR.SetFlags(log.LstdFlags)
// checking and setting go paths
initGoPaths()
// checking and setting application
setApplicationPath(args)
// checking and setting skeleton
setSkeletonPath(args)
// copy files to new app directory
copyNewAppFiles()
// goodbye world
fmt.Fprintln(os.Stdout, "Your application is ready:\n ", appPath)
fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run", importPath)
}
const alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
func generateSecret() string {
chars := make([]byte, 64)
for i := 0; i < 64; i++ {
chars[i] = alphaNumeric[rand.Intn(len(alphaNumeric))]
}
return string(chars)
}
// lookup and set Go related variables
func initGoPaths() {
// lookup go path
gopath = build.Default.GOPATH
if gopath == "" {
errorf("Abort: GOPATH environment variable is not set. " +
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
}
// check for go executable
var err error
gocmd, err = exec.LookPath("go")
if err != nil {
errorf("Go executable not found in PATH.")
}
// revel/revel#1004 choose go path relative to current working directory
workingDir, _ := os.Getwd()
goPathList := filepath.SplitList(gopath)
for _, path := range goPathList {
if strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
srcRoot = path
break
}
path, _ = filepath.EvalSymlinks(path)
if len(path) > 0 && strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
srcRoot = path
break
}
}
if len(srcRoot) == 0 {
revel.ERROR.Fatalln("Abort: could not create a Revel application outside of GOPATH.")
}
// set go src path
srcRoot = filepath.Join(srcRoot, "src")
}
func setApplicationPath(args []string) {
var err error
importPath = args[0]
// revel/revel#1014 validate relative path, we cannot use built-in functions
// since Go import path is valid relative path too.
// so check basic part of the path, which is "."
if filepath.IsAbs(importPath) || strings.HasPrefix(importPath, ".") {
errorf("Abort: '%s' looks like a directory. Please provide a Go import path instead.",
importPath)
}
_, err = build.Import(importPath, "", build.FindOnly)
if err == nil {
errorf("Abort: Import path %s already exists.\n", importPath)
}
revelPkg, err = build.Import(revel.RevelImportPath, "", build.FindOnly)
if err != nil {
errorf("Abort: Could not find Revel source code: %s\n", err)
}
appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath))
appName = filepath.Base(appPath)
basePath = filepath.ToSlash(filepath.Dir(importPath))
if basePath == "." {
// we need to remove the a single '.' when
// the app is in the $GOROOT/src directory
basePath = ""
} else {
// we need to append a '/' when the app is
// is a subdirectory such as $GOROOT/src/path/to/revelapp
basePath += "/"
}
}
func setSkeletonPath(args []string) {
var err error
if len(args) == 2 { // user specified
skeletonName := args[1]
_, err = build.Import(skeletonName, "", build.FindOnly)
if err != nil {
// Execute "go get <pkg>"
getCmd := exec.Command(gocmd, "get", "-d", skeletonName)
fmt.Println("Exec:", getCmd.Args)
getOutput, err := getCmd.CombinedOutput()
// check getOutput for no buildible string
bpos := bytes.Index(getOutput, []byte("no buildable Go source files in"))
if err != nil && bpos == -1 {
errorf("Abort: Could not find or 'go get' Skeleton source code: %s\n%s\n", getOutput, skeletonName)
}
}
// use the
skeletonPath = filepath.Join(srcRoot, skeletonName)
} else {
// use the revel default
revelCmdPkg, err = build.Import(RevelCmdImportPath, "", build.FindOnly)
if err != nil {
errorf("Abort: Could not find Revel Cmd source code: %s\n", err)
}
skeletonPath = filepath.Join(revelCmdPkg.Dir, "revel", "skeleton")
}
}
func copyNewAppFiles() {
var err error
err = os.MkdirAll(appPath, 0777)
panicOnError(err, "Failed to create directory "+appPath)
_ = mustCopyDir(appPath, skeletonPath, map[string]interface{}{
// app.conf
"AppName": appName,
"BasePath": basePath,
"Secret": generateSecret(),
})
// Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore.
gitignore := ".gitignore"
mustCopyFile(filepath.Join(appPath, gitignore), filepath.Join(skeletonPath, gitignore))
}
+69
View File
@@ -0,0 +1,69 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/revel/revel"
)
var cmdPackage = &Command{
UsageLine: "package [import path] [run mode]",
Short: "package a Revel application (e.g. for deployment)",
Long: `
Package the Revel web application named by the given import path.
This allows it to be deployed and run on a machine that lacks a Go installation.
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
Run mode defaults to "dev".
For example:
revel package github.com/revel/examples/chat
`,
}
func init() {
cmdPackage.Run = packageApp
}
func packageApp(args []string) {
if len(args) == 0 {
fmt.Fprint(os.Stderr, cmdPackage.Long)
return
}
// Determine the run mode.
mode := DefaultRunMode
if len(args) >= 2 {
mode = args[1]
}
appImportPath := args[0]
revel.Init(mode, appImportPath, "")
// Remove the archive if it already exists.
destFile := filepath.Base(revel.BasePath) + ".tar.gz"
if err := os.Remove(destFile); err != nil && !os.IsNotExist(err) {
revel.ERROR.Fatal(err)
}
// Collect stuff in a temp directory.
tmpDir, err := ioutil.TempDir("", filepath.Base(revel.BasePath))
panicOnError(err, "Failed to get temp dir")
buildApp([]string{args[0], tmpDir, mode})
// Create the zip file.
archiveName := mustTarGzDir(destFile, tmpDir)
fmt.Println("Your archive is ready:", archiveName)
}
@@ -0,0 +1,2 @@
@echo off
{{.BinName}} -importPath {{.ImportPath}} -srcPath %CD%\src -runMode {{.Mode}}
@@ -0,0 +1,3 @@
#!/bin/sh
SCRIPTPATH=$(cd "$(dirname "$0")"; pwd)
"$SCRIPTPATH/{{.BinName}}" -importPath {{.ImportPath}} -srcPath "$SCRIPTPATH/src" -runMode {{.Mode}}
+144
View File
@@ -0,0 +1,144 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// The command line tool for running Revel apps.
package main
import (
"flag"
"fmt"
"io"
"math/rand"
"os"
"runtime"
"strings"
"text/template"
"time"
"github.com/agtorre/gocolorize"
)
const (
// RevelCmdImportPath Revel framework cmd tool import path
RevelCmdImportPath = "github.com/revel/cmd"
// DefaultRunMode for revel's application
DefaultRunMode = "dev"
)
// Command structure cribbed from the genius organization of the "go" command.
type Command struct {
Run func(args []string)
UsageLine, Short, Long string
}
// Name returns command name from usage line
func (cmd *Command) Name() string {
name := cmd.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
var commands = []*Command{
cmdNew,
cmdRun,
cmdBuild,
cmdPackage,
cmdClean,
cmdTest,
cmdVersion,
}
func main() {
if runtime.GOOS == "windows" {
gocolorize.SetPlain(true)
}
fmt.Fprintf(os.Stdout, gocolorize.NewColor("blue").Paint(header))
flag.Usage = func() { usage(1) }
flag.Parse()
args := flag.Args()
if len(args) < 1 || args[0] == "help" {
if len(args) == 1 {
usage(0)
}
if len(args) > 1 {
for _, cmd := range commands {
if cmd.Name() == args[1] {
tmpl(os.Stdout, helpTemplate, cmd)
return
}
}
}
usage(2)
}
// Commands use panic to abort execution when something goes wrong.
// Panics are logged at the point of error. Ignore those.
defer func() {
if err := recover(); err != nil {
if _, ok := err.(LoggedError); !ok {
// This panic was not expected / logged.
panic(err)
}
os.Exit(1)
}
}()
for _, cmd := range commands {
if cmd.Name() == args[0] {
cmd.Run(args[1:])
return
}
}
errorf("unknown command %q\nRun 'revel help' for usage.\n", args[0])
}
func errorf(format string, args ...interface{}) {
// Ensure the user's command prompt starts on the next line.
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
fmt.Fprintf(os.Stderr, format, args...)
panic(LoggedError{}) // Panic instead of os.Exit so that deferred will run.
}
const header = `~
~ revel! http://revel.github.io
~
`
const usageTemplate = `usage: revel command [arguments]
The commands are:
{{range .}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}
Use "revel help [command]" for more information.
`
var helpTemplate = `usage: revel {{.UsageLine}}
{{.Long}}
`
func usage(exitCode int) {
tmpl(os.Stderr, usageTemplate, commands)
os.Exit(exitCode)
}
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
template.Must(t.Parse(text))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}
func init() {
rand.Seed(time.Now().UnixNano())
}
+172
View File
@@ -0,0 +1,172 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"go/build"
"strconv"
"github.com/leanote/leanote/cmd/harness"
"github.com/revel/revel"
// "fmt"
"path/filepath"
)
var cmdRun = &Command{
UsageLine: "run [import path] [run mode] [port]",
Short: "run a Revel application",
Long: `
Run the Revel web application named by the given import path.
For example, to run the chat room sample application:
revel run github.com/revel/examples/chat dev
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
Run mode defaults to "dev".
You can set a port as an optional third parameter. For example:
revel run github.com/revel/examples/chat prod 8080`,
}
// RunArgs holds revel run parameters
type RunArgs struct {
ImportPath string
Mode string
Port int
}
func init() {
cmdRun.Run = runApp
}
func parseRunArgs(args []string) *RunArgs {
inputArgs := RunArgs{
ImportPath: importPathFromCurrentDir(),
Mode: DefaultRunMode,
Port: revel.HTTPPort,
}
switch len(args) {
case 3:
// Possibile combinations
// revel run [import-path] [run-mode] [port]
port, err := strconv.Atoi(args[2])
if err != nil {
errorf("Failed to parse port as integer: %s", args[2])
}
inputArgs.ImportPath = args[0]
inputArgs.Mode = args[1]
inputArgs.Port = port
case 2:
// Possibile combinations
// 1. revel run [import-path] [run-mode]
// 2. revel run [import-path] [port]
// 3. revel run [run-mode] [port]
if _, err := build.Import(args[0], "", build.FindOnly); err == nil {
// 1st arg is the import path
inputArgs.ImportPath = args[0]
if port, err := strconv.Atoi(args[1]); err == nil {
// 2nd arg is the port number
inputArgs.Port = port
} else {
// 2nd arg is the run mode
inputArgs.Mode = args[1]
}
} else {
// 1st arg is the run mode
port, err := strconv.Atoi(args[1])
if err != nil {
errorf("Failed to parse port as integer: %s", args[1])
}
inputArgs.Mode = args[0]
inputArgs.Port = port
}
case 1:
// Possibile combinations
// 1. revel run [import-path]
// 2. revel run [port]
// 3. revel run [run-mode]
if _, err := build.Import(args[0], "", build.FindOnly); err == nil {
// 1st arg is the import path
inputArgs.ImportPath = args[0]
} else if port, err := strconv.Atoi(args[0]); err == nil {
// 1st arg is the port number
inputArgs.Port = port
} else {
// 1st arg is the run mode
inputArgs.Mode = args[0]
}
}
return &inputArgs
}
// findSrcPaths uses the "go/build" package to find the source root for Revel
// and the app.
func findSrcPaths(importPath string) (appSourcePath string) {
var (
gopaths = filepath.SplitList(build.Default.GOPATH)
goroot = build.Default.GOROOT
)
if len(gopaths) == 0 {
revel.ERROR.Fatalln("GOPATH environment variable is not set. ",
"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
}
if revel.ContainsString(gopaths, goroot) {
revel.ERROR.Fatalf("GOPATH (%s) must not include your GOROOT (%s). "+
"Please refer to http://golang.org/doc/code.html to configure your Go environment.",
gopaths, goroot)
}
appPkg, err := build.Import(importPath, "", build.FindOnly)
if err != nil {
revel.ERROR.Fatalln("Failed to import", importPath, "with error:", err)
}
return appPkg.SrcRoot
}
func runApp(args []string) {
runArgs := parseRunArgs(args)
// Find and parse app.conf
// fmt.Println(runArgs.ImportPath + "/vendor")
// revel.Init(runArgs.Mode, runArgs.ImportPath, runArgs.ImportPath + "/vendor")
srcPath := findSrcPaths(runArgs.ImportPath)
srcPath = ""
revel.Init(runArgs.Mode, runArgs.ImportPath, srcPath)
revel.LoadMimeConfig()
// fallback to default port
if runArgs.Port == 0 {
runArgs.Port = revel.HTTPPort
}
revel.INFO.Printf("Running %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, runArgs.Mode)
revel.TRACE.Println("Base path:", revel.BasePath)
// If the app is run in "watched" mode, use the harness to run it.
if revel.Config.BoolDefault("watch", true) && revel.Config.BoolDefault("watch.code", true) {
revel.TRACE.Println("Running in watched mode.")
revel.HTTPPort = runArgs.Port
harness.NewHarness().Run() // Never returns.
}
// Else, just build and run the app.
revel.TRACE.Println("Running in live build mode.")
app, err := harness.Build()
if err != nil {
errorf("Failed to build app: %s", err)
}
app.Port = runArgs.Port
app.Cmd().Run()
}
+3
View File
@@ -0,0 +1,3 @@
test-results/
tmp/
routes/
+43
View File
@@ -0,0 +1,43 @@
# Welcome to Revel
A high-productivity web framework for the [Go language](http://www.golang.org/).
### Start the web server:
revel run myapp
### Go to http://localhost:9000/ and you'll see:
"It works"
## Code Layout
The directory structure of a generated Revel application:
conf/ Configuration directory
app.conf Main app configuration file
routes Routes definition file
app/ App sources
init.go Interceptor registration
controllers/ App controllers go here
views/ Templates directory
messages/ Message files
public/ Public static assets
css/ CSS files
js/ Javascript files
images/ Image files
tests/ Test suites
## Help
* The [Getting Started with Revel](http://revel.github.io/tutorial/gettingstarted.html).
* The [Revel guides](http://revel.github.io/manual/index.html).
* The [Revel sample apps](http://revel.github.io/examples/index.html).
* The [API documentation](https://godoc.org/github.com/revel/revel).
@@ -0,0 +1,13 @@
package controllers
import (
"github.com/revel/revel"
)
type App struct {
*revel.Controller
}
func (c App) Index() revel.Result {
return c.Render()
}
+59
View File
@@ -0,0 +1,59 @@
package app
import (
"github.com/revel/revel"
)
var (
// AppVersion revel app version (ldflags)
AppVersion string
// BuildTime revel app build-time (ldflags)
BuildTime string
)
func init() {
// Filters is the default set of global filters.
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
revel.RouterFilter, // Use the routing table to select the right Action
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
revel.ParamsFilter, // Parse parameters into Controller.Params.
revel.SessionFilter, // Restore and write the session cookie.
revel.FlashFilter, // Restore and write the flash cookie.
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
revel.I18nFilter, // Resolve the requested language
HeaderFilter, // Add some security based headers
revel.InterceptorFilter, // Run interceptors around the action.
revel.CompressFilter, // Compress the result.
revel.ActionInvoker, // Invoke the action.
}
// register startup functions with OnAppStart
// revel.DevMode and revel.RunMode only work inside of OnAppStart. See Example Startup Script
// ( order dependent )
// revel.OnAppStart(ExampleStartupScript)
// revel.OnAppStart(InitDB)
// revel.OnAppStart(FillCache)
}
// HeaderFilter adds common security headers
// TODO turn this into revel.HeaderFilter
// should probably also have a filter for CSRF
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")
fc[0](c, fc[1:]) // Execute the next filter stage.
}
//func ExampleStartupScript() {
// // revel.DevMod and revel.RunMode work here
// // Use this script to check for dev mode and set dev/prod startup scripts here!
// if revel.DevMode == true {
// // Dev mode
// }
//}
@@ -0,0 +1,21 @@
{{set . "title" "Home"}}
{{template "header.html" .}}
<header class="jumbotron" style="background-color:#A9F16C">
<div class="container">
<div class="row">
<h1>It works!</h1>
<p></p>
</div>
</div>
</header>
<div class="container">
<div class="row">
<div class="span6">
{{template "flash.html" .}}
</div>
</div>
</div>
{{template "footer.html" .}}
@@ -0,0 +1,64 @@
<style type="text/css">
#sidebar {
position: absolute;
right: 0px;
top:69px;
max-width: 75%;
z-index: 1000;
background-color: #fee;
border: thin solid grey;
padding: 10px;
}
#toggleSidebar {
position: absolute;
right: 0px;
top: 50px;
background-color: #fee;
}
</style>
<div id="sidebar" style="display:none;">
<h4>Available pipelines</h4>
<dl>
{{ range $index, $value := .}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Flash</h4>
<dl>
{{ range $index, $value := .flash}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
<h4>Errors</h4>
<dl>
{{ range $index, $value := .errors}}
<dt>{{$index}}</dt>
<dd>{{$value}}</dd>
{{end}}
</dl>
</div>
<a id="toggleSidebar" href="#" class="toggles"><i class="glyphicon glyphicon-chevron-left"></i></a>
<script>
$sidebar = 0;
$('#toggleSidebar').click(function() {
if ($sidebar === 1) {
$('#sidebar').hide();
$('#toggleSidebar i').addClass('glyphicon-chevron-left');
$('#toggleSidebar i').removeClass('glyphicon-chevron-right');
$sidebar = 0;
}
else {
$('#sidebar').show();
$('#toggleSidebar i').addClass('glyphicon-chevron-right');
$('#toggleSidebar i').removeClass('glyphicon-chevron-left');
$sidebar = 1;
}
return false;
});
</script>
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/404-dev.html" .}}
{{else}}
{{with .Error}}
<h1>
{{.Title}}
</h1>
<p>
{{.Description}}
</p>
{{end}}
{{end}}
</body>
</html>
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Application error</title>
</head>
<body>
{{if eq .RunMode "dev"}}
{{template "errors/500-dev.html" .}}
{{else}}
<h1>Oops, an error occured</h1>
<p>
This exception has been logged.
</p>
{{end}}
</body>
</html>
@@ -0,0 +1,18 @@
{{if .flash.success}}
<div class="alert alert-success">
{{.flash.success}}
</div>
{{end}}
{{if or .errors .flash.error}}
<div class="alert alert-danger">
{{if .flash.error}}
{{.flash.error}}
{{end}}
<ul style="margin-top:10px;">
{{range .errors}}
<li>{{.}}</li>
{{end}}
</ul>
</div>
{{end}}
@@ -0,0 +1,5 @@
{{if eq .RunMode "dev"}}
{{template "debug.html" .}}
{{end}}
</body>
</html>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>{{.title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/public/css/bootstrap-3.3.6.min.css">
<link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
<script src="/public/js/jquery-2.2.4.min.js"></script>
<script src="/public/js/bootstrap-3.3.6.min.js"></script>
{{range .moreStyles}}
<link rel="stylesheet" type="text/css" href="/public/{{.}}">
{{end}}
{{range .moreScripts}}
<script src="/public/{{.}}" type="text/javascript" charset="utf-8"></script>
{{end}}
</head>
<body>
@@ -0,0 +1,258 @@
################################################################################
# Revel configuration file
# More info at http://revel.github.io/manual/appconf.html
################################################################################
# Sets `revel.AppName` for use in-app.
# Example:
# `if revel.AppName {...}`
app.name = {{ .AppName }}
# A secret string which is passed to cryptographically sign the cookie to prevent
# (and detect) user modification.
# Keep this string secret or users will be able to inject arbitrary cookie values
# into your application
app.secret = {{ .Secret }}
# Revel running behind proxy like nginx, haproxy, etc.
app.behind.proxy = false
# The IP address on which to listen.
http.addr =
# The port on which to listen.
http.port = 9000
# Whether to use SSL or not.
http.ssl = false
# Path to an X509 certificate file, if using SSL.
#http.sslcert =
# Path to an X509 certificate key, if using SSL.
#http.sslkey =
# Timeout specifies a time limit for request (in seconds) made by a single client.
# A Timeout of zero means no timeout.
http.timeout.read = 90
http.timeout.write = 60
# For any cookies set by Revel (Session,Flash,Error) these properties will set
# the fields of:
# http://golang.org/pkg/net/http/#Cookie
#
# Each cookie set by Revel is prefixed with this string.
cookie.prefix = REVEL
# A secure cookie has the secure attribute enabled and is only used via HTTPS,
# ensuring that the cookie is always encrypted when transmitting from client to
# server. This makes the cookie less likely to be exposed to cookie theft via
# eavesdropping.
#
# Defaults to false. If 'http.ssl' is enabled, this will be defaulted to true.
# This should only be true when Revel is handling SSL connections. If you are
# using a proxy in front of revel (Nginx, Apache, etc), then this should be left
# as false.
# cookie.secure = false
# Limit cookie access to a given domain.
#cookie.domain =
# Define when your session cookie expires.
# Values:
# "720h"
# A time duration (http://golang.org/pkg/time/#ParseDuration) after which
# the cookie expires and the session is invalid.
# "session"
# Sets a session cookie which invalidates the session when the user close
# the browser.
session.expires = 720h
# The date format used by Revel. Possible formats defined by the Go `time`
# package (http://golang.org/pkg/time/#Parse)
format.date = 2006-01-02
format.datetime = 2006-01-02 15:04
# Determines whether the template rendering should use chunked encoding.
# Chunked encoding can decrease the time to first byte on the client side by
# sending data before the entire template has been fully rendered.
results.chunked = false
# Prefixes for each log message line.
# User can override these prefix values within any section
# For e.g: [dev], [prod], etc
log.trace.prefix = "TRACE "
log.info.prefix = "INFO "
log.warn.prefix = "WARN "
log.error.prefix = "ERROR "
# The default language of this application.
i18n.default_language = en
# The default format when message is missing.
# The original message shows in %s
#i18n.unknown_format = "??? %s ???"
# Module to serve static content such as CSS, JavaScript and Media files
# Allows Routes like this:
# `Static.ServeModule("modulename","public")`
module.static=github.com/revel/modules/static
################################################################################
# Section: dev
# This section is evaluated when running Revel in dev mode. Like so:
# `revel run path/to/myapp`
[dev]
# This sets `revel.DevMode` for use in-app.
# Example:
# `if revel.DevMode {...}`
# or in your templates with
# `{{.DevMode}}`
# Values:
# "true"
# Sets `DevMode` to `true`.
# "false"
# Sets `DevMode` to `false`.
mode.dev = true
# Pretty print JSON/XML when calling RenderJSON/RenderXML
# Values:
# "true"
# Enables pretty printing.
# "false"
# Disables pretty printing.
results.pretty = true
# Watch your applicaton files for changes and automatically rebuild
# Values:
# "true"
# Enables auto rebuilding.
# "false"
# Disables auto rebuilding.
watch = true
# Define when to rebuild new changes.
# Values:
# "normal"
# Rebuild when a new request is received and changes have been detected.
# "eager"
# Rebuild as soon as changes are detected.
watch.mode = normal
# Watch the entire `$GOPATH` for changes.
# Values:
# "true"
# Includes `$GOPATH` in watch path.
# "false"
# Excludes `$GOPATH` from watch path. Default value.
#watch.gopath = true
# Module to run code tests in the browser
# See:
# http://revel.github.io/manual/testing.html
module.testrunner = github.com/revel/modules/testrunner
# Where to log the various Revel logs
# Values:
# "off"
# Disable log output.
# "stdout"
# Log to OS's standard output.
# "stderr"
# Log to Os's standard error output. Default value.
# "relative/path/to/log"
# Log to file.
log.trace.output = off
log.info.output = stderr
log.warn.output = stderr
log.error.output = stderr
# Revel log flags. Possible flags defined by the Go `log` package. Go log is
# "Bits OR'ed together to control what's printed
# See:
# https://golang.org/pkg/log/#pkg-constants
# Values:
# "0"
# Just log the message, turn off the flags.
# "3"
# log.LstdFlags (log.Ldate|log.Ltime)
# "19"
# log.Ldate|log.Ltime|log.Lshortfile
# "23"
# log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 19
log.info.flags = 19
log.warn.flags = 19
log.error.flags = 19
# Revel request access log
# Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
# Sample format:
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
log.request.output = stderr
################################################################################
# Section: prod
# This section is evaluated when running Revel in production mode. Like so:
# `revel run path/to/myapp prod`
# See:
# [dev] section for documentation of the various settings
[prod]
mode.dev = false
results.pretty = false
watch = false
module.testrunner =
log.trace.output = off
log.info.output = off
log.warn.output = log/%(app.name)s.log
log.error.output = log/%(app.name)s.log
# Revel log flags. Possible flags defined by the Go `log` package,
# please refer https://golang.org/pkg/log/#pkg-constants
# Go log is "Bits or'ed together to control what's printed"
# Examples:
# 0 => just log the message, turn off the flags
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
# 19 => log.Ldate|log.Ltime|log.Lshortfile
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
log.trace.flags = 3
log.info.flags = 3
log.warn.flags = 3
log.error.flags = 3
# Revel request access log
# Access log line format:
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
# Sample format:
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
# Example:
# log.request.output = %(app.name)s-request.log
log.request.output = off
+19
View File
@@ -0,0 +1,19 @@
# Routes Config
#
# This file defines all application routes (Higher priority routes first)
#
module:testrunner
# module:jobs
GET / App.Index
# Ignore favicon requests
GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path
GET /public/*filepath Static.Serve("public")
# Catch all
* /:controller/:action :controller.:action
@@ -0,0 +1,7 @@
# Sample messages file for the English language (en)
# Message file extensions should be ISO 639-1 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
# Sections within each message file can optionally override the defaults using ISO 3166-1 alpha-2 codes (http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
# See also:
# - http://www.rfc-editor.org/rfc/bcp/bcp47.txt
# - http://www.w3.org/International/questions/qa-accept-lang-locales
@@ -0,0 +1,5 @@
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */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,menu,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-color:transparent}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}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!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:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{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.woff2) format('woff2'),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:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.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:"\Line truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -0,0 +1,7 @@
/*!
* Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under the MIT license
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(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.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):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.3.6",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]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"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")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),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"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(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),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b|Line truncated
d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
@@ -0,0 +1,4 @@
/*! jQuery v2.2.4 | (c) jQuery Foundation | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new ReLine truncated
}catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=N.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function W(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&T.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var X=/^(?:checkbox|radio)$/i,Y=/<([\w:-]+)/,Z=/^$|\/(?:java|ecma)script/i,$={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);forLine truncated
void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var eb=/[\t\r\n\f]/g;function fb(a){return a.getAttribute&&a.getAttribute("class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,fb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,fb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,fb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=fb(this),b&&N.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":N.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+fb(c)+" ").replace(eb," ").indexOf(b)>-1)return!0;return!1}});var gb=/\r/g,hb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(gb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(hb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(n.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var ib=/^(?:focusinfocus|focusoutblur)$/;n.extend(n.event,{trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!ib.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),l=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},f||!o.trigger||o.trigger.apply(e,c)!==!1)){if(!f&&!o.noBubble&&!n.isWindow(e)){for(j=o.delegateType||q,ib.test(j+q)||(h=h.parentNode);h;h=h.parentNode)p.push(h),i=h;i===(e.ownerDocument||d)&&p.push(i.defaultView||i.parentWindow||a)}g=0;while((h=p[g++])&&!b.isPropagationStopped())b.type=g>1?j:o.bindType||q,m=(N.get(h,"events")||{})[b.type]&&N.get(h,"handle"),m&&m.apply(h,c),m=l&&h[l],m&&m.apply&&L(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=q,f||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==Line truncated
@@ -0,0 +1,23 @@
package tests
import (
"github.com/revel/revel/testing"
)
type AppTest struct {
testing.TestSuite
}
func (t *AppTest) Before() {
println("Set up")
}
func (t *AppTest) TestThatIndexPageWorks() {
t.Get("/")
t.AssertOk()
t.AssertContentType("text/html; charset=utf-8")
}
func (t *AppTest) After() {
println("Tear down")
}
+314
View File
@@ -0,0 +1,314 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/revel/cmd/harness"
"github.com/revel/modules/testrunner/app/controllers"
"github.com/revel/revel"
)
var cmdTest = &Command{
UsageLine: "test [import path] [run mode] [suite.method]",
Short: "run all tests from the command-line",
Long: `
Run all tests for the Revel app named by the given import path.
For example, to run the booking sample application's tests:
revel test github.com/revel/examples/booking dev
The run mode is used to select which set of app.conf configuration should
apply and may be used to determine logic in the application itself.
Run mode defaults to "dev".
You can run a specific suite (and function) by specifying a third parameter.
For example, to run all of UserTest:
revel test outspoken test UserTest
or one of UserTest's methods:
revel test outspoken test UserTest.Test1
`,
}
func init() {
cmdTest.Run = testApp
}
func testApp(args []string) {
var err error
if len(args) == 0 {
errorf("No import path given.\nRun 'revel help test' for usage.\n")
}
mode := DefaultRunMode
if len(args) >= 2 {
mode = args[1]
}
// Find and parse app.conf
revel.Init(mode, args[0], "")
// Ensure that the testrunner is loaded in this mode.
checkTestRunner()
// Create a directory to hold the test result files.
resultPath := filepath.Join(revel.BasePath, "test-results")
if err = os.RemoveAll(resultPath); err != nil {
errorf("Failed to remove test result directory %s: %s", resultPath, err)
}
if err = os.Mkdir(resultPath, 0777); err != nil {
errorf("Failed to create test result directory %s: %s", resultPath, err)
}
// Direct all the output into a file in the test-results directory.
file, err := os.OpenFile(filepath.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
errorf("Failed to create test result log file: %s", err)
}
app, reverr := harness.Build()
if reverr != nil {
errorf("Error building: %s", reverr)
}
cmd := app.Cmd()
cmd.Stderr = io.MultiWriter(cmd.Stderr, file)
cmd.Stdout = io.MultiWriter(cmd.Stderr, file)
// Start the app...
if err := cmd.Start(); err != nil {
errorf("%s", err)
}
defer cmd.Kill()
revel.INFO.Printf("Testing %s (%s) in %s mode\n", revel.AppName, revel.ImportPath, mode)
var httpAddr = revel.HTTPAddr
if httpAddr == "" {
httpAddr = "127.0.0.1"
}
var httpProto = "http"
if revel.HTTPSsl {
httpProto = "https"
}
// Get a list of tests
var baseURL = fmt.Sprintf("%s://%s:%d", httpProto, httpAddr, revel.HTTPPort)
testSuites, _ := getTestsList(baseURL)
// If a specific TestSuite[.Method] is specified, only run that suite/test
if len(args) == 3 {
testSuites = filterTestSuites(testSuites, args[2])
}
testSuiteCount := len(*testSuites)
fmt.Printf("\n%d test suite%s to run.\n", testSuiteCount, pluralize(testSuiteCount, "", "s"))
fmt.Println()
// Run each suite.
failedResults, overallSuccess := runTestSuites(baseURL, resultPath, testSuites)
fmt.Println()
if overallSuccess {
writeResultFile(resultPath, "result.passed", "passed")
fmt.Println("All Tests Passed.")
} else {
for _, failedResult := range *failedResults {
fmt.Printf("Failures:\n")
for _, result := range failedResult.Results {
if !result.Passed {
fmt.Printf("%s.%s\n", failedResult.Name, result.Name)
fmt.Printf("%s\n\n", result.ErrorSummary)
}
}
}
writeResultFile(resultPath, "result.failed", "failed")
errorf("Some tests failed. See file://%s for results.", resultPath)
}
}
func writeResultFile(resultPath, name, content string) {
if err := ioutil.WriteFile(filepath.Join(resultPath, name), []byte(content), 0666); err != nil {
errorf("Failed to write result file %s: %s", filepath.Join(resultPath, name), err)
}
}
func pluralize(num int, singular, plural string) string {
if num == 1 {
return singular
}
return plural
}
// Filters test suites and individual tests to match
// the parsed command line parameter
func filterTestSuites(suites *[]controllers.TestSuiteDesc, suiteArgument string) *[]controllers.TestSuiteDesc {
var suiteName, testName string
argArray := strings.Split(suiteArgument, ".")
suiteName = argArray[0]
if suiteName == "" {
return suites
}
if len(argArray) == 2 {
testName = argArray[1]
}
for _, suite := range *suites {
if suite.Name != suiteName {
continue
}
if testName == "" {
return &[]controllers.TestSuiteDesc{suite}
}
// Only run a particular test in a suite
for _, test := range suite.Tests {
if test.Name != testName {
continue
}
return &[]controllers.TestSuiteDesc{
{
Name: suite.Name,
Tests: []controllers.TestDesc{test},
},
}
}
errorf("Couldn't find test %s in suite %s", testName, suiteName)
}
errorf("Couldn't find test suite %s", suiteName)
return nil
}
func checkTestRunner() {
testRunnerFound := false
for _, module := range revel.Modules {
if module.ImportPath == revel.Config.StringDefault("module.testrunner", "github.com/revel/modules/testrunner") {
testRunnerFound = true
break
}
}
if !testRunnerFound {
errorf(`Error: The testrunner module is not running.
You can add it to a run mode configuration with the following line:
module.testrunner = github.com/revel/modules/testrunner
`)
}
}
// Get a list of tests from server.
// Since this is the first request to the server, retry/sleep a couple times
// in case it hasn't finished starting up yet.
func getTestsList(baseURL string) (*[]controllers.TestSuiteDesc, error) {
var (
err error
resp *http.Response
testSuites []controllers.TestSuiteDesc
)
for i := 0; ; i++ {
if resp, err = http.Get(baseURL + "/@tests.list"); err == nil {
if resp.StatusCode == http.StatusOK {
break
}
}
if i < 3 {
time.Sleep(3 * time.Second)
continue
}
if err != nil {
errorf("Failed to request test list: %s", err)
} else {
errorf("Failed to request test list: non-200 response")
}
}
defer func() {
_ = resp.Body.Close()
}()
err = json.NewDecoder(resp.Body).Decode(&testSuites)
return &testSuites, err
}
func runTestSuites(baseURL, resultPath string, testSuites *[]controllers.TestSuiteDesc) (*[]controllers.TestSuiteResult, bool) {
// Load the result template, which we execute for each suite.
module, _ := revel.ModuleByName("testrunner")
TemplateLoader := revel.NewTemplateLoader([]string{filepath.Join(module.Path, "app", "views")})
if err := TemplateLoader.Refresh(); err != nil {
errorf("Failed to compile templates: %s", err)
}
resultTemplate, err := TemplateLoader.Template("TestRunner/SuiteResult.html")
if err != nil {
errorf("Failed to load suite result template: %s", err)
}
var (
overallSuccess = true
failedResults []controllers.TestSuiteResult
)
for _, suite := range *testSuites {
// Print the name of the suite we're running.
name := suite.Name
if len(name) > 22 {
name = name[:19] + "..."
}
fmt.Printf("%-22s", name)
// Run every test.
startTime := time.Now()
suiteResult := controllers.TestSuiteResult{Name: suite.Name, Passed: true}
for _, test := range suite.Tests {
testURL := baseURL + "/@tests/" + suite.Name + "/" + test.Name
resp, err := http.Get(testURL)
if err != nil {
errorf("Failed to fetch test result at url %s: %s", testURL, err)
}
defer func() {
_ = resp.Body.Close()
}()
var testResult controllers.TestResult
err = json.NewDecoder(resp.Body).Decode(&testResult)
if err == nil && !testResult.Passed {
suiteResult.Passed = false
}
suiteResult.Results = append(suiteResult.Results, testResult)
}
overallSuccess = overallSuccess && suiteResult.Passed
// Print result. (Just PASSED or FAILED, and the time taken)
suiteResultStr, suiteAlert := "PASSED", ""
if !suiteResult.Passed {
suiteResultStr, suiteAlert = "FAILED", "!"
failedResults = append(failedResults, suiteResult)
}
fmt.Printf("%8s%3s%6ds\n", suiteResultStr, suiteAlert, int(time.Since(startTime).Seconds()))
// Create the result HTML file.
suiteResultFilename := filepath.Join(resultPath,
fmt.Sprintf("%s.%s.html", suite.Name, strings.ToLower(suiteResultStr)))
suiteResultFile, err := os.Create(suiteResultFilename)
if err != nil {
errorf("Failed to create result file %s: %s", suiteResultFilename, err)
}
if err = resultTemplate.Render(suiteResultFile, suiteResult); err != nil {
errorf("Failed to render result template: %s", err)
}
}
return &failedResults, overallSuccess
}
+176
View File
@@ -0,0 +1,176 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"archive/tar"
"compress/gzip"
"fmt"
"go/build"
"io"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/revel/revel"
)
// LoggedError is wrapper to differentiate logged panics from unexpected ones.
type LoggedError struct{ error }
func panicOnError(err error, msg string) {
if revErr, ok := err.(*revel.Error); (ok && revErr != nil) || (!ok && err != nil) {
fmt.Fprintf(os.Stderr, "Abort: %s: %s\n", msg, err)
panic(LoggedError{err})
}
}
func mustCopyFile(destFilename, srcFilename string) {
destFile, err := os.Create(destFilename)
panicOnError(err, "Failed to create file "+destFilename)
srcFile, err := os.Open(srcFilename)
panicOnError(err, "Failed to open file "+srcFilename)
_, err = io.Copy(destFile, srcFile)
panicOnError(err,
fmt.Sprintf("Failed to copy data from %s to %s", srcFile.Name(), destFile.Name()))
err = destFile.Close()
panicOnError(err, "Failed to close file "+destFile.Name())
err = srcFile.Close()
panicOnError(err, "Failed to close file "+srcFile.Name())
}
func mustRenderTemplate(destPath, srcPath string, data map[string]interface{}) {
tmpl, err := template.ParseFiles(srcPath)
panicOnError(err, "Failed to parse template "+srcPath)
f, err := os.Create(destPath)
panicOnError(err, "Failed to create "+destPath)
err = tmpl.Execute(f, data)
panicOnError(err, "Failed to render template "+srcPath)
err = f.Close()
panicOnError(err, "Failed to close "+f.Name())
}
func mustChmod(filename string, mode os.FileMode) {
err := os.Chmod(filename, mode)
panicOnError(err, fmt.Sprintf("Failed to chmod %d %q", mode, filename))
}
// copyDir copies a directory tree over to a new directory. Any files ending in
// ".template" are treated as a Go template and rendered using the given data.
// Additionally, the trailing ".template" is stripped from the file name.
// Also, dot files and dot directories are skipped.
func mustCopyDir(destDir, srcDir string, data map[string]interface{}) error {
return revel.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {
// Get the relative path from the source base, and the corresponding path in
// the dest directory.
relSrcPath := strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator))
destPath := filepath.Join(destDir, relSrcPath)
// Skip dot files and dot directories.
if strings.HasPrefix(relSrcPath, ".") {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
// Create a subdirectory if necessary.
if info.IsDir() {
err := os.MkdirAll(filepath.Join(destDir, relSrcPath), 0777)
if !os.IsExist(err) {
panicOnError(err, "Failed to create directory")
}
return nil
}
// If this file ends in ".template", render it as a template.
if strings.HasSuffix(relSrcPath, ".template") {
mustRenderTemplate(destPath[:len(destPath)-len(".template")], srcPath, data)
return nil
}
// Else, just copy it over.
mustCopyFile(destPath, srcPath)
return nil
})
}
func mustTarGzDir(destFilename, srcDir string) string {
zipFile, err := os.Create(destFilename)
panicOnError(err, "Failed to create archive")
defer func() {
_ = zipFile.Close()
}()
gzipWriter := gzip.NewWriter(zipFile)
defer func() {
_ = gzipWriter.Close()
}()
tarWriter := tar.NewWriter(gzipWriter)
defer func() {
_ = tarWriter.Close()
}()
_ = revel.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
srcFile, err := os.Open(srcPath)
panicOnError(err, "Failed to read source file")
defer func() {
_ = srcFile.Close()
}()
err = tarWriter.WriteHeader(&tar.Header{
Name: strings.TrimLeft(srcPath[len(srcDir):], string(os.PathSeparator)),
Size: info.Size(),
Mode: int64(info.Mode()),
ModTime: info.ModTime(),
})
panicOnError(err, "Failed to write tar entry header")
_, err = io.Copy(tarWriter, srcFile)
panicOnError(err, "Failed to copy")
return nil
})
return zipFile.Name()
}
func exists(filename string) bool {
_, err := os.Stat(filename)
return err == nil
}
// empty returns true if the given directory is empty.
// the directory must exist.
func empty(dirname string) bool {
dir, err := os.Open(dirname)
if err != nil {
errorf("error opening directory: %s", err)
}
defer func() {
_ = dir.Close()
}()
results, _ := dir.Readdir(1)
return len(results) == 0
}
func importPathFromCurrentDir() string {
pwd, _ := os.Getwd()
importPath, _ := filepath.Rel(filepath.Join(build.Default.GOPATH, "src"), pwd)
return filepath.ToSlash(importPath)
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
// Revel Framework source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"runtime"
"github.com/revel/revel"
)
var cmdVersion = &Command{
UsageLine: "version",
Short: "displays the Revel Framework and Go version",
Long: `
Displays the Revel Framework and Go version.
For example:
revel version
`,
}
func init() {
cmdVersion.Run = versionApp
}
func versionApp(args []string) {
fmt.Printf("Version(s):")
fmt.Printf("\n Revel v%v (%v)", revel.Version, revel.BuildDate)
fmt.Printf("\n %s %s/%s\n\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
+3 -1
View File
@@ -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
@@ -46,7 +47,8 @@ log.error.prefix = "ERROR "
# The default language of this application. # The default language of this application.
i18n.default_language=en-us i18n.default_language=en-us
module.static=github.com/revel/modules/static # module.static=github.com/revel/modules/static
module.static=github.com/leanote/leanote/vendor/github.com/revel/modules/static
[dev] [dev]
mode.dev=true mode.dev=true
+1
View File
@@ -48,6 +48,7 @@ log.error.prefix = "ERROR "
i18n.default_language=en-us i18n.default_language=en-us
module.static=github.com/revel/modules/static module.static=github.com/revel/modules/static
module.static=github.com/leanote/leanote/vendor/github.com/revel/modules/static
[dev] [dev]
mode.dev=true mode.dev=true
+1
View File
@@ -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
+6 -6
View File
@@ -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:
+6 -6
View File
@@ -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:
+31
View File
@@ -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
+91
View File
@@ -0,0 +1,91 @@
# blog
blogNavs=Navs
quickLinks=Accesos rápidos
latestPosts=Últimos posts
noBlog=Sin blog
noTag=Sin etiquetas
blogClass=Categoría
updatedTime=Actualizado en
createdTime=Creado en
fullBlog=Blog completo
blogNav=Navegación del Blog
more=Leer más...
previous=Anterior
next=Siguiente
#
# set blog
#
blogSet=Blog configuración
baseInfoSet=Base info
commentSet=Comentario
themeSet=Tema
theme=Tema
blogName=Título
blogLogo=Logo
blogDesc=Descripción
aboutMe=Sobre mí
#domain
domainSet=Dominio
subDomain=Subdominio
domain=Domain personalizado
# theme
elegant=Elegante
navFixed=Navegación fijado en el lado izquierdo
openComment=Comentarios abiertos?
chooseComment=Comentarios del sistema
disqusHelp=Por favor ingresa el id de Disqus.
needHelp=Necesita ayuda?
blogLogoTips=Subir una imagen para reemplzar el título del blog
saveSuccess=Guardado
community=Comunidad
home=Inicio
none=None
moreShare=Más
sinaWeibo=Weibo
weixin=Weichat
tencentWeibo=Tencent Weibo
qqZone=QQ Zone
renren=Renren
report=Reportar
like=Me gusta
unlike=No me gusta
viewers=Visitas
author=Autor
delete=Eliminar
reply=Responder
comment=Comentario
comments=Comentarios
cancel=Cancelar
confirm=Confirmar
signIn=Iniciar sesión
signUp=Salir
submitComment=Enviar
reportReason1=Contenido no amigable
reportReason2=Publicidad y otro spam
reportReason3=Contenido ilegal
reportReason4=Discusión pública de contenido político
other=Otro
reportReason=Razón
chooseReason=Seleccione razón de reporte
reportSuccess=Reportado correctamente, será notificado al autor, gracias por su aporte
error=Error
reportComment?=Reportar este comenatario?
reportBlog?=Reportar este blog?
confirmDeleteComment=Está seguro?
scanQRCode=Abrir wechat y escanear el código QR
justNow=Justo ahora
minutesAgo=minustos antes
hoursAgo=horas antes
daysAgo=días antes
weeksAgo=semanas antes
monthsAgo=meses antes
a=a
Loaded 100 of 812 files, more files were not shown because too many files have changed in this diff. Show more