init
This commit is contained in:
1 parent
fac05a7b6c
commit
476ade10e7
1085 files changed
+259628
No files matched your search
@@ -0,0 +1,130 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
)
|
||||
|
||||
// 用户登录/注销/找回密码
|
||||
|
||||
type Auth struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
//--------
|
||||
// 登录
|
||||
func (c Auth) Login(email string) revel.Result {
|
||||
c.RenderArgs["title"] = c.Message("login")
|
||||
c.RenderArgs["subTitle"] = c.Message("login")
|
||||
c.RenderArgs["email"] = email
|
||||
if c.Has("demo") {
|
||||
c.RenderArgs["demo"] = true
|
||||
c.RenderArgs["email"] = "demo@leanote.com"
|
||||
}
|
||||
return c.RenderTemplate("home/login.html")
|
||||
}
|
||||
func (c Auth) DoLogin(email, pwd string) revel.Result {
|
||||
userInfo := authService.Login(email, pwd)
|
||||
if userInfo.Email != "" {
|
||||
c.SetSession(userInfo)
|
||||
// 必须要redirect, 不然用户刷新会重复提交登录信息
|
||||
// return c.Redirect("/")
|
||||
return c.RenderJson(info.Re{Ok: true})
|
||||
}
|
||||
// return c.RenderTemplate("login.html")
|
||||
return c.RenderJson(info.Re{Ok: false, Msg: c.Message("wrongUsernameOrPassword")})
|
||||
}
|
||||
// 注销
|
||||
func (c Auth) Logout() revel.Result {
|
||||
c.ClearSession()
|
||||
return c.Redirect("login")
|
||||
}
|
||||
// 体验一下
|
||||
func (c Auth) Demo() revel.Result {
|
||||
c.DoLogin("demo@leanote.com", "demo@leanote.com")
|
||||
return c.Redirect("/note")
|
||||
}
|
||||
|
||||
//--------
|
||||
// 注册
|
||||
func (c Auth) Register() revel.Result {
|
||||
c.RenderArgs["title"] = c.Message("register")
|
||||
c.RenderArgs["subTitle"] = c.Message("register")
|
||||
return c.RenderTemplate("home/register.html")
|
||||
}
|
||||
func (c Auth) DoRegister(email, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
|
||||
if email == "" {
|
||||
re.Msg = c.Message("inputEmail")
|
||||
return c.RenderJson(re)
|
||||
} else if !IsEmail(email) {
|
||||
re.Msg = c.Message("wrongEmail")
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 密码
|
||||
if pwd == "" {
|
||||
re.Msg = c.Message("inputPassword")
|
||||
return c.RenderJson(re)
|
||||
} else if len(pwd) < 6 {
|
||||
re.Msg = c.Message("wrongPassword")
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 注册
|
||||
re.Ok, re.Msg = authService.Register(email, pwd)
|
||||
|
||||
// 注册成功, 则立即登录之
|
||||
if re.Ok {
|
||||
c.DoLogin(email, pwd)
|
||||
}
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//--------
|
||||
// 找回密码
|
||||
func (c Auth) FindPassword() revel.Result {
|
||||
c.RenderArgs["title"] = c.Message("findPassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||
return c.RenderTemplate("home/find_password.html")
|
||||
}
|
||||
func (c Auth) DoFindPassword(email string) revel.Result {
|
||||
pwdService.FindPwd(email)
|
||||
re := info.NewRe()
|
||||
re.Ok = true
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
// 点击链接后, 先验证之
|
||||
func (c Auth) FindPassword2(token string) revel.Result {
|
||||
c.RenderArgs["title"] = c.Message("findPassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("findPassword")
|
||||
if token == "" {
|
||||
return c.RenderTemplate("find_password2_timeout.html")
|
||||
}
|
||||
ok, _, findPwd := tokenService.VerifyToken(token, info.TokenPwd);
|
||||
if !ok {
|
||||
return c.RenderTemplate("home/find_password2_timeout.html")
|
||||
}
|
||||
c.RenderArgs["findPwd"] = findPwd
|
||||
|
||||
c.RenderArgs["title"] = c.Message("updatePassword")
|
||||
c.RenderArgs["subTitle"] = c.Message("updatePassword")
|
||||
|
||||
return c.RenderTemplate("home/find_password2.html")
|
||||
}
|
||||
// 找回密码修改密码
|
||||
func (c Auth) FindPasswordUpdate(token, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
|
||||
re.Ok, re.Msg = IsGoodPwd(pwd)
|
||||
if !re.Ok {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 修改之
|
||||
re.Ok, re.Msg = pwdService.UpdatePwd(token, pwd)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 公用Controller, 其它Controller继承它
|
||||
type BaseController struct {
|
||||
*revel.Controller
|
||||
}
|
||||
|
||||
func (c BaseController) GetUserId() string {
|
||||
if userId, ok := c.Session["UserId"]; ok {
|
||||
return userId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 是否已登录
|
||||
func (c BaseController) HasLogined() bool {
|
||||
return c.GetUserId() != ""
|
||||
}
|
||||
|
||||
func (c BaseController) GetObjectUserId() bson.ObjectId {
|
||||
userId := c.GetUserId()
|
||||
if userId != "" {
|
||||
return bson.ObjectIdHex(userId)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c BaseController) GetEmail() string {
|
||||
if email, ok := c.Session["Email"]; ok {
|
||||
return email
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c BaseController) GetUsername() string {
|
||||
if email, ok := c.Session["Username"]; ok {
|
||||
return email
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 得到用户信息
|
||||
func (c BaseController) GetUserInfo() info.User {
|
||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||
notebookWidth, _ := strconv.Atoi(c.Session["NotebookWidth"])
|
||||
noteListWidth, _ := strconv.Atoi(c.Session["NoteListWidth"])
|
||||
user := info.User{UserId: bson.ObjectIdHex(userId),
|
||||
Email: c.Session["Email"],
|
||||
Username: c.Session["Username"],
|
||||
UsernameRaw: c.Session["UsernameRaw"],
|
||||
Theme: c.Session["Theme"],
|
||||
NotebookWidth: notebookWidth,
|
||||
NoteListWidth: noteListWidth,
|
||||
}
|
||||
if c.Session["Verified"] == "1" {
|
||||
user.Verified = true
|
||||
}
|
||||
if c.Session["LeftIsMin"] == "1" {
|
||||
user.LeftIsMin = true
|
||||
}
|
||||
return user
|
||||
}
|
||||
return info.User{}
|
||||
}
|
||||
|
||||
func (c BaseController) SetSession(userInfo info.User) {
|
||||
if userInfo.UserId.Hex() != "" {
|
||||
c.Session["UserId"] = userInfo.UserId.Hex()
|
||||
c.Session["Email"] = userInfo.Email
|
||||
c.Session["Username"] = userInfo.Username
|
||||
c.Session["UsernameRaw"] = userInfo.UsernameRaw
|
||||
c.Session["Theme"] = userInfo.Theme
|
||||
|
||||
c.Session["NotebookWidth"] = strconv.Itoa(userInfo.NotebookWidth)
|
||||
c.Session["NoteListWidth"] = strconv.Itoa(userInfo.NoteListWidth)
|
||||
|
||||
if userInfo.Verified {
|
||||
c.Session["Verified"] = "1"
|
||||
} else {
|
||||
c.Session["Verified"] = "0"
|
||||
}
|
||||
|
||||
if userInfo.LeftIsMin {
|
||||
c.Session["LeftIsMin"] = "1"
|
||||
} else {
|
||||
c.Session["LeftIsMin"] = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c BaseController) ClearSession() {
|
||||
delete(c.Session, "UserId")
|
||||
delete(c.Session, "Email")
|
||||
delete(c.Session, "Username")
|
||||
delete(c.Session, "theme")
|
||||
}
|
||||
|
||||
// 修改session
|
||||
func (c BaseController) UpdateSession(key, value string) {
|
||||
c.Session[key] = value
|
||||
}
|
||||
|
||||
// 返回json
|
||||
func (c BaseController) Json(i interface{}) string {
|
||||
// b, _ := json.MarshalIndent(i, "", " ")
|
||||
b, _ := json.Marshal(i)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// 得到第几页
|
||||
func (c BaseController) GetPage() int {
|
||||
page := 0
|
||||
c.Params.Bind(&page, "page")
|
||||
if page == 0 {
|
||||
return 1
|
||||
}
|
||||
return page
|
||||
}
|
||||
|
||||
// 判断是否含有某参数
|
||||
func (c BaseController) Has(key string) bool {
|
||||
if _, ok := c.Params.Values[key]; ok {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
func (c Blog) GetPage(page, count int, list interface{}) info.Page {
|
||||
return info.Page{page, int(math.Ceil(float64(count)/float64(page))), list}
|
||||
}
|
||||
*/
|
||||
|
||||
func (c BaseController) GetTotalPage(page, count int) int {
|
||||
return int(math.Ceil(float64(count)/float64(page)))
|
||||
}
|
||||
|
||||
//-------------
|
||||
func (c BaseController) E404() revel.Result {
|
||||
c.RenderArgs["title"] = "404";
|
||||
return c.NotFound("", nil)
|
||||
}
|
||||
|
||||
// 设置本地
|
||||
func (c BaseController) SetLocale() {
|
||||
locale := string(c.Request.Locale) // zh-CN
|
||||
lang := locale
|
||||
if strings.Contains(locale, "-") {
|
||||
pos := strings.Index(locale, "-")
|
||||
lang = locale[0:pos]
|
||||
}
|
||||
if lang != "zh" && lang != "en" {
|
||||
lang = "en";
|
||||
}
|
||||
c.RenderArgs["locale"] = lang;
|
||||
}
|
||||
|
||||
// 设置userInfo
|
||||
func (c BaseController) SetUserInfo() {
|
||||
userInfo := c.GetUserInfo()
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// . "leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
)
|
||||
|
||||
type Blog struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
// 后台 note<->blog
|
||||
|
||||
// 设置/取消Blog; 置顶
|
||||
func (c Blog) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||
if isTop {
|
||||
isBlog = true
|
||||
}
|
||||
if !isBlog {
|
||||
isTop = false
|
||||
}
|
||||
noteUpdate := bson.M{"IsBlog": isBlog, "IsTop": isTop}
|
||||
re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(),
|
||||
noteId, noteUpdate)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 设置notebook <-> blog
|
||||
func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||
noteUpdate := bson.M{"IsBlog": isBlog}
|
||||
re := notebookService.UpdateNotebook(c.GetUserId(),
|
||||
notebookId, noteUpdate)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//-----------------------------
|
||||
// 前台
|
||||
|
||||
// 默认是admin用户的博客
|
||||
// 列表
|
||||
// 这里还需要得到其它博客配置信息...
|
||||
// 配置信息可以放在users表中, 或添加一个user_options表(用户配置表)
|
||||
var blogPageSize = 5
|
||||
var searchBlogPageSize = 30
|
||||
func (c Blog) Index(userId string, notebookId string) revel.Result {
|
||||
if userId == "" {
|
||||
userId = leanoteUserId
|
||||
}
|
||||
|
||||
// userId可能是 username, email
|
||||
userInfo := userService.GetUserInfoByAny(userId)
|
||||
if userInfo.UserId == "" {
|
||||
return c.E404()
|
||||
}
|
||||
|
||||
userId = userInfo.UserId.Hex()
|
||||
c.isMe(userId)
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
// 得到博客设置信息
|
||||
userBlog := blogService.GetUserBlog(userId)
|
||||
c.RenderArgs["userBlog"] = userBlog
|
||||
|
||||
var notebook info.Notebook
|
||||
if notebookId != "" {
|
||||
notebook = notebookService.GetNotebook(notebookId, userId)
|
||||
if !notebook.IsBlog {
|
||||
return c.E404()
|
||||
}
|
||||
|
||||
c.RenderArgs["title"] = userBlog.Title + " - 分类: " + notebook.Title
|
||||
} else {
|
||||
c.RenderArgs["title"] = userBlog.Title
|
||||
}
|
||||
// 分页的话, 需要分页信息, totalPage, curPage
|
||||
page := c.GetPage()
|
||||
count, blogs := blogService.ListBlogs(userId, notebookId, page, blogPageSize, "UpdatedTime", false)
|
||||
|
||||
c.RenderArgs["blogs"] = blogs
|
||||
c.RenderArgs["page"] = page
|
||||
c.RenderArgs["pageSize"] = blogPageSize
|
||||
c.RenderArgs["count"] = count
|
||||
|
||||
// 当前notebook
|
||||
c.RenderArgs["notebookId"] = notebookId
|
||||
c.RenderArgs["notebook"] = notebook
|
||||
|
||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||
|
||||
|
||||
if notebookId == "" {
|
||||
c.RenderArgs["index"] = true
|
||||
}
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
return c.RenderTemplate("blog/index.html")
|
||||
}
|
||||
|
||||
// 详情
|
||||
func (c Blog) View(noteId string) revel.Result {
|
||||
blog := blogService.GetBlog(noteId)
|
||||
c.RenderArgs["blog"] = blog
|
||||
|
||||
userInfo := userService.GetUserInfo(blog.UserId.Hex())
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
c.RenderArgs["title"] = blog.Title + " - " + userInfo.Email
|
||||
|
||||
userId := userInfo.UserId.Hex()
|
||||
c.isMe(userId)
|
||||
|
||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||
|
||||
// 得到博客设置信息
|
||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
return c.RenderTemplate("blog/view.html")
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (c Blog) SearchBlog(userId, key string) revel.Result {
|
||||
c.RenderArgs["title"] = "搜索 " + key
|
||||
c.RenderArgs["key"] = key
|
||||
|
||||
userInfo := userService.GetUserInfoByAny(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
userId = userInfo.UserId.Hex()
|
||||
|
||||
page := c.GetPage()
|
||||
_, blogs := blogService.SearchBlog(key, userId, page, searchBlogPageSize, "UpdatedTime", false)
|
||||
|
||||
c.RenderArgs["blogs"] = blogs
|
||||
c.RenderArgs["key"] = key
|
||||
|
||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||
// 得到博客设置信息
|
||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
c.isMe(userId)
|
||||
|
||||
return c.RenderTemplate("blog/search.html")
|
||||
}
|
||||
|
||||
// 博客设置
|
||||
func (c Blog) Set() revel.Result {
|
||||
userId := c.GetUserId()
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||
|
||||
// 得到博客设置信息
|
||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
||||
c.RenderArgs["title"] = "博客设置"
|
||||
c.RenderArgs["isMe"] = true
|
||||
c.RenderArgs["set"] = true
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
return c.RenderTemplate("blog/set.html")
|
||||
}
|
||||
|
||||
func (c Blog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c Blog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c Blog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// userId可能是其它的
|
||||
func (c Blog) AboutMe(userId string) revel.Result {
|
||||
userInfo := userService.GetUserInfoByAny(userId)
|
||||
if userInfo.UserId == "" {
|
||||
return c.E404()
|
||||
}
|
||||
userId = userInfo.UserId.Hex()
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
|
||||
|
||||
c.RenderArgs["userBlog"] = blogService.GetUserBlog(userId)
|
||||
c.RenderArgs["aboutMe"] = true
|
||||
|
||||
c.RenderArgs["title"] = "关于我"
|
||||
|
||||
c.isMe(userId)
|
||||
|
||||
c.getRecentBlogs(userId)
|
||||
|
||||
return c.RenderTemplate("blog/about_me.html")
|
||||
}
|
||||
|
||||
// 当前的博客是否是我的
|
||||
func (c Blog) isMe(userId string) {
|
||||
c.RenderArgs["isMe"] = userId == c.GetUserId()
|
||||
}
|
||||
|
||||
// 优化, 这里不要得到count
|
||||
func (c Blog) getRecentBlogs(userId string) {
|
||||
_, c.RenderArgs["recentBlogs"] = blogService.ListBlogs(userId, "", 1, 5, "UpdatedTime", false)
|
||||
}
|
||||
|
||||
// 可以不要, 因为注册的时候已经把username设为email了
|
||||
func (c Blog) setRenderUserInfo(userInfo info.User) {
|
||||
if userInfo.Username == "" {
|
||||
userInfo.Username = userInfo.Email
|
||||
}
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 首页
|
||||
type File struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 上传图片 editor
|
||||
func (c File) UploadImage(renderHtml string) revel.Result {
|
||||
if renderHtml == "" {
|
||||
renderHtml = "file/image.html"
|
||||
}
|
||||
|
||||
re := c.uploadImage();
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = "http://leanote.com" + re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
|
||||
return c.RenderTemplate(renderHtml)
|
||||
}
|
||||
|
||||
// 上传的是博客logo
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
return c.UploadImage("file/blog_logo.html");
|
||||
}
|
||||
|
||||
// 拖拉上传
|
||||
func (c File) UploadImageJson(renderHtml string) revel.Result {
|
||||
re := c.uploadImage();
|
||||
re.Id = "http://leanote.com" + re.Id
|
||||
// re.Id = re.Id
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 上传图片, 公用方法
|
||||
func (c File) uploadImage() (re info.Re) {
|
||||
var fileUrlPath = ""
|
||||
var resultCode = 0 // 1表示正常
|
||||
var resultMsg = "内部错误" // 错误信息
|
||||
|
||||
defer func() {
|
||||
re.Id = fileUrlPath
|
||||
re.Code = resultCode
|
||||
re.Msg = resultMsg
|
||||
}()
|
||||
|
||||
file, handel, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
return re
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
|
||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
Log(err)
|
||||
return re
|
||||
}
|
||||
// 生成新的文件名
|
||||
filename := handel.Filename
|
||||
_, ext := SplitFilename(filename)
|
||||
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||
resultMsg = "不是图片"
|
||||
return re
|
||||
}
|
||||
filename = NewGuid() + ext
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
return re
|
||||
}
|
||||
|
||||
// > 2M?
|
||||
if(len(data) > 5 * 1024 * 1024) {
|
||||
resultCode = 0
|
||||
resultMsg = "图片大于2M"
|
||||
return re
|
||||
}
|
||||
|
||||
toPath := dir + "/" + filename;
|
||||
err = ioutil.WriteFile(toPath, data, 0777)
|
||||
if err != nil {
|
||||
LogJ(err)
|
||||
return re
|
||||
}
|
||||
// 改变成gif图片
|
||||
_, toPathGif := TransToGif(toPath, 0, true)
|
||||
|
||||
fileUrlPath += "/" + GetFilename(toPathGif)
|
||||
resultCode = 1
|
||||
resultMsg = "上传成功!"
|
||||
|
||||
return re
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
)
|
||||
|
||||
// 首页
|
||||
|
||||
type Index struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Index) Index() revel.Result {
|
||||
c.SetUserInfo();
|
||||
c.RenderArgs["title"] = "leanote";
|
||||
c.SetLocale()
|
||||
|
||||
return c.RenderTemplate("home/index.html");
|
||||
}
|
||||
|
||||
// 建议
|
||||
func (c Index) Suggestion(addr, suggestion string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = suggestionService.AddSuggestion(info.Suggestion{Addr: addr, UserId: c.GetObjectUserId(), Suggestion: suggestion})
|
||||
|
||||
// 发给我
|
||||
go func() {
|
||||
SendToLeanote("建议", "建议", "UserId: " + c.GetUserId() + " <br /> Suggestions: " + suggestion)
|
||||
}();
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// 首页
|
||||
type Mobile struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Mobile) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
userInfo := c.GetUserInfo()
|
||||
userId := userInfo.UserId.Hex()
|
||||
|
||||
// 没有登录
|
||||
if userId == "" {
|
||||
return c.RenderTemplate("mobile/login.html")
|
||||
}
|
||||
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||
|
||||
return c.RenderTemplate("mobile/index.html");
|
||||
}
|
||||
|
||||
func (c Mobile) Logout() revel.Result {
|
||||
c.ClearSession()
|
||||
return c.RenderTemplate("mobile/login.html");
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
type NoteContentHistory struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 得到list
|
||||
func (c NoteContentHistory) ListHistories(noteId string) revel.Result {
|
||||
histories := noteContentHistoryService.ListHistories(noteId, c.GetUserId())
|
||||
|
||||
return c.RenderJson(histories)
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"labix.org/v2/mgo/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/lea/html2image"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "os"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
)
|
||||
|
||||
type Note struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 笔记首页, 判断是否已登录
|
||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||
// 否则, 转向登录页面
|
||||
func (c Note) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
userInfo := c.GetUserInfo()
|
||||
|
||||
userId := userInfo.UserId.Hex()
|
||||
|
||||
// 没有登录
|
||||
if userId == "" {
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
// 已登录了, 那么得到所有信息
|
||||
notebooks := notebookService.GetNotebooks(userId)
|
||||
shareNotebooks, sharedUserInfos := shareService.GetShareNotebooks(userId)
|
||||
|
||||
// 还需要按时间排序(DESC)得到notes
|
||||
notes := []info.Note{}
|
||||
noteContent := info.NoteContent{}
|
||||
if len(notebooks) > 0 {
|
||||
// _, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||
// 变成最新
|
||||
_, notes = noteService.ListNotes(c.GetUserId(), "", false, c.GetPage(), 50, defaultSortField, false, false);
|
||||
if len(notes) > 0 {
|
||||
noteContent = noteService.GetNoteContent(notes[0].NoteId.Hex(), userId)
|
||||
}
|
||||
}
|
||||
// 当然, 还需要得到第一个notes的content
|
||||
//...
|
||||
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||
c.RenderArgs["shareNotebooks"] = c.Json(shareNotebooks)
|
||||
c.RenderArgs["sharedUserInfos"] = c.Json(sharedUserInfos)
|
||||
|
||||
c.RenderArgs["notes"] = c.Json(notes)
|
||||
c.RenderArgs["noteContentJson"] = c.Json(noteContent)
|
||||
c.RenderArgs["noteContent"] = noteContent.Content
|
||||
|
||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||
|
||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||
return c.RenderTemplate("note/note-dev.html")
|
||||
} else {
|
||||
return c.RenderTemplate("note/note.html")
|
||||
}
|
||||
}
|
||||
|
||||
// 首页, 判断是否已登录
|
||||
// 已登录, 得到用户基本信息(notebook, shareNotebook), 跳转到index.html中
|
||||
// 否则, 转向登录页面
|
||||
func (c Note) ListNotes(notebookId string) revel.Result {
|
||||
_, notes := noteService.ListNotes(c.GetUserId(), notebookId, false, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||
return c.RenderJson(notes)
|
||||
}
|
||||
|
||||
// 得到trash
|
||||
func (c Note) ListTrashNotes() revel.Result {
|
||||
_, notes := noteService.ListNotes(c.GetUserId(), "", true, c.GetPage(), pageSize, defaultSortField, false, false);
|
||||
return c.RenderJson(notes)
|
||||
}
|
||||
|
||||
// 得到内容
|
||||
func (c Note) GetNoteContent(noteId string) revel.Result {
|
||||
noteContent := noteService.GetNoteContent(noteId, c.GetUserId())
|
||||
return c.RenderJson(noteContent)
|
||||
}
|
||||
|
||||
// 更新note或content
|
||||
// 肯定会传userId(谁的), NoteId
|
||||
// 会传Title, Content, Tags, 一种或几种
|
||||
type NoteOrContent struct {
|
||||
NotebookId string
|
||||
NoteId string
|
||||
UserId string
|
||||
Title string
|
||||
Desc string
|
||||
ImgSrc string
|
||||
Tags []string
|
||||
Content string
|
||||
Abstract string
|
||||
IsNew bool
|
||||
IsMarkdown bool
|
||||
FromUserId string // 为共享而新建
|
||||
IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog
|
||||
}
|
||||
// 这里不能用json, 要用post
|
||||
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
// 新添加note
|
||||
LogJ(noteOrContent)
|
||||
if noteOrContent.IsNew {
|
||||
userId := c.GetObjectUserId();
|
||||
myUserId := userId
|
||||
// 为共享新建?
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
}
|
||||
|
||||
note := info.Note{UserId: userId,
|
||||
NoteId: bson.ObjectIdHex(noteOrContent.NoteId),
|
||||
NotebookId: bson.ObjectIdHex(noteOrContent.NotebookId),
|
||||
Title: noteOrContent.Title,
|
||||
Tags: noteOrContent.Tags,
|
||||
Desc: noteOrContent.Desc,
|
||||
ImgSrc: noteOrContent.ImgSrc,
|
||||
IsBlog: noteOrContent.IsBlog,
|
||||
IsMarkdown: noteOrContent.IsMarkdown,
|
||||
};
|
||||
noteContent := info.NoteContent{NoteId: note.NoteId,
|
||||
UserId: userId,
|
||||
IsBlog: note.IsBlog,
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract};
|
||||
|
||||
note = noteService.AddNoteAndContent(note, noteContent, myUserId)
|
||||
return c.RenderJson(note)
|
||||
}
|
||||
|
||||
noteUpdate := bson.M{}
|
||||
needUpdateNote := false
|
||||
|
||||
// Desc前台传来
|
||||
if c.Has("Desc") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Desc"] = noteOrContent.Desc;
|
||||
}
|
||||
if c.Has("ImgSrc") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["ImgSrc"] = noteOrContent.ImgSrc;
|
||||
}
|
||||
if c.Has("Title") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Title"] = noteOrContent.Title;
|
||||
}
|
||||
|
||||
if c.Has("Tags[]") {
|
||||
needUpdateNote = true
|
||||
noteUpdate["Tags"] = noteOrContent.Tags;
|
||||
}
|
||||
|
||||
if needUpdateNote {
|
||||
noteService.UpdateNote(noteOrContent.UserId, c.GetUserId(),
|
||||
noteOrContent.NoteId, noteUpdate)
|
||||
}
|
||||
|
||||
//-------------
|
||||
|
||||
if c.Has("Content") {
|
||||
noteService.UpdateNoteContent(noteOrContent.UserId, c.GetUserId(),
|
||||
noteOrContent.NoteId, noteOrContent.Content, noteOrContent.Abstract)
|
||||
}
|
||||
|
||||
return c.RenderJson(true)
|
||||
}
|
||||
|
||||
// 删除note/ 删除别人共享给我的笔记
|
||||
// userId 是note.UserId
|
||||
func (c Note) DeleteNote(noteId, userId string, isShared bool) revel.Result {
|
||||
if(!isShared) {
|
||||
return c.RenderJson(trashService.DeleteNote(noteId, c.GetUserId()));
|
||||
}
|
||||
|
||||
return c.RenderJson(trashService.DeleteSharedNote(noteId, userId, c.GetUserId()));
|
||||
}
|
||||
// 删除trash
|
||||
func (c Note) DeleteTrash(noteId string) revel.Result {
|
||||
return c.RenderJson(trashService.DeleteTrash(noteId, c.GetUserId()));
|
||||
}
|
||||
// 移动note
|
||||
func (c Note) MoveNote(noteId, notebookId string) revel.Result {
|
||||
return c.RenderJson(noteService.MoveNote(noteId, notebookId, c.GetUserId()));
|
||||
}
|
||||
// 复制note
|
||||
func (c Note) CopyNote(noteId, notebookId string) revel.Result {
|
||||
return c.RenderJson(noteService.CopyNote(noteId, notebookId, c.GetUserId()));
|
||||
}
|
||||
// 复制别人共享的笔记给我
|
||||
func (c Note) CopySharedNote(noteId, notebookId, fromUserId string) revel.Result {
|
||||
return c.RenderJson(noteService.CopySharedNote(noteId, notebookId, fromUserId, c.GetUserId()));
|
||||
}
|
||||
|
||||
//------------
|
||||
// search
|
||||
// 通过title搜索
|
||||
func (c Note) SearchNote(key string) revel.Result {
|
||||
_, blogs := noteService.SearchNote(key, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false, false)
|
||||
return c.RenderJson(blogs)
|
||||
}
|
||||
// 通过tags搜索
|
||||
func (c Note) SearchNoteByTags(tags []string) revel.Result {
|
||||
_, blogs := noteService.SearchNoteByTags(tags, c.GetUserId(), c.GetPage(), pageSize, "UpdatedTime", false)
|
||||
return c.RenderJson(blogs)
|
||||
}
|
||||
|
||||
//-----------------
|
||||
// html2image
|
||||
func (c Note) Html2Image(noteId string) revel.Result {
|
||||
re := info.NewRe()
|
||||
userId := c.GetUserId()
|
||||
note := noteService.GetNote(noteId, userId)
|
||||
if note.NoteId == "" {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
content := noteService.GetNoteContent(noteId, userId)
|
||||
|
||||
// path 判断是否需要重新生成之
|
||||
fileUrlPath := "/upload/" + userId + "/images/weibo"
|
||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
||||
if !ClearDir(dir) {
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
filename := note.NoteId.Hex() + ".png";
|
||||
path := dir + "/" + filename
|
||||
|
||||
// 生成之
|
||||
html2image.ToImage(userId, c.GetUsername(), noteId, note.Title, content.Content, path)
|
||||
|
||||
re.Ok = true
|
||||
re.Id = fileUrlPath + "/" + filename
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
type Notebook struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 得到笔记本
|
||||
// 该用户下的
|
||||
func (c Notebook) GetNotebooks() {
|
||||
}
|
||||
|
||||
func (c Notebook) Index(notebook info.Notebook, i int, name string) revel.Result {
|
||||
return c.RenderJson(notebook)
|
||||
}
|
||||
|
||||
// 得到用户的所有笔记本
|
||||
func (c Notebook) getNotebooks() revel.Result {
|
||||
re := notebookService.GetNotebooks(c.GetUserId())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
func (c Notebook) DeleteNotebook(notebookId string) revel.Result {
|
||||
re, msg := notebookService.DeleteNotebook(c.GetUserId(), notebookId)
|
||||
return c.RenderJson(info.Re{Ok: re, Msg: msg})
|
||||
}
|
||||
|
||||
// 添加notebook
|
||||
func (c Notebook) AddNotebook(notebookId, title string) revel.Result {
|
||||
notebook := info.Notebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||
Title: title,
|
||||
Seq: -1,
|
||||
UserId: c.GetObjectUserId()}
|
||||
re := notebookService.AddNotebook(notebook)
|
||||
|
||||
if(re) {
|
||||
return c.RenderJson(notebook)
|
||||
} else {
|
||||
return c.RenderJson(false)
|
||||
}
|
||||
}
|
||||
// 修改标题
|
||||
func (c Notebook) UpdateNotebookTitle(notebookId, title string) revel.Result {
|
||||
return c.RenderJson(notebookService.UpdateNotebookTitle(notebookId, c.GetUserId(), title))
|
||||
}
|
||||
// 排序
|
||||
func (c Notebook) SortNotebooks(notebookId2Seqs map[string]int) revel.Result {
|
||||
return c.RenderJson(notebookService.SortNotebooks(c.GetUserId(), notebookId2Seqs))
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/lea/netutil"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Oauth struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
var oauthCfg = &oauth.Config{
|
||||
ClientId: "3790fbf1fc14bc6c5d85",
|
||||
ClientSecret: "e9dadfe601c7caa6df9b33db3e7539945c60dfa2",
|
||||
AuthURL: "https://github.com/login/oauth/authorize",
|
||||
TokenURL: "https://github.com/login/oauth/access_token",
|
||||
RedirectURL: "http://leanote.com/oauth/githubCallback",
|
||||
Scope: "user",
|
||||
}
|
||||
|
||||
// 用户允许后, github返回到leanote
|
||||
// 通过code得到token
|
||||
// https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Foauth2callback&response_type=code&scope=user&state=
|
||||
func (c Oauth) GithubCallback(code string) revel.Result {
|
||||
t := &oauth.Transport{Config: oauthCfg}
|
||||
|
||||
// Exchange the received code for a token
|
||||
tok, err := t.Exchange(code)
|
||||
token := tok.AccessToken
|
||||
if err != nil || token == "" {
|
||||
c.RenderArgs["title"] = "error"
|
||||
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||
}
|
||||
|
||||
// 得到用户信息
|
||||
profileInfoURL := "https://api.github.com/user"
|
||||
url := fmt.Sprintf("%s?access_token=%s", profileInfoURL, token)
|
||||
content, err2 := netutil.GetContent(url)
|
||||
if err2 != nil {
|
||||
c.RenderArgs["title"] = "error"
|
||||
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||
}
|
||||
// 转成map
|
||||
profileInfo := map[string]interface{}{}
|
||||
Log(string(content))
|
||||
err2 = json.Unmarshal(content, &profileInfo)
|
||||
if err2 != nil {
|
||||
c.RenderArgs["title"] = "error"
|
||||
return c.RenderTemplate("oauth/oauth_callback_error.html")
|
||||
}
|
||||
|
||||
usernameI := profileInfo["login"]
|
||||
|
||||
username, _ := usernameI.(string)
|
||||
userId := username
|
||||
|
||||
// 注册
|
||||
isExists, userInfo := authService.ThirdRegister("github", userId, username)
|
||||
c.RenderArgs["isExists"] = isExists
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
|
||||
// 登录之
|
||||
c.SetSession(userInfo)
|
||||
|
||||
return c.Redirect("/note")
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "labix.org/v2/mgo/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
)
|
||||
|
||||
type Share struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 添加共享note
|
||||
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
// 自己不能给自己添加共享
|
||||
myEmail := c.GetEmail();
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue;
|
||||
}
|
||||
if(myEmail != email) {
|
||||
ok, msg, userId := shareService.AddShareNote(noteId, perm, c.GetUserId(), email);
|
||||
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
|
||||
|
||||
} else {
|
||||
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
|
||||
}
|
||||
}
|
||||
|
||||
return c.RenderJson(status)
|
||||
}
|
||||
|
||||
// 添加共享notebook
|
||||
func (c Share) AddShareNotebook(notebookId string, emails []string, perm int) revel.Result {
|
||||
status := make(map[string]info.Re, len(emails))
|
||||
// 自己不能给自己添加共享
|
||||
myEmail := c.GetEmail();
|
||||
for _, email := range emails {
|
||||
if email == "" {
|
||||
continue;
|
||||
}
|
||||
if(myEmail != email) {
|
||||
ok, msg, userId := shareService.AddShareNotebook(notebookId, perm, c.GetUserId(), email);
|
||||
status[email] = info.Re{Ok: ok, Msg: msg, Id: userId}
|
||||
} else {
|
||||
status[email] = info.Re{Ok: false, Msg: "不能分享给自己"}
|
||||
}
|
||||
}
|
||||
|
||||
return c.RenderJson(status)
|
||||
}
|
||||
|
||||
// 得到notes
|
||||
// userId 该userId分享给我的
|
||||
func (c Share) ListShareNotes(notebookId, userId string) revel.Result {
|
||||
// 表示是默认笔记本, 不是某个特定notebook的共享
|
||||
var notes []info.ShareNoteWithPerm
|
||||
if notebookId == "" {
|
||||
notes = shareService.ListShareNotes(c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false);
|
||||
return c.RenderJson(notes)
|
||||
} else {
|
||||
// 有notebookId的
|
||||
return c.RenderJson(shareService.ListShareNotesByNotebookId(notebookId, c.GetUserId(), userId, c.GetPage(), pageSize, defaultSortField, false));
|
||||
}
|
||||
}
|
||||
|
||||
// 得到内容
|
||||
// sharedUserId 是谁的笔记
|
||||
func (c Share) GetShareNoteContent(noteId, sharedUserId string) revel.Result {
|
||||
noteContent := shareService.GetShareNoteContent(noteId, c.GetUserId(), sharedUserId)
|
||||
return c.RenderJson(noteContent)
|
||||
}
|
||||
|
||||
// 查看note的分享信息
|
||||
// 分享给了哪些用户和权限
|
||||
// ShareNotes表 userId = me, noteId = ...
|
||||
// 还要查看该note的notebookId分享的信息
|
||||
func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
||||
note := noteService.GetNote(noteId, c.GetUserId())
|
||||
|
||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||
|
||||
c.RenderArgs["isNote"] = true
|
||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||
c.RenderArgs["title"] = note.Title
|
||||
|
||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||
}
|
||||
func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
||||
notebook := notebookService.GetNotebook(notebookId, c.GetUserId())
|
||||
|
||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||
|
||||
c.RenderArgs["isNote"] = false
|
||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||
c.RenderArgs["title"] = notebook.Title
|
||||
|
||||
return c.RenderTemplate("share/note_notebook_share_user_infos.html")
|
||||
}
|
||||
|
||||
//------------
|
||||
// 改变share note 权限
|
||||
func (c Share) UpdateShareNotePerm(noteId string, perm int, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.UpdateShareNotePerm(noteId, perm, c.GetUserId(), toUserId));
|
||||
}
|
||||
|
||||
// 改变share notebook 权限
|
||||
func (c Share) UpdateShareNotebookPerm(notebookId string, perm int, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.UpdateShareNotebookPerm(notebookId, perm, c.GetUserId(), toUserId));
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 删除share note
|
||||
func (c Share) DeleteShareNote(noteId string, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, c.GetUserId(), toUserId));
|
||||
}
|
||||
// 删除share notebook
|
||||
func (c Share) DeleteShareNotebook(notebookId string, toUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, c.GetUserId(), toUserId));
|
||||
}
|
||||
|
||||
// 删除share note, 被共享方删除
|
||||
func (c Share) DeleteShareNoteBySharedUser(noteId string, fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNote(noteId, fromUserId, c.GetUserId()));
|
||||
}
|
||||
// 删除share notebook, 被共享方删除
|
||||
func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteShareNotebook(notebookId, fromUserId, c.GetUserId()));
|
||||
}
|
||||
|
||||
// 删除fromUserId分享给我的所有note, notebook
|
||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// "labix.org/v2/mgo/bson"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
"fmt"
|
||||
// "math"
|
||||
// "os"
|
||||
// "path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// 修改用户名, 需要重置session
|
||||
func (c User) UpdateUsername(username string) revel.Result {
|
||||
re := info.NewRe();
|
||||
// 判断是否满足最基本的, 4位, 不含特殊字符, 大小写无关. email大小写无关
|
||||
if len(username) < 4 {
|
||||
re.Ok = false
|
||||
re.Msg = "至少4位"
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
if !IsUsername(username) {
|
||||
re.Ok = false
|
||||
re.Msg = "不能包含特殊字符"
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = userService.UpdateUsername(c.GetUserId(), username)
|
||||
if(re.Ok) {
|
||||
c.UpdateSession("Username", username)
|
||||
}
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
func (c User) UpdatePwd(oldPwd, pwd string) revel.Result {
|
||||
re := info.NewRe();
|
||||
if oldPwd == "" {
|
||||
re.Msg = "旧密码错误"
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = IsGoodPwd(pwd)
|
||||
if !re.Ok {
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = userService.UpdatePwd(c.GetUserId(), oldPwd, pwd)
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
// 更新主题
|
||||
func (c User) UpdateTheme(theme string) revel.Result {
|
||||
re := info.NewRe();
|
||||
re.Ok = userService.UpdateTheme(c.GetUserId(), theme)
|
||||
if re.Ok {
|
||||
c.UpdateSession("Theme", theme)
|
||||
}
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
// 发送邀请链接
|
||||
func (c User) SendRegisterEmail(content, toEmail string) revel.Result {
|
||||
re := info.NewRe()
|
||||
if content == "" || !IsEmail(toEmail) {
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
var userInfo = c.GetUserInfo();
|
||||
url := "http://leanote.com/register?from=" + userInfo.Username
|
||||
body := fmt.Sprintf("点击链接注册leanote: <a href='%v'>%v</a>. ", url, url);
|
||||
body = content + "<br />" + body
|
||||
re.Ok = SendEmail(toEmail, userInfo.Username + "邀请您注册leanote", "邀请注册", body)
|
||||
|
||||
return c.RenderJson(re);
|
||||
}
|
||||
|
||||
//---------------------------
|
||||
|
||||
// 重新发送激活邮件
|
||||
func (c User) ReSendActiveEmail() revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = userService.RegisterSendActiveEmail(c.GetUserId(), c.GetEmail())
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 修改Email发送激活邮箱
|
||||
func (c User) UpdateEmailSendActiveEmail(email string) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok, re.Msg = userService.UpdateEmailSendActiveEmail(c.GetUserId(), email)
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 通过点击链接
|
||||
// 修改邮箱
|
||||
func (c User) UpdateEmail(token string) revel.Result {
|
||||
c.SetUserInfo();
|
||||
|
||||
ok, msg, email := userService.UpdateEmail(token)
|
||||
|
||||
c.RenderArgs["title"] = "验证邮箱"
|
||||
c.RenderArgs["ok"] = ok
|
||||
c.RenderArgs["msg"] = msg
|
||||
c.RenderArgs["email"] = email
|
||||
|
||||
// 修改session
|
||||
if ok {
|
||||
c.UpdateSession("Email", email)
|
||||
}
|
||||
|
||||
return c.RenderTemplate("user/update_email.html")
|
||||
}
|
||||
|
||||
// 注册后激活邮箱
|
||||
func (c User) ActiveEmail(token string) revel.Result {
|
||||
c.SetUserInfo();
|
||||
|
||||
ok, msg, email := userService.ActiveEmail(token)
|
||||
|
||||
// 需要修改session
|
||||
if ok {
|
||||
c.UpdateSession("Verified", "1");
|
||||
}
|
||||
|
||||
c.RenderArgs["title"] = "验证邮箱"
|
||||
c.RenderArgs["ok"] = ok
|
||||
c.RenderArgs["msg"] = msg
|
||||
c.RenderArgs["email"] = email
|
||||
|
||||
return c.RenderTemplate("user/active_email.html")
|
||||
}
|
||||
|
||||
//------------
|
||||
// 第三方账号添加leanote账号
|
||||
func (c User) AddAccount(email, pwd string) revel.Result {
|
||||
re := info.NewRe()
|
||||
|
||||
if email == "" {
|
||||
re.Msg = "请输入邮箱"
|
||||
return c.RenderJson(re)
|
||||
} else if !IsEmail(email) {
|
||||
re.Msg = "请输入正确的邮箱"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
// 密码
|
||||
if pwd == "" {
|
||||
re.Msg = "请输入密码"
|
||||
return c.RenderJson(re)
|
||||
} else if len(pwd) < 6 {
|
||||
re.Msg = "密码长度至少6位"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
re.Ok, re.Msg = userService.ThirdAddUser(c.GetUserId(), email, pwd)
|
||||
|
||||
if re.Ok {
|
||||
c.UpdateSession("Email", email);
|
||||
}
|
||||
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
//-----------------
|
||||
// 用户偏爱
|
||||
func (c User) UpdateColumnWidth(notebookWidth, noteListWidth int) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = userService.UpdateColumnWidth(c.GetUserId(), notebookWidth, noteListWidth)
|
||||
if re.Ok {
|
||||
c.UpdateSession("NotebookWidth", strconv.Itoa(notebookWidth));
|
||||
c.UpdateSession("NoteListWidth", strconv.Itoa(noteListWidth));
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
func (c User) UpdateLeftIsMin(leftIsMin bool) revel.Result {
|
||||
re := info.NewRe()
|
||||
re.Ok = userService.UpdateLeftIsMin(c.GetUserId(), leftIsMin)
|
||||
if re.Ok {
|
||||
if leftIsMin {
|
||||
c.UpdateSession("LeftIsMin", "1");
|
||||
} else {
|
||||
c.UpdateSession("LeftIsMin", "0");
|
||||
}
|
||||
}
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 该文件初始化所有service方法
|
||||
|
||||
var userService *service.UserService
|
||||
var noteService *service.NoteService
|
||||
var trashService *service.TrashService
|
||||
var notebookService *service.NotebookService
|
||||
var noteContentHistoryService *service.NoteContentHistoryService
|
||||
|
||||
var authService *service.AuthService
|
||||
var shareService *service.ShareService
|
||||
var blogService *service.BlogService
|
||||
var tagService *service.TagService
|
||||
var pwdService *service.PwdService
|
||||
var tokenService *service.TokenService
|
||||
var suggestionService *service.SuggestionService
|
||||
|
||||
var pageSize = 1000
|
||||
var defaultSortField = "UpdatedTime"
|
||||
var leanoteUserId = "52d26b4e99c37b609a000001"
|
||||
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// Index 除了Note之外都不需要
|
||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||
"Login": true,
|
||||
"DoLogin": true,
|
||||
"Logout": true,
|
||||
"Register": true,
|
||||
"DoRegister": true,
|
||||
"FindPasswword": true,
|
||||
"DoFindPassword": true,
|
||||
"FindPassword2": true,
|
||||
"FindPasswordUpdate": true,
|
||||
"Suggestion": true,
|
||||
},
|
||||
"Blog": map[string]bool{"Index": true,
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"SearchBlog": true,
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
"ActiveEmail":true,
|
||||
},
|
||||
"oauth": map[string]bool{"githubCallback": true},
|
||||
}
|
||||
func needValidate(controller, method string) bool {
|
||||
// 在里面
|
||||
if v, ok := commonUrl[controller]; ok {
|
||||
// 不在commonUrl里
|
||||
if _, ok2 := v[method]; ok2 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
// 全部变成首字大写
|
||||
var controller = strings.Title(c.Name)
|
||||
var method = strings.Title(c.MethodName)
|
||||
|
||||
// 是否需要验证?
|
||||
if !needValidate(controller, method) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// 验证是否已登录
|
||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||
return nil // 已登录
|
||||
}
|
||||
|
||||
// 没有登录, 判断是否是ajax操作
|
||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
re := info.NewRe()
|
||||
re.Msg = "NOTLOGIN"
|
||||
return c.RenderJson(re)
|
||||
}
|
||||
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
func init() {
|
||||
// interceptor
|
||||
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Index{}) // Index.Note自己校验
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Notebook{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Note{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Share{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||
|
||||
// service
|
||||
|
||||
userService = &service.UserService{}
|
||||
noteService = &service.NoteService{}
|
||||
trashService = &service.TrashService{}
|
||||
notebookService = &service.NotebookService{}
|
||||
noteContentHistoryService = &service.NoteContentHistoryService{}
|
||||
authService = &service.AuthService{}
|
||||
shareService = &service.ShareService{}
|
||||
blogService = &service.BlogService{}
|
||||
tagService = &service.TagService{}
|
||||
pwdService = &service.PwdService{}
|
||||
tokenService = &service.TokenService{}
|
||||
suggestionService = &service.SuggestionService{}
|
||||
|
||||
revel.OnAppStart(func() {
|
||||
leanoteUserId, _ = revel.Config.String("adminUsername")
|
||||
})
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// Init mgo and the common DAO
|
||||
|
||||
// 数据连接
|
||||
var Session *mgo.Session
|
||||
|
||||
// 各个表的Collection对象
|
||||
var Notebooks *mgo.Collection
|
||||
var Notes *mgo.Collection
|
||||
var NoteContents *mgo.Collection
|
||||
var NoteContentHistories *mgo.Collection
|
||||
|
||||
var ShareNotes *mgo.Collection
|
||||
var ShareNotebooks *mgo.Collection
|
||||
var HasShareNotes *mgo.Collection
|
||||
var Blogs *mgo.Collection
|
||||
var Users *mgo.Collection
|
||||
|
||||
var Tags *mgo.Collection
|
||||
var TagNotes *mgo.Collection
|
||||
|
||||
var UserBlogs *mgo.Collection
|
||||
|
||||
var Tokens *mgo.Collection
|
||||
|
||||
var Suggestions *mgo.Collection
|
||||
|
||||
// 初始化时连接数据库
|
||||
func Init() {
|
||||
var url string
|
||||
var ok bool
|
||||
config := revel.Config;
|
||||
url, ok = config.String("db.url")
|
||||
dbname, _ := config.String("db.dbname")
|
||||
if !ok {
|
||||
host, _ := revel.Config.String("db.host")
|
||||
port, _ := revel.Config.String("db.port")
|
||||
username, _ := revel.Config.String("db.username")
|
||||
password, _ := revel.Config.String("db.password")
|
||||
url = "mongodb://" + username + ":" + password + "@" + host + ":" + port + "/" + dbname
|
||||
}
|
||||
|
||||
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
||||
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||
var err error
|
||||
Session, err = mgo.Dial(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Optional. Switch the session to a monotonic behavior.
|
||||
Session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
// notebook
|
||||
Notebooks = Session.DB(dbname).C("notebooks")
|
||||
|
||||
// notes
|
||||
Notes = Session.DB(dbname).C("notes")
|
||||
|
||||
// noteContents
|
||||
NoteContents = Session.DB(dbname).C("note_contents")
|
||||
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
||||
|
||||
// share
|
||||
ShareNotes = Session.DB(dbname).C("share_notes")
|
||||
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
||||
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
||||
|
||||
// user
|
||||
Users = Session.DB(dbname).C("users")
|
||||
|
||||
// blog
|
||||
Blogs = Session.DB(dbname).C("blogs")
|
||||
|
||||
// tag
|
||||
Tags = Session.DB(dbname).C("tags")
|
||||
TagNotes = Session.DB(dbname).C("tag_notes")
|
||||
|
||||
// blog
|
||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||
|
||||
// find password
|
||||
Tokens = Session.DB(dbname).C("tokens")
|
||||
|
||||
//
|
||||
Suggestions = Session.DB(dbname).C("suggestions")
|
||||
}
|
||||
|
||||
func init() {
|
||||
revel.OnAppStart(func() {
|
||||
Init()
|
||||
})
|
||||
}
|
||||
|
||||
func close() {
|
||||
Session.Close()
|
||||
}
|
||||
|
||||
// common DAO
|
||||
// 公用方法
|
||||
|
||||
//----------------------
|
||||
|
||||
func Insert(collection *mgo.Collection, i interface{}) bool {
|
||||
err := collection.Insert(i)
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
//----------------------
|
||||
|
||||
// 适合一条记录全部更新
|
||||
func Update(collection *mgo.Collection, query interface{}, i interface{}) bool {
|
||||
err := collection.Update(query, i)
|
||||
return Err(err)
|
||||
}
|
||||
func Upsert(collection *mgo.Collection, query interface{}, i interface{}) bool {
|
||||
_, err := collection.Upsert(query, i)
|
||||
return Err(err)
|
||||
}
|
||||
func UpdateAll(collection *mgo.Collection, query interface{}, i interface{}) bool {
|
||||
_, err := collection.UpdateAll(query, i)
|
||||
return Err(err)
|
||||
}
|
||||
func UpdateByIdAndUserId(collection *mgo.Collection, id, userId string, i interface{}) bool {
|
||||
err := collection.Update(GetIdAndUserIdQ(id, userId), i)
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i interface{}) bool {
|
||||
err := collection.Update(GetIdAndUserIdBsonQ(id, userId), i)
|
||||
return Err(err)
|
||||
}
|
||||
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
||||
}
|
||||
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
||||
}
|
||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
//
|
||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||
return Err(err)
|
||||
}
|
||||
// 查询条件和值
|
||||
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
//------------------------
|
||||
|
||||
// 删除一条
|
||||
func Delete(collection *mgo.Collection, q interface{}) bool {
|
||||
err := collection.Remove(q)
|
||||
return Err(err)
|
||||
}
|
||||
func DeleteByIdAndUserId(collection *mgo.Collection, id, userId string) bool {
|
||||
err := collection.Remove(GetIdAndUserIdQ(id, userId))
|
||||
return Err(err)
|
||||
}
|
||||
func DeleteByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId) bool {
|
||||
err := collection.Remove(GetIdAndUserIdBsonQ(id, userId))
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
// 删除所有
|
||||
func DeleteAllByIdAndUserId(collection *mgo.Collection, id, userId string) bool {
|
||||
_, err := collection.RemoveAll(GetIdAndUserIdQ(id, userId))
|
||||
return Err(err)
|
||||
}
|
||||
func DeleteAllByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId) bool {
|
||||
_, err := collection.RemoveAll(GetIdAndUserIdBsonQ(id, userId))
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
func DeleteAll(collection *mgo.Collection, q interface{}) bool {
|
||||
_, err := collection.RemoveAll(q)
|
||||
return Err(err)
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
|
||||
func Get(collection *mgo.Collection, id string, i interface{}) {
|
||||
collection.FindId(bson.ObjectIdHex(id)).One(i)
|
||||
}
|
||||
func Get2(collection *mgo.Collection, id bson.ObjectId, i interface{}) {
|
||||
collection.FindId(id).One(i)
|
||||
}
|
||||
|
||||
func GetByQ(collection *mgo.Collection, q interface{}, i interface{}) {
|
||||
collection.Find(q).One(i)
|
||||
}
|
||||
func ListByQ(collection *mgo.Collection, q interface{}, i interface{}) {
|
||||
collection.Find(q).All(i)
|
||||
}
|
||||
|
||||
func ListByQLimit(collection *mgo.Collection, q interface{}, i interface{}, limit int) {
|
||||
collection.Find(q).Limit(limit).All(i)
|
||||
}
|
||||
|
||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||
func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||
selector := make(bson.M, len(fields))
|
||||
for _, field := range fields {
|
||||
selector[field] = true
|
||||
}
|
||||
collection.Find(q).Select(selector).One(i)
|
||||
}
|
||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||
selector := make(bson.M, len(fields))
|
||||
for _, field := range fields {
|
||||
selector[field] = true
|
||||
}
|
||||
collection.Find(q).Select(selector).All(i)
|
||||
}
|
||||
func GetByIdAndUserId(collection *mgo.Collection, id, userId string, i interface{}) {
|
||||
collection.Find(GetIdAndUserIdQ(id, userId)).One(i)
|
||||
}
|
||||
func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i interface{}) {
|
||||
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
||||
}
|
||||
|
||||
//----------------------
|
||||
|
||||
func Count(collection *mgo.Collection, q interface{}) int {
|
||||
cnt, err := collection.Find(q).Count()
|
||||
if err != nil {
|
||||
Err(err)
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
func Has(collection *mgo.Collection, q interface{}) bool {
|
||||
if Count(collection, q) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//-----------------
|
||||
|
||||
// 得到主键和userId的复合查询条件
|
||||
func GetIdAndUserIdQ(id, userId string) bson.M {
|
||||
return bson.M{"_id": bson.ObjectIdHex(id), "UserId": bson.ObjectIdHex(userId)}
|
||||
}
|
||||
func GetIdAndUserIdBsonQ(id, userId bson.ObjectId) bson.M {
|
||||
return bson.M{"_id": id, "UserId": userId}
|
||||
}
|
||||
|
||||
// DB处理错误
|
||||
func Err(err error) bool {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
// 删除时, 查找
|
||||
if err.Error() == "not found" {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"bufio"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// convert revel msg to js msg
|
||||
|
||||
var msgBasePath = "/Users/life/Documents/Go/package/src/leanote/messages/"
|
||||
var targetBasePath = "/Users/life/Documents/Go/package/src/leanote/public/js/i18n/"
|
||||
func parse(filename string) {
|
||||
file, err := os.Open(msgBasePath + filename)
|
||||
reader := bufio.NewReader(file)
|
||||
msg := map[string]string{}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for true {
|
||||
line, _, err := reader.ReadLine()
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
// 对每一行进行处理
|
||||
if line[0] == '#' || line[1] == '#' {
|
||||
continue;
|
||||
}
|
||||
lineStr := string(line)
|
||||
|
||||
// 找到第一个=位置
|
||||
pos := strings.Index(lineStr, "=")
|
||||
|
||||
if pos < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
key := string(line[0:pos])
|
||||
value := string(line[pos+1:])
|
||||
|
||||
// fmt.Println(lineStr)
|
||||
// fmt.Println(value)
|
||||
|
||||
msg[key] = value
|
||||
}
|
||||
|
||||
// JSON
|
||||
b, _ := json.Marshal(msg)
|
||||
str := string(b)
|
||||
fmt.Println(str);
|
||||
|
||||
targetName := targetBasePath + filename + ".js"
|
||||
file2, err2 := os.OpenFile(targetName, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err2 != nil {
|
||||
file2, err2 = os.Create(targetName)
|
||||
}
|
||||
file2.WriteString("var MSG = " + str + ";")
|
||||
}
|
||||
|
||||
// 生成js的i18n文件
|
||||
func main() {
|
||||
parse("msg.en")
|
||||
parse("msg.zh")
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// 只为blog, 不为note
|
||||
|
||||
type BlogItem struct {
|
||||
Note
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
}
|
||||
|
||||
type UserBlogBase struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
}
|
||||
|
||||
type UserBlogComment struct {
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
DisqusId string `DisqusId`
|
||||
}
|
||||
|
||||
type UserBlogStyle struct {
|
||||
Style string `Style` // 风格
|
||||
}
|
||||
|
||||
// 每个用户一份博客设置信息
|
||||
type UserBlog struct {
|
||||
UserId bson.ObjectId `bson:"_id"` // 谁的
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
DisqusId string `DisqusId`
|
||||
|
||||
Style string `Style` // 风格
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 只存笔记基本信息
|
||||
// 内容不存放
|
||||
type Note struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"` // 谁的
|
||||
CreatedUserId bson.ObjectId `bson:"CreatedUserId,omitempty"` // 谁创建的(UserId != CreatedUserId, 是因为共享). 只是共享才有, 默认为空, 不存 必须要加omitempty
|
||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||
Title string `Title` // 标题
|
||||
Desc string `Desc` // 描述, 非html
|
||||
|
||||
ImgSrc string `ImgSrc` // 图片, 第一张缩略图地址
|
||||
Tags []string `Tags,omitempty`
|
||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||
|
||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||
|
||||
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
}
|
||||
|
||||
// 内容
|
||||
type NoteContent struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
|
||||
IsBlog bool `IsBlog,omitempty` // 为了搜索博客
|
||||
|
||||
Content string `Content`
|
||||
Abstract string `Abstract` // 摘要, 有html标签, 比content短, 在博客展示需要, 不放在notes表中
|
||||
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||
}
|
||||
|
||||
// 基本信息和内容在一起
|
||||
type NoteAndContent struct {
|
||||
Note
|
||||
NoteContent
|
||||
}
|
||||
|
||||
// 历史记录
|
||||
// 每一个历史记录对象
|
||||
type EachHistory struct {
|
||||
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
||||
UpdatedTime time.Time `UpdatedTime`
|
||||
Content string `Content`
|
||||
}
|
||||
type NoteContentHistory struct {
|
||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||
Histories []EachHistory `Histories`
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 在数据库中每个
|
||||
// 修改字段必须要在NotebookService中修改ParseAndSortNotebooks(没有匿名字段), 以后重构
|
||||
type Notebook struct {
|
||||
NotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
||||
Seq int `Seq` // 排序
|
||||
Title string `Title` // 标题
|
||||
NumberNotes int `NumberNotes` // 笔记数
|
||||
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||
CreatedTime time.Time `CreatedTime,omitempty`
|
||||
UpdatedTime time.Time `UpdatedTime,omitempty`
|
||||
}
|
||||
|
||||
// 仅仅是为了返回前台
|
||||
type SubNotebooks []Notebooks
|
||||
type Notebooks struct {
|
||||
Notebook
|
||||
Subs SubNotebooks // 子notebook 在数据库中是没有的
|
||||
}
|
||||
|
||||
// SubNotebook sort
|
||||
func (this SubNotebooks) Len() int {
|
||||
return len(this)
|
||||
}
|
||||
func (this SubNotebooks) Less(i, j int) bool {
|
||||
return this[i].Seq < this[j].Seq
|
||||
}
|
||||
func (this SubNotebooks) Swap(i, j int) {
|
||||
this[i], this[j] = this[j], this[i]
|
||||
}
|
||||
|
||||
/*
|
||||
修改方案, 因为要共享notebook的问题, 所以还是每个notebook一条记录
|
||||
{
|
||||
notebookId,
|
||||
title,
|
||||
seq,
|
||||
parentNoteBookId, // 上级
|
||||
userId
|
||||
}
|
||||
|
||||
得到所有该用户的notebook, 然后组装成tree返回之
|
||||
更新顺序
|
||||
添加notebook
|
||||
更新notebook
|
||||
删除notebook
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
All the mgo model and common struct
|
||||
@@ -0,0 +1,18 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
)
|
||||
|
||||
// controller ajax返回
|
||||
type Re struct {
|
||||
Ok bool
|
||||
Code int
|
||||
Msg string
|
||||
Id string
|
||||
List interface{}
|
||||
Item interface{}
|
||||
}
|
||||
|
||||
func NewRe() Re {
|
||||
return Re{Ok: false}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 共享笔记本
|
||||
/*
|
||||
{
|
||||
userId, 谁的共享笔记本
|
||||
shared: {
|
||||
userId1: { // 哪个用户共享的
|
||||
seq:
|
||||
"defaultNotebook": {noteId:{Seq:33}, noteId2:{}} // 默认笔记本, 里面是全部的笔记
|
||||
"notebookIds":{notebookId:{}, notebookId2:{}}} // 其它笔记本
|
||||
},
|
||||
userId2: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 以后可能含有其它信息
|
||||
type EachSharedNote struct {
|
||||
Seq int
|
||||
}
|
||||
type EachSharedNotebook struct {
|
||||
Seq int
|
||||
}
|
||||
|
||||
// 每一个用户共享给的note, notebook
|
||||
type EachSharedNotebookAndNotes struct {
|
||||
Seq int // 共享给谁的所在序号
|
||||
DefaultNotebook map[string]EachSharedNote // noteId => 共享的note
|
||||
Notebooks map[string]EachSharedNotebook // notebookId => 共享的notebook
|
||||
}
|
||||
|
||||
type SharedNotebookAndNotes struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Shared map[string]EachSharedNotebookAndNotes // userId =>
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
UserId
|
||||
Notes: {noteId => [userId1, userId2], noteId2: []}
|
||||
Notebooks: {notebookId => [], notebookId2 => []}
|
||||
}
|
||||
*/
|
||||
|
||||
// 用户正在共享的notebook, note
|
||||
type SharingNotebookAndNotes struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Notes map[string][]string // noteId => []string{userId1, userId2}
|
||||
Notebooks map[string][]string // notebookId => []string{userId1, userId2}
|
||||
}
|
||||
|
||||
// 以上以后再用, 现不用
|
||||
//----------------------------------------
|
||||
|
||||
/*
|
||||
每一个sharing一条记录, 这样更好操作
|
||||
类似Notebook的
|
||||
{
|
||||
_id
|
||||
userId
|
||||
toUserId
|
||||
noteId
|
||||
notebookId
|
||||
seq
|
||||
}
|
||||
*/
|
||||
|
||||
type ShareNotebook struct {
|
||||
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||
Seq int `bson:"Seq"` // 排序
|
||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||
CreatedTime time.Time `CreatedTime,omitempty`
|
||||
// IsDefault bool `IsDefault` // 是否是默认共享notebook, perm seq=-9999999, NotebookId=null
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
ShareNotebooks,
|
||||
Subs: [ShareNotebooks, ]
|
||||
ShareNotebooks
|
||||
]
|
||||
*/
|
||||
type SubShareNotebooks []ShareNotebooks
|
||||
type ShareNotebooks struct {
|
||||
Notebook
|
||||
ShareNotebook
|
||||
Subs SubShareNotebooks
|
||||
|
||||
// Notebook与ShareNotebook公用的不能生成json
|
||||
Seq int
|
||||
NotebookId bson.ObjectId
|
||||
IsDefault bool // 是否是默认笔记本
|
||||
}
|
||||
|
||||
// SubShareNotebook sort
|
||||
func (this SubShareNotebooks) Len() int {
|
||||
return len(this)
|
||||
}
|
||||
func (this SubShareNotebooks) Less(i, j int) bool {
|
||||
return this[i].ShareNotebook.Seq < this[j].ShareNotebook.Seq
|
||||
}
|
||||
func (this SubShareNotebooks) Swap(i, j int) {
|
||||
this[i], this[j] = this[j], this[i]
|
||||
}
|
||||
|
||||
// 以用户进行分组
|
||||
// type ShareNotebooksByUsers []ShareNotebooksByUser
|
||||
type ShareNotebooksByUser map[string][]ShareNotebooks
|
||||
|
||||
/*
|
||||
type ShareNotebooksByUser struct {
|
||||
// User
|
||||
UserId bson.ObjectId
|
||||
ShareNotebooks []ShareNotebooks // SubShareNotebooks 一样的, 不过用[]更容易理解
|
||||
}
|
||||
*/
|
||||
|
||||
//----------------------------------
|
||||
|
||||
// 唯一: userId-ToUserId-NoteId
|
||||
// use leanote
|
||||
// db.leanote.share_notes.ensureIndex({"UserId":1,"ToUserId":1, "NoteId": 1},{"unique":true})
|
||||
type ShareNote struct {
|
||||
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
}
|
||||
|
||||
// 谁共享给了谁note
|
||||
// 共享了note, notebook都要加!
|
||||
// 唯一: UserId-ToUserId
|
||||
// db.leanote.has_share_notes.ensureIndex({"UserId":1,"ToUserId":1},{"unique":true})
|
||||
type HasShareNote struct {
|
||||
HasShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
Seq int `bson:"Seq"` // 以后还可以用户排序
|
||||
}
|
||||
|
||||
// 将note与权限结合起来
|
||||
type ShareNoteWithPerm struct {
|
||||
Note
|
||||
Perm int
|
||||
}
|
||||
|
||||
// 查看共享状态, 用户的信息
|
||||
type ShareUserInfo struct {
|
||||
ToUserId bson.ObjectId `bson:"UserId"`
|
||||
Email string
|
||||
Perm int // note或其notebook的权限
|
||||
NotebookHasShared bool // 是否其notebook共享了
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// 建议
|
||||
type Suggestion struct {
|
||||
Id bson.ObjectId `bson:"_id"`
|
||||
UserId bson.ObjectId `UserId`
|
||||
Addr string `Addr`
|
||||
Suggestion string `Suggestion`
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
// 这里主要是为了统计每个tag的note数目
|
||||
type TagNote struct {
|
||||
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
Tag string `Title` // 标题
|
||||
NoteNum int `NoteNum` // note数目
|
||||
}
|
||||
|
||||
// 每个用户一条记录, 存储用户的所有tags
|
||||
type Tag struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Tags []string `Tags`
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 随机token
|
||||
// 验证邮箱
|
||||
// 找回密码
|
||||
|
||||
// token type
|
||||
const (
|
||||
TokenPwd = iota
|
||||
TokenActiveEmail
|
||||
TokenUpdateEmail
|
||||
)
|
||||
|
||||
// 过期时间
|
||||
const (
|
||||
PwdOverHours = 2.0
|
||||
ActiveEmailOverHours = 48.0
|
||||
UpdateEmailOverHours = 2.0
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
Email string `Email`
|
||||
Token string `Token`
|
||||
Type int `Type`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 第三方类型
|
||||
const (
|
||||
ThirdGithub = iota
|
||||
ThirdQQ
|
||||
)
|
||||
|
||||
type User struct {
|
||||
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
Email string `Email` // 全是小写
|
||||
Verified bool `Verified` // Email是否已验证过?
|
||||
Username string `Username` // 不区分大小写, 全是小写
|
||||
UsernameRaw string `UsernameRaw` // 可能有大小写
|
||||
Pwd string `bson:"Pwd" json:"-"`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
// 主题
|
||||
Theme string `Theme`
|
||||
|
||||
// 用户配置
|
||||
NotebookWidth int `NotebookWidth` // 笔记本宽度
|
||||
NoteListWidth int `NoteListWidth` // 笔记列表宽度
|
||||
LeftIsMin bool `LeftIsMin` // 左侧是否是隐藏的, 默认是打开的
|
||||
|
||||
// 这里 第三方登录
|
||||
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||
ThirdType int `ThirdType` // 第三方类型
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
)
|
||||
|
||||
|
||||
// 分页数据
|
||||
type Page struct {
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
List interface{}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
_ "github.com/leanote/leanote/app/lea/binder"
|
||||
"reflect"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
// AuthFilter, // Invoke the 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.
|
||||
|
||||
// session.SessionFilter, // leanote memcache session life
|
||||
|
||||
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
|
||||
revel.InterceptorFilter, // Run interceptors around the action.
|
||||
revel.CompressFilter, // Compress the result.
|
||||
revel.ActionInvoker, // Invoke the action.
|
||||
}
|
||||
|
||||
revel.TemplateFuncs["raw"] = func(str string) template.HTML {
|
||||
return template.HTML(str)
|
||||
}
|
||||
revel.TemplateFuncs["add"] = func(i int) template.HTML {
|
||||
i = i + 1;
|
||||
return template.HTML(fmt.Sprintf("%v", i))
|
||||
}
|
||||
revel.TemplateFuncs["concat"] = func(s1, s2 string) template.HTML {
|
||||
return template.HTML(s1 + s2)
|
||||
}
|
||||
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
// interface是否有该字段
|
||||
revel.TemplateFuncs["has"] = func(i interface{}, key string) bool {
|
||||
t := reflect.TypeOf(i)
|
||||
_, ok := t.FieldByName(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
// tags
|
||||
revel.TemplateFuncs["blogTags"] = func(tags []string) template.HTML {
|
||||
if tags == nil || len(tags) == 0 {
|
||||
return ""
|
||||
}
|
||||
tagMap := map[string]string{"red": "红色", "yellow": "黄色", "blue": "蓝色", "green": "绝色"}
|
||||
tagStr := ""
|
||||
lenTags := len(tags)
|
||||
for i, tag := range tags {
|
||||
if text, ok := tagMap[tag]; ok {
|
||||
tagStr += text
|
||||
} else {
|
||||
tagStr += tag
|
||||
}
|
||||
if i != lenTags - 1 {
|
||||
tagStr += ","
|
||||
}
|
||||
}
|
||||
return template.HTML(tagStr)
|
||||
}
|
||||
|
||||
// pagination
|
||||
revel.TemplateFuncs["page"] = func(userId, notebookId string, page, pageSize, count int) template.HTML {
|
||||
if count == 0 {
|
||||
return "";
|
||||
}
|
||||
totalPage := int(math.Ceil(float64(count)/float64(pageSize)))
|
||||
|
||||
preClass := ""
|
||||
prePage := page - 1
|
||||
if prePage == 0 {
|
||||
prePage = 1
|
||||
}
|
||||
nextClass := ""
|
||||
nextPage := page + 1
|
||||
var preUrl, nextUrl string
|
||||
|
||||
urlBase := "/blog/" + userId
|
||||
if notebookId != "" {
|
||||
urlBase += "/" + notebookId
|
||||
}
|
||||
|
||||
preUrl = urlBase + "?page=" + strconv.Itoa(prePage)
|
||||
nextUrl = urlBase + "?page=" + strconv.Itoa(nextPage)
|
||||
|
||||
// 没有上一页了
|
||||
if page == 1 {
|
||||
preClass = "disabled"
|
||||
preUrl = "#"
|
||||
}
|
||||
// 没有下一页了
|
||||
if totalPage <= page {
|
||||
nextClass = "disabled"
|
||||
nextUrl = "#"
|
||||
}
|
||||
return template.HTML("<li class='" + preClass + "'><a href='" + preUrl + "'>Previous</a></li> <li class='" + nextClass + "'><a href='" + nextUrl + "'>Next</a></li>")
|
||||
}
|
||||
|
||||
// init Email
|
||||
revel.OnAppStart(func() {
|
||||
InitEmail()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
func Log(i interface{}) {
|
||||
revel.INFO.Println(i)
|
||||
}
|
||||
|
||||
func LogJ(i interface{}) {
|
||||
b, _ := json.MarshalIndent(i, "", " ")
|
||||
revel.INFO.Println(string(b))
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
// 发送邮件
|
||||
var host = "smtp.ym.163.com"
|
||||
var port = "25"
|
||||
var username = "noreply@leanote.com"
|
||||
var password = "---"
|
||||
|
||||
func InitEmail() {
|
||||
config := revel.Config;
|
||||
host, _ = config.String("email.host")
|
||||
port, _ = config.String("email.port")
|
||||
username, _ = config.String("email.username")
|
||||
password, _ = config.String("email.password")
|
||||
}
|
||||
|
||||
var bodyTpl = `
|
||||
<html>
|
||||
<body>
|
||||
<div style="width: 800px; margin:auto; border-radius:5px; border: 1px solid #ccc; padding: 20px;">
|
||||
<div>
|
||||
<div>
|
||||
<div style="float:left; height: 40px;">
|
||||
<a href="http://leanote.com" style="font-size: 24px">leanote</a>
|
||||
</div>
|
||||
<div style="float:left; height:40px; line-height:16px;">
|
||||
| <span style="font-size:24px">$title</span>
|
||||
</div>
|
||||
<div style="clear:both"></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr style="border:none;border-top: 1px solid #ccc"/>
|
||||
<div style="margin-top: 20px; font-size: 14px;">
|
||||
$body
|
||||
</div>
|
||||
|
||||
<div id="leanoteFooter" style="margin-top: 30px; border-top: 1px solid #ccc">
|
||||
<style>
|
||||
#leanoteFooter {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
#leanoteFooter a {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<a href="http://leanote.com">leanote</a>, your own cloud note
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
func SendEmail(to, subject, title, body string) bool {
|
||||
hp := strings.Split(host, ":")
|
||||
auth := smtp.PlainAuth("", username, password, hp[0])
|
||||
|
||||
var content_type string
|
||||
|
||||
mailtype := "html"
|
||||
if mailtype == "html" {
|
||||
content_type = "Content-Type: text/"+ mailtype + "; charset=UTF-8"
|
||||
} else{
|
||||
content_type = "Content-Type: text/plain" + "; charset=UTF-8"
|
||||
}
|
||||
|
||||
// 登录之
|
||||
body = strings.Replace(bodyTpl, "$body", body, 1)
|
||||
body = strings.Replace(body, "$title", title, 1)
|
||||
|
||||
msg := []byte("To: " + to + "\r\nFrom: " + username + "<"+ username +">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
|
||||
send_to := strings.Split(to, ";")
|
||||
err := smtp.SendMail(host+":"+port, auth, username, send_to, msg)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SendToLeanote(subject, title, body string) {
|
||||
to := "leanote@leanote.com"
|
||||
SendEmail(to, subject, title, body);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 分离文件名与扩展名(包含.)
|
||||
func SplitFilename(filename string) (baseName, ext string) {
|
||||
baseName = filename
|
||||
// 找到最后一个'.'
|
||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||
baseName = strings.TrimRight(filename, ext)
|
||||
ext = strings.ToLower(ext)
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换文件的格式
|
||||
// toExt包含.
|
||||
func TransferExt(path string, toExt string) string {
|
||||
dir := filepath.Dir(path) + "/" // 文件路径
|
||||
name := filepath.Base(path) // 文件名 a.jpg
|
||||
// 获取文件名与路径
|
||||
baseName, _ := SplitFilename(name)
|
||||
return dir + baseName + toExt
|
||||
}
|
||||
|
||||
func GetFilename(path string) string {
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
// 清空dir下所有的文件和文件夹
|
||||
// RemoveAll会清空本文件夹, 所以还要创建之
|
||||
func ClearDir(dir string) bool {
|
||||
err := os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = os.MkdirAll(dir, 0777)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"github.com/Terry-Mao/paint"
|
||||
"github.com/Terry-Mao/paint/wand"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 传源路径, 在该路径下写入另一个gif
|
||||
// maxWidth 最大宽度, == 0表示不改变宽度
|
||||
// 成功后删除
|
||||
func TransToGif(path string, maxWidth uint, afterDelete bool) (ok bool, transPath string) {
|
||||
ok = false
|
||||
transPath = path
|
||||
wand.Genesis()
|
||||
defer wand.Terminus()
|
||||
|
||||
w := wand.NewMagickWand()
|
||||
defer w.Destroy()
|
||||
|
||||
if err := w.ReadImage(path); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
width := w.ImageWidth()
|
||||
height := w.ImageHeight()
|
||||
if maxWidth != 0 {
|
||||
if width > maxWidth {
|
||||
// 等比缩放
|
||||
height = height * maxWidth/width
|
||||
width = maxWidth
|
||||
}
|
||||
}
|
||||
|
||||
w.SetImageFormat("GIF");
|
||||
|
||||
if err := paint.Thumbnail(w, width, height); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否是gif图片, 是就不用转换了
|
||||
baseName, ext := SplitFilename(path)
|
||||
var toPath string
|
||||
if(ext == ".gif") {
|
||||
toPath = baseName + "_2" + ext
|
||||
} else {
|
||||
toPath = TransferExt(path, ".gif");
|
||||
}
|
||||
|
||||
if err := w.WriteImage(toPath); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if afterDelete {
|
||||
os.Remove(path)
|
||||
}
|
||||
|
||||
ok = true
|
||||
transPath = toPath
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 缩小到
|
||||
// 未用
|
||||
func Reset(path string, maxWidth uint) (ok bool, transPath string){
|
||||
wand.Genesis()
|
||||
defer wand.Terminus()
|
||||
|
||||
w := wand.NewMagickWand()
|
||||
defer w.Destroy()
|
||||
|
||||
if err := w.ReadImage(path); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
width := w.ImageWidth()
|
||||
height := w.ImageHeight()
|
||||
if maxWidth != 0 {
|
||||
if width > maxWidth {
|
||||
// 等比缩放
|
||||
height = height * maxWidth/width
|
||||
width = maxWidth
|
||||
}
|
||||
}
|
||||
if err := paint.Thumbnail(w, width, height); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
toPath := TransferExt(path, ".gif");
|
||||
if err := w.WriteImage(toPath); err != nil {
|
||||
fmt.Println(err);
|
||||
return;
|
||||
}
|
||||
|
||||
ok = true
|
||||
transPath = toPath
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
The leanote util package
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
math_rand "math/rand"
|
||||
)
|
||||
|
||||
// 字符串
|
||||
|
||||
// md5
|
||||
func Md5(s string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(s))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Guid
|
||||
func NewGuid() string {
|
||||
b := make([]byte, 48)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return ""
|
||||
}
|
||||
return Md5(base64.URLEncoding.EncodeToString(b))
|
||||
}
|
||||
|
||||
// 后面加个str生成之, 更有保障, 确保唯一
|
||||
func NewGuidWith(str string) string {
|
||||
b := make([]byte, 48)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return ""
|
||||
}
|
||||
return Md5(base64.URLEncoding.EncodeToString([]byte(string(b) + str)))
|
||||
}
|
||||
|
||||
// 以byte来截取
|
||||
func SubstringByte(str string, start int) string {
|
||||
return substr(str, start, len(str)-start, false)
|
||||
}
|
||||
|
||||
func Substring(str string, start int) string {
|
||||
return substr(str, start, len(str)-start, true)
|
||||
}
|
||||
|
||||
func Substr(str string, start, length int) string {
|
||||
return substr(str, start, length, true)
|
||||
}
|
||||
|
||||
func substr(str string, start, length int, isRune bool) string {
|
||||
rs := []rune(str)
|
||||
rs2 := []byte(str)
|
||||
|
||||
rl := len(rs)
|
||||
if !isRune {
|
||||
rl = len(rs2)
|
||||
}
|
||||
end := 0
|
||||
|
||||
if start < 0 {
|
||||
start = rl - 1 + start
|
||||
}
|
||||
end = start + length
|
||||
|
||||
if start > end {
|
||||
start, end = end, start
|
||||
}
|
||||
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
if start > rl {
|
||||
start = rl
|
||||
}
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
if end > rl {
|
||||
end = rl
|
||||
}
|
||||
|
||||
if isRune {
|
||||
return string(rs[start:end])
|
||||
}
|
||||
return string(rs2[start:end])
|
||||
}
|
||||
|
||||
// 截取含html的字符串
|
||||
/*
|
||||
<div>
|
||||
abcdef
|
||||
<p>xxxxxxxxxxx</p>
|
||||
<img src="" />
|
||||
<div>
|
||||
abcdfef
|
||||
<p>aksdfjsld
|
||||
dfsadf
|
||||
--------------- 这里截断
|
||||
</p>
|
||||
<p>xxxxxxxxxxxxxxx</p>
|
||||
abcdef
|
||||
</div>
|
||||
</div>
|
||||
那么只要在最后的html中添加</p></div></div>补全结束即可
|
||||
思路:
|
||||
1. 找到截断的位置
|
||||
2. 去掉成对的标签
|
||||
3. 去掉不要结束的标签
|
||||
4. 补全标签
|
||||
*/
|
||||
func ReplaceAll(oldStr, pattern, newStr string) string {
|
||||
p, _ := regexp.Compile(pattern)
|
||||
s := p.ReplaceAll([]byte(oldStr), []byte(newStr))
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func SubStringHTML(param string, length int, end string) string {
|
||||
// 先取出<pre></pre>占位..
|
||||
|
||||
result := ""
|
||||
|
||||
// 1
|
||||
n := 0
|
||||
var temp rune // 中文问题, 用rune来解决
|
||||
isCode := false //是不是HTML代码
|
||||
isHTML := false //是不是HTML特殊字符,如
|
||||
rStr := []rune(param)
|
||||
for i := 0; i < len(rStr); i++ {
|
||||
temp = rStr[i]
|
||||
if temp == '<' {
|
||||
isCode = true
|
||||
} else if temp == '&' {
|
||||
isHTML = true
|
||||
} else if temp == '>' && isCode {
|
||||
n = n - 1
|
||||
isCode = false
|
||||
} else if temp == ';' && isHTML {
|
||||
isHTML = false
|
||||
}
|
||||
if !isCode && !isHTML {
|
||||
n = n + 1
|
||||
}
|
||||
result += string(temp)
|
||||
if n >= length {
|
||||
break
|
||||
}
|
||||
}
|
||||
result += end
|
||||
|
||||
// 取出所有标签
|
||||
tempResult := ReplaceAll(result, "(>)[^<>]*(<?)", "$1$2") // 把标签中间的所有内容都去掉了
|
||||
|
||||
// 2. 去掉不需要结素标记的HTML标记
|
||||
tempResult = ReplaceAll(tempResult, "</?(embed|AREA|BASE|BASEFONT|BR|COL|COLGROUP|DD|DT|FRAME|HEAD|HR|IMG|INPUT|ISINDEX|LI|LINK|META|OPTION|PARAM|area|wbr|br|col|colgroup|dd|dt|frame|hr|img|input|isindex|link|meta|param)[^<>]*/?>", "")
|
||||
|
||||
// 把<div class=xxx的class=xxx去掉
|
||||
tempResult = ReplaceAll(tempResult, "<(/?[a-zA-Z]+)[^<>]*>", "<$1>")
|
||||
|
||||
// 3 只能用正则,+stack来去有结束的
|
||||
// golang的正则暂不支持back reference, 以后可以用它来去掉重复的标签
|
||||
p, _ := regexp.Compile("<(/?[a-zA-Z]+)[^<>]*>") // 得到所有的<div>, </div>...
|
||||
strs := p.FindAllString(tempResult, -1)
|
||||
|
||||
// fmt.Println(strs)
|
||||
stack := make([]string, len(strs))
|
||||
stackP := -1
|
||||
for _, each := range strs {
|
||||
if stackP >= 0 {
|
||||
// 匹配
|
||||
if stack[stackP][1:] == each[2:] {
|
||||
stackP--
|
||||
continue
|
||||
}
|
||||
}
|
||||
stackP++
|
||||
stack[stackP] = each
|
||||
}
|
||||
// 补全tag
|
||||
if stackP != -1 {
|
||||
fmt.Println(stack[0 : stackP+1])
|
||||
|
||||
for _, each := range stack[0 : stackP+1] {
|
||||
if each[1] != '/' {
|
||||
result += "</" + each[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
// 是否是合格的密码
|
||||
func IsGoodPwd(pwd string) (bool, string) {
|
||||
if pwd == "" {
|
||||
return false, "密码不能为空"
|
||||
}
|
||||
if len(pwd) < 6 {
|
||||
return false, "密码至少6位"
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// 是否是email
|
||||
func IsEmail(email string) bool {
|
||||
if email == "" {
|
||||
return false;
|
||||
}
|
||||
ok, _ := regexp.MatchString(`^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[0-9a-zA-Z]{2,3}$`, email)
|
||||
return ok
|
||||
}
|
||||
|
||||
// 是否只包含数字, 字母 -, _
|
||||
func IsUsername(username string) bool {
|
||||
if username == "" {
|
||||
return false;
|
||||
}
|
||||
ok, _ := regexp.MatchString(`[^0-9a-zA-Z_\-]`, username)
|
||||
return !ok
|
||||
}
|
||||
|
||||
// 是否是ObjectId
|
||||
func IsObjectId(id string) (ok bool) {
|
||||
defer func() { // 必须要先声明defer,否则不能捕获到panic异常
|
||||
// 证明有错误发生
|
||||
if err := recover(); err != nil {
|
||||
ok = false
|
||||
} else {
|
||||
ok = true
|
||||
}
|
||||
}()
|
||||
bson.ObjectIdHex(id)
|
||||
return
|
||||
}
|
||||
|
||||
// 随机密码
|
||||
// num 几位
|
||||
func RandomPwd(num int) string {
|
||||
chars := make([]byte, 62)
|
||||
j := 0
|
||||
for i := 48; i <= 57; i++ {
|
||||
chars[j] = byte(i)
|
||||
j++
|
||||
}
|
||||
for i := 65; i <= 90; i++ {
|
||||
chars[j] = byte(i)
|
||||
j++
|
||||
}
|
||||
for i := 97; i <= 122; i++ {
|
||||
chars[j] = byte(i)
|
||||
j++
|
||||
}
|
||||
j--;
|
||||
|
||||
str := ""
|
||||
math_rand.Seed(time.Now().UnixNano())
|
||||
for i := 0; i < num; i++ {
|
||||
x := math_rand.Intn(j)
|
||||
str += string(chars[x])
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package binder
|
||||
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// leanote binder struct
|
||||
// rewrite revel struct binder
|
||||
// not need the struct name as prefix,
|
||||
// eg:
|
||||
// type Note struct {Name}
|
||||
// func (c Controller) List(note Note) revel.Result {}
|
||||
// in revel you must pass the note.Name as key, now you just pass Name
|
||||
|
||||
// for test
|
||||
// map[string][string]
|
||||
var MSSBinder = revel.Binder{
|
||||
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
||||
var (
|
||||
result = reflect.MakeMap(typ)
|
||||
keyType = typ.Key()
|
||||
valueType = typ.Elem()
|
||||
)
|
||||
for paramName, values := range params.Values {
|
||||
key := paramName // [len(name)+1 : len(paramName)-1]
|
||||
// 每一个值 values[0]
|
||||
result.SetMapIndex(revel.BindValue(key, keyType), revel.BindValue(values[0], valueType))
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
Unbind: func(output map[string]string, name string, val interface{}) {
|
||||
mapValue := reflect.ValueOf(val)
|
||||
for _, key := range mapValue.MapKeys() {
|
||||
revel.Unbind(output, fmt.Sprintf("%v", key.Interface()),
|
||||
mapValue.MapIndex(key).Interface())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// struct需要., a.b = "life"
|
||||
// a: contoller是形参名
|
||||
// 修改, 默认就是a.b, 传b
|
||||
func nextKey(key string) string {
|
||||
fieldLen := strings.IndexAny(key, ".[")
|
||||
if fieldLen == -1 {
|
||||
return key
|
||||
}
|
||||
return key[:fieldLen]
|
||||
}
|
||||
var leanoteStructBinder = revel.Binder{
|
||||
Bind: func(params *revel.Params, name string, typ reflect.Type) reflect.Value {
|
||||
result := reflect.New(typ).Elem()
|
||||
fieldValues := make(map[string]reflect.Value)
|
||||
for key, _ := range params.Values {
|
||||
// 这里, 如果没有点, 默认就是a.
|
||||
// life
|
||||
var suffix string
|
||||
var noPrefix = false
|
||||
if !strings.HasPrefix(key, name + ".") {
|
||||
noPrefix = true
|
||||
suffix = key
|
||||
// continue
|
||||
} else {
|
||||
// Get the name of the struct property.
|
||||
// Strip off the prefix. e.g. foo.bar.baz => bar.baz
|
||||
suffix = key[len(name)+1:]
|
||||
}
|
||||
|
||||
fieldName := nextKey(suffix) // e.g. bar => "bar", bar.baz => "bar", bar[0] => "bar"
|
||||
fieldLen := len(fieldName)
|
||||
|
||||
if _, ok := fieldValues[fieldName]; !ok {
|
||||
// Time to bind this field. Get it and make sure we can set it.
|
||||
fieldValue := result.FieldByName(fieldName)
|
||||
if !fieldValue.IsValid() {
|
||||
continue
|
||||
}
|
||||
if !fieldValue.CanSet() {
|
||||
continue
|
||||
}
|
||||
var boundVal reflect.Value
|
||||
// 没有name前缀
|
||||
if(noPrefix) {
|
||||
boundVal = revel.Bind(params, key[:fieldLen], fieldValue.Type())
|
||||
} else {
|
||||
boundVal = revel.Bind(params, key[:len(name)+1+fieldLen], fieldValue.Type())
|
||||
}
|
||||
fieldValue.Set(boundVal)
|
||||
fieldValues[fieldName] = boundVal
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
Unbind: func(output map[string]string, name string, iface interface{}) {
|
||||
val := reflect.ValueOf(iface)
|
||||
typ := val.Type()
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
structField := typ.Field(i)
|
||||
fieldValue := val.Field(i)
|
||||
// PkgPath is specified to be empty exactly for exported fields.
|
||||
if structField.PkgPath == "" {
|
||||
revel.Unbind(output, fmt.Sprintf("%s.%s", name, structField.Name), fieldValue.Interface())
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogBase{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogComment{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(info.UserBlogStyle{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(info.Notebook{})] = leanoteStructBinder
|
||||
revel.TypeBinders[reflect.TypeOf(controllers.NoteOrContent{})] = leanoteStructBinder
|
||||
}
|
||||
@@ -0,0 +1,762 @@
|
||||
package html2image
|
||||
|
||||
import (
|
||||
"leanote/app/lea"
|
||||
"leanote/app/lea/netutil"
|
||||
"bufio"
|
||||
"code.google.com/p/draw2d/draw2d"
|
||||
// "fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"os"
|
||||
// "strings"
|
||||
// "time"
|
||||
"github.com/revel/revel"
|
||||
"code.google.com/p/go.net/html"
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Html2Image struct {
|
||||
image *image.RGBA
|
||||
gc *draw2d.ImageGraphicContext
|
||||
|
||||
// 试探
|
||||
gc2 *draw2d.ImageGraphicContext
|
||||
|
||||
width float64 // 图片宽度
|
||||
height float64
|
||||
|
||||
painWidth float64 // 画布宽度
|
||||
|
||||
startX float64
|
||||
x float64
|
||||
y float64
|
||||
|
||||
isFirstP bool // 是否是第一个段落?
|
||||
|
||||
// 换行和段落的高度
|
||||
brY float64
|
||||
pY float64
|
||||
|
||||
// 字体
|
||||
normalFontFamily draw2d.FontData
|
||||
boldFontFamily draw2d.FontData
|
||||
|
||||
// preTag 之前的标签
|
||||
preTag *html.Node
|
||||
}
|
||||
|
||||
func NewHtml2Image() *Html2Image {
|
||||
h := &Html2Image{}
|
||||
h.width = 440
|
||||
h.height = 10000 // 最开始设为很大, 不然加不了图片, 会影响速度
|
||||
i, gc := h.InitGc(h.width, h.height)
|
||||
h.gc = gc;
|
||||
h.image = i
|
||||
|
||||
// 试探
|
||||
_, h.gc2 = h.InitGc(h.width, 100)
|
||||
|
||||
h.startX = 10
|
||||
|
||||
// 最初位置
|
||||
h.x = h.startX
|
||||
h.y = 80
|
||||
|
||||
h.isFirstP = true
|
||||
|
||||
h.normalFontFamily = draw2d.FontData{"xihei", 4, draw2d.FontStyleNormal};
|
||||
h.boldFontFamily = draw2d.FontData{"heiti", 5, draw2d.FontStyleNormal};
|
||||
|
||||
h.SetNormalFont()
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (this *Html2Image) InitGc(w, h float64) (* image.RGBA, *draw2d.ImageGraphicContext) {
|
||||
i := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
|
||||
gc := draw2d.NewGraphicContext(i)
|
||||
|
||||
gc.SetStrokeColor(image.Black)
|
||||
gc.SetFillColor(image.White)
|
||||
// fill the background
|
||||
// gc.Clear()
|
||||
|
||||
draw2d.SetFontFolder(revel.BasePath + "/public/fonts/weibo")
|
||||
draw2d.Rect(gc, 0, 0, w, h) // 设置背景
|
||||
gc.FillStroke()
|
||||
gc.SetFillColor(image.Black)
|
||||
|
||||
// 这个很耗时
|
||||
// gc.Translate(0, 0)
|
||||
return i, gc
|
||||
}
|
||||
|
||||
func (this *Html2Image) SaveToPngFile(filePath string) bool {
|
||||
// m := this.image;
|
||||
m := this.image.SubImage(image.Rect(0, 0, int(this.width), int(this.y + 20)))
|
||||
// 需要截断之
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
b := bufio.NewWriter(f)
|
||||
err = png.Encode(b, m)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 字体大小
|
||||
|
||||
func (this *Html2Image) SetSmallFont() {
|
||||
this.gc.SetFontData(this.normalFontFamily)
|
||||
this.gc2.SetFontData(this.normalFontFamily)
|
||||
|
||||
this.gc.SetFillColor(color.NRGBA{60, 60, 60, 255})
|
||||
this.gc.SetFontSize(12)
|
||||
this.gc2.SetFontSize(12)
|
||||
|
||||
this.brY = 16
|
||||
this.pY = 30
|
||||
|
||||
this.painWidth = this.width - 10
|
||||
}
|
||||
|
||||
func (this *Html2Image) SetNormalFont() {
|
||||
this.gc.SetFillColor(image.Black)
|
||||
this.gc.SetFontData(this.normalFontFamily)
|
||||
this.gc2.SetFontData(this.normalFontFamily)
|
||||
|
||||
this.gc.SetFontSize(14)
|
||||
this.gc2.SetFontSize(14)
|
||||
|
||||
this.brY = 20
|
||||
this.pY = 30
|
||||
|
||||
this.painWidth = this.width - 10
|
||||
}
|
||||
func (this *Html2Image) SetAColor() {
|
||||
this.gc.SetFillColor(color.NRGBA{66, 139, 202, 255})
|
||||
}
|
||||
|
||||
// 标题
|
||||
func (this *Html2Image) SetTitleFont() {
|
||||
this.gc.SetFillColor(image.Black)
|
||||
|
||||
this.gc.SetFontData(this.boldFontFamily)
|
||||
this.gc2.SetFontData(this.boldFontFamily)
|
||||
|
||||
this.gc.SetFontSize(24)
|
||||
this.gc2.SetFontSize(24)
|
||||
|
||||
this.brY = 30
|
||||
this.pY = 60
|
||||
|
||||
this.painWidth = this.width - 100
|
||||
}
|
||||
|
||||
// h1, h2...
|
||||
// h1
|
||||
func (this *Html2Image) SetHeadFont(h string) {
|
||||
this.gc.SetFillColor(image.Black)
|
||||
|
||||
this.gc.SetFontData(this.boldFontFamily)
|
||||
this.gc2.SetFontData(this.boldFontFamily)
|
||||
|
||||
this.painWidth = this.width - 50
|
||||
|
||||
if h == "h1" {
|
||||
this.gc.SetFontSize(20)
|
||||
this.gc2.SetFontSize(20)
|
||||
this.brY = 30
|
||||
this.pY = 60
|
||||
} else if h == "h2" {
|
||||
this.gc.SetFontSize(16)
|
||||
this.gc2.SetFontSize(16)
|
||||
this.brY = 25
|
||||
this.pY = 50
|
||||
} else if h == "h3" || h == "h4" {
|
||||
this.gc.SetFontSize(14)
|
||||
this.gc2.SetFontSize(14)
|
||||
this.brY = 20
|
||||
this.pY = 40
|
||||
}
|
||||
}
|
||||
|
||||
// 新的段落
|
||||
func (this *Html2Image) NewP() {
|
||||
// if !this.isFirstP {
|
||||
this.x = this.startX;
|
||||
this.y += this.pY;
|
||||
// } else {
|
||||
// this.isFirstP = false
|
||||
// }
|
||||
}
|
||||
|
||||
// 新一行
|
||||
func (this *Html2Image) NewBr() {
|
||||
this.x = this.startX;
|
||||
this.y += this.brY;
|
||||
}
|
||||
|
||||
// 是否超出了
|
||||
// 1 个汉字 17.875
|
||||
// 1 个字母最多 17.15625
|
||||
func (this *Html2Image) IsOver(r []rune) bool {
|
||||
// fmt.Println(string(r))
|
||||
// 还有多宽
|
||||
// 就算全拿汉字来说
|
||||
// 这里是优化,速度有提升
|
||||
/*
|
||||
if this.painWidth - this.x > 17.875 * float64(len(r)) {
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
// println(text)
|
||||
width2 := this.gc2.FillStringAt(string(r), 0, 0)
|
||||
// 以下的方法可以极大节约时间
|
||||
// a, b, c, d := this.gc2.GetStringBounds(string(r))
|
||||
// width2 := c - a + 2
|
||||
|
||||
// fmt.Println(width2)
|
||||
// fmt.Println(c - a)
|
||||
|
||||
// 小于, 那么需要->大 到第一个不合适的位置
|
||||
if width2 + this.x <= this.painWidth {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// 是否是字母
|
||||
func (this *Html2Image) isAlpha(word rune) bool {
|
||||
if (word >= 'a' && word <= 'z') || (word >= 'A' && word <= 'Z') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 是否是标点, 是标点就包含进来
|
||||
func (this *Html2Image) includePunctuation(r []rune, end int) int {
|
||||
if len(r) == end {
|
||||
return end
|
||||
}
|
||||
c := r[end]
|
||||
if c == ',' || c == '.' || c == '?' || c == ':' || c == ';' || c == '!' || c == ',' || c == '。' || c == '?' || c == ':' || c == ';' || c == '!' {
|
||||
return end + 1
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
// 插入文本
|
||||
// 要判断是否太长了, 太长了就截断
|
||||
func (this *Html2Image) InsertText(text string, needTest bool, prefix string) {
|
||||
if needTest && this.painWidth - this.x < 2 {
|
||||
// 另起一行
|
||||
this.NewBr()
|
||||
this.InsertText(text, true, prefix)
|
||||
return;
|
||||
}
|
||||
|
||||
r := []rune(text)
|
||||
// 试探吧, 可能需要截取
|
||||
if !needTest || !this.IsOver(r) {
|
||||
// 不用截
|
||||
// 可能有\n
|
||||
width := this.gc.FillStringAt(prefix + text, this.x, this.y)
|
||||
this.x += width + 1
|
||||
} else {
|
||||
// 刚开始加10个字, 之后一个一个来
|
||||
// 一个汉字, 或一个单词加
|
||||
wordStart := false
|
||||
wordStartPos := 0
|
||||
maxRI := len(r) - 1
|
||||
for i, word := range r { // i 是0, 1, 2, 3...
|
||||
// i是byte的位置, 一个汉字占3位
|
||||
// 是字母
|
||||
if this.isAlpha(word) {
|
||||
if !wordStart {
|
||||
wordStart = true
|
||||
wordStartPos = i
|
||||
}
|
||||
} else if(word == '\n' || word == '\r') {
|
||||
// 是否是\n
|
||||
i = this.includePunctuation(r, i)
|
||||
this.InsertText(string(r[0:i]), false, prefix)
|
||||
this.NewBr()
|
||||
// 之后的
|
||||
if maxRI != i {
|
||||
this.InsertText(string(r[i+1:]), true, prefix)
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// 单词没结束不计算
|
||||
wordStart = false
|
||||
if i > 0 {
|
||||
// 这里计算是否超出了, 包含自己在内
|
||||
if this.IsOver(r[0:i+1]) {
|
||||
// 那么...回退前一个
|
||||
end := i
|
||||
// 如果上一个是单词, 那么整个单词都不要, 取单词开头
|
||||
if this.isAlpha(r[i-1]) {
|
||||
end = wordStartPos
|
||||
// 这一行全是这个单词, 不太现实, 但有可能, 只能截断了
|
||||
if end == 0 {
|
||||
end = i
|
||||
}
|
||||
}
|
||||
|
||||
// 这一段写上
|
||||
// println("------>" + string(r[0:end]))
|
||||
|
||||
// 这里, 判断后面一个是否是标点符号
|
||||
end = this.includePunctuation(r, end)
|
||||
this.InsertText(string(r[0:end]), false, prefix)
|
||||
this.NewBr()
|
||||
// 之后的
|
||||
this.InsertText(string(r[end:]), true, prefix)
|
||||
|
||||
return;
|
||||
} else {
|
||||
// 没超出, 不用计算, 但出要看是否是结尾了
|
||||
// 怎么可能会出现这种情况呢?, 第一步就试了
|
||||
/*
|
||||
if i+1 == len(text) {
|
||||
println("不可能")
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for
|
||||
// !!
|
||||
// 如果是 go get code.google.com/p/graphics-go/graphics 最后是字母, 怎么办?
|
||||
if wordStart {
|
||||
// 这里计算是否超出了, 包含自己在内
|
||||
end := maxRI + 1
|
||||
// 如果上一个是单词, 那么整个单词都不要, 取单词开头
|
||||
if this.isAlpha(r[maxRI]) {
|
||||
end = wordStartPos
|
||||
// 这一行全是这个单词, 不太现实, 但有可能, 只能截断了
|
||||
if end == 0 {
|
||||
end = maxRI + 1
|
||||
}
|
||||
}
|
||||
|
||||
// 这一段写上
|
||||
// println("-e----->" + string(r[0:end]))
|
||||
|
||||
// 这里, 判断后面一个是否是标点符号
|
||||
end = this.includePunctuation(r, end)
|
||||
this.InsertText(string(r[0:end]), false, prefix)
|
||||
this.NewBr()
|
||||
// 之后的
|
||||
this.InsertText(string(r[end:]), true, prefix)
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置页脚, url文章链接
|
||||
func (this *Html2Image) SetBottom(username, url string) {
|
||||
// 画一条线
|
||||
this.NewBr()
|
||||
this.gc.MoveTo(this.x, this.y)
|
||||
this.gc.LineTo(this.painWidth, this.y)
|
||||
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
|
||||
this.gc.SetLineWidth(2)
|
||||
this.gc.FillStroke()
|
||||
|
||||
this.SetSmallFont()
|
||||
|
||||
// 左侧写字
|
||||
this.NewP()
|
||||
this.InsertText("本文来自 " + username + " 的leanote笔记", true, " ")
|
||||
this.NewBr()
|
||||
this.InsertText("个人博客: ", false, " ")
|
||||
siteUrl, _ := revel.Config.String("site.url")
|
||||
if siteUrl == "" {
|
||||
siteUrl = "http://leanote.com"
|
||||
}
|
||||
this.InsertA(siteUrl + "/blog/" + username, false)
|
||||
|
||||
this.setLogo()
|
||||
/*
|
||||
this.painWidth = this.width - 100
|
||||
this.NewP()
|
||||
this.InsertText("leanote, 不一样的笔记.", false, " ")
|
||||
this.NewBr()
|
||||
this.InsertText("在这里你可以管理自己的知识", false, " ")
|
||||
this.NewBr()
|
||||
this.InsertText("将知识分享给好友, 与好友一起协作知识", false, " ")
|
||||
this.NewBr()
|
||||
this.InsertText("并且还可以将笔记设为博客公开", false, " ")
|
||||
this.InsertText(". 赶紧加入吧! leanote.com", false, "")
|
||||
|
||||
// Logo
|
||||
*/
|
||||
}
|
||||
|
||||
func (this *Html2Image) setImage(path string, x, y float64) {
|
||||
f1, err := os.Open(path)
|
||||
if err != nil {
|
||||
return;
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var m1 image.Image
|
||||
_, ext := lea.SplitFilename(path)
|
||||
if ext == ".png" {
|
||||
m1, err = png.Decode(f1)
|
||||
} else if ext == ".gif" {
|
||||
m1, err = gif.Decode(f1)
|
||||
} else if ext == ".jpg" {
|
||||
m1, err = jpeg.Decode(f1)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
panic(err)
|
||||
}
|
||||
|
||||
this.gc.Translate(x, y)
|
||||
this.gc.DrawImage(m1)
|
||||
this.gc.Translate(-x, -y)
|
||||
}
|
||||
|
||||
// 画leanote logo
|
||||
func (this *Html2Image) setLogo() {
|
||||
// 右上角的logo
|
||||
path := revel.BasePath + "/public/images/leanote/logo-20-a-6.png"
|
||||
println(path)
|
||||
this.setImage(path, 320, 10)
|
||||
|
||||
/*
|
||||
// 右下角设置Logo
|
||||
path = revel.BasePath + "/public/images/leanote/logo-60-a-6.png"
|
||||
this.setImage(path, 320, this.y - 75)
|
||||
*/
|
||||
}
|
||||
|
||||
// 插入链接
|
||||
func (this *Html2Image) InsertA(text string, isNormal bool) {
|
||||
if text == "" {
|
||||
return
|
||||
}
|
||||
|
||||
this.SetAColor()
|
||||
this.InsertText(text, true, "")
|
||||
|
||||
// 还原
|
||||
if isNormal {
|
||||
this.SetNormalFont()
|
||||
} else {
|
||||
this.SetSmallFont()
|
||||
}
|
||||
}
|
||||
|
||||
// 文章标题
|
||||
func (this *Html2Image) InsertTitle(title string) {
|
||||
oldX := this.x
|
||||
oldY := this.y - 35
|
||||
|
||||
// 插入之
|
||||
this.SetTitleFont()
|
||||
|
||||
this.InsertText(title, true, " ")
|
||||
|
||||
// 还原字体大小
|
||||
this.SetNormalFont()
|
||||
|
||||
this.NewBr()
|
||||
|
||||
this.gc.MoveTo(oldX, oldY)
|
||||
this.gc.LineTo(this.x, this.y - 10)
|
||||
this.gc.SetStrokeColor(color.NRGBA{200, 0, 0, 255})
|
||||
this.gc.SetLineWidth(5)
|
||||
this.gc.FillStroke()
|
||||
}
|
||||
|
||||
// 插入h1, h2, ... h4
|
||||
func (this *Html2Image) InsertHead(n *html.Node) {
|
||||
this.SetHeadFont(n.Data); // h1, h2...
|
||||
this.NewP()
|
||||
// 把标题内容全都拿出
|
||||
var text = ""
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if c.Type == html.ElementNode && (c.Data == "p" || c.Data == "br"){
|
||||
text += " "
|
||||
} else {
|
||||
text += strings.TrimRight(c.Data, "\n")
|
||||
}
|
||||
}
|
||||
this.InsertText(text, true, "")
|
||||
this.SetNormalFont()
|
||||
}
|
||||
|
||||
// 插入代码
|
||||
func (this *Html2Image) InsertCode(n *html.Node) {
|
||||
this.NewP()
|
||||
oldX := this.x
|
||||
oldY := this.y - 20
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if c.Type == html.ElementNode && (c.Data == "p" || c.Data == "br"){
|
||||
this.NewBr()
|
||||
} else {
|
||||
this.InsertText(strings.TrimRight(c.Data, "\n"), true, " ")
|
||||
}
|
||||
}
|
||||
this.NewBr()
|
||||
|
||||
this.gc.MoveTo(oldX, oldY)
|
||||
this.gc.LineTo(this.x, this.y - 20)
|
||||
this.gc.SetStrokeColor(color.NRGBA{0, 200, 0, 255})
|
||||
this.gc.SetLineWidth(2)
|
||||
this.gc.FillStroke()
|
||||
}
|
||||
|
||||
// 插入图片
|
||||
// 这个path应该是url,
|
||||
// http://abc.com/a.gif 需要先下载
|
||||
// 或 /upload/a.gif
|
||||
func (this *Html2Image) InsertImage(path string, needTrans bool, width uint) {
|
||||
if path == "" {
|
||||
return;
|
||||
}
|
||||
|
||||
// 是url, 那么取网络图片之
|
||||
var ok bool
|
||||
if strings.HasPrefix(path, "http") || strings.HasPrefix(path, "//") {
|
||||
path, ok = netutil.WriteUrl(path, "/tmp")
|
||||
if !ok || path == ""{
|
||||
return
|
||||
}
|
||||
} else {
|
||||
path = revel.BasePath + "/public/" + path
|
||||
}
|
||||
|
||||
// 需要转换, logo不需要转换
|
||||
if(needTrans) {
|
||||
painWidth := uint(this.painWidth - 10)
|
||||
if width > 0 && painWidth > width {
|
||||
painWidth = width
|
||||
}
|
||||
ok, path = lea.TransToGif(path, painWidth, false)
|
||||
if !ok || path == "" {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
f1, err := os.Open(path)
|
||||
if err != nil {
|
||||
return;
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var m1 image.Image
|
||||
_, ext := lea.SplitFilename(path)
|
||||
if ext == ".png" {
|
||||
m1, err = png.Decode(f1)
|
||||
} else {
|
||||
m1, err = gif.Decode(f1)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 如果之前是p, 那么不要有<br>
|
||||
if this.preTag.Data != "p" {
|
||||
this.NewBr()
|
||||
}
|
||||
this.gc.Translate(this.x, this.y)
|
||||
this.gc.DrawImage(m1)
|
||||
// 还原
|
||||
this.gc.Translate(-this.x, -this.y) // 这个有用些
|
||||
this.y += float64(m1.Bounds().Dy()) - 20
|
||||
this.NewP()
|
||||
|
||||
os.Remove(path)
|
||||
|
||||
// 如果图片是文章第一个的话, 之后的需要p
|
||||
this.isFirstP = false
|
||||
}
|
||||
|
||||
// 内容主体
|
||||
func (this *Html2Image) InsertBody(htmlStr string) (ok bool) {
|
||||
reader := bufio.NewReader(strings.NewReader(htmlStr))
|
||||
doc, err := html.Parse(reader)
|
||||
if err != nil {
|
||||
return;
|
||||
}
|
||||
var f func(*html.Node, *html.Node, string)
|
||||
f = func(n *html.Node, p *html.Node, prefix string) {
|
||||
// if p != nil {
|
||||
// fmt.Println("Parent Data: " + p.Data)
|
||||
// }
|
||||
|
||||
defer func() {
|
||||
if n.Type == html.ElementNode {
|
||||
this.preTag = n
|
||||
}
|
||||
}()
|
||||
|
||||
// 标签
|
||||
if n.Type == html.ElementNode {
|
||||
if n.Data == "p" {
|
||||
this.NewP()
|
||||
// 遍历之后的
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c, n, prefix)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 也是一个段落, 只是要缩进
|
||||
if n.Data == "ul" || n.Data == "ol" {
|
||||
this.NewP()
|
||||
// 遍历之后的
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c, n, "")
|
||||
}
|
||||
return;
|
||||
}
|
||||
if n.Data == "li" {
|
||||
// 遍历之后的
|
||||
// 是否需要前缀
|
||||
needPrefix := true // 第一个肯定要
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if needPrefix {
|
||||
f(c, n, " ")
|
||||
needPrefix = false
|
||||
} else {
|
||||
f(c, n, "")
|
||||
}
|
||||
|
||||
if c.Type == html.ElementNode {
|
||||
if c.Data == "br" || c.Data == "p" {
|
||||
needPrefix = true
|
||||
} else {
|
||||
needPrefix = false
|
||||
}
|
||||
}
|
||||
}
|
||||
// 输完一行后再换行
|
||||
this.NewBr()
|
||||
return;
|
||||
}
|
||||
|
||||
// 标题
|
||||
if n.Data == "h1" || n.Data == "h2" || n.Data == "h3" || n.Data == "h4" {
|
||||
this.InsertHead(n)
|
||||
return;
|
||||
}
|
||||
|
||||
if n.Data == "pre" {
|
||||
// 把之后的全拿过来
|
||||
this.InsertCode(n)
|
||||
return;
|
||||
}
|
||||
|
||||
// 图片
|
||||
// 得到src
|
||||
if n.Data == "img" {
|
||||
src := ""
|
||||
width := 0
|
||||
for _, attr := range n.Attr {
|
||||
if attr.Key == "src" {
|
||||
src = attr.Val
|
||||
} else if attr.Key == "width" {
|
||||
width, _ = strconv.Atoi(attr.Val)
|
||||
}
|
||||
}
|
||||
if src != "" {
|
||||
this.InsertImage(src, true, uint(width))
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 链接
|
||||
// 如果链接里只有文本, 那么单独处理, 如果还有其它的, 不作链接处理
|
||||
if n.Data == "a" {
|
||||
if n.FirstChild == n.LastChild {
|
||||
this.InsertA(n.FirstChild.Data, true)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 空行
|
||||
if n.Data == "br"/* || n.Data == "div"*/ {
|
||||
this.NewBr()
|
||||
}
|
||||
}
|
||||
|
||||
// 是文本, 输出之
|
||||
if n.Type == html.TextNode {
|
||||
data := strings.TrimSpace(n.Data);
|
||||
// <p>xx<br/>xxx</p> 这些空白也是TextNode <p>
|
||||
if data != "" {
|
||||
this.InsertText(prefix + data, true, "")
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 其余的
|
||||
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c, n, prefix)
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
f(doc, nil, "")
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 主函数
|
||||
func ToImage(uid, username, noteId, title, htmlStr, toPath string) (ok bool) {
|
||||
h := NewHtml2Image()
|
||||
|
||||
// 标题
|
||||
h.InsertTitle(title)
|
||||
|
||||
// 主体
|
||||
ok = h.InsertBody(htmlStr)
|
||||
if(!ok) {
|
||||
return
|
||||
}
|
||||
|
||||
// 页眉与页脚
|
||||
h.SetBottom(username, "")
|
||||
|
||||
// 保存成png图片
|
||||
ok = h.SaveToPngFile(toPath)
|
||||
return
|
||||
}
|
||||
|
||||
func TestFillString() {
|
||||
h := NewHtml2Image()
|
||||
str := `一个合格的 Techspace 需要有足够专业的器材、场地和资源,你可以和你的团队在里面进行激光切割、快速贴片甚至加工木材等操作,在相对独立的空间内又能同周围的同道友人互相激发切磋。国内现有的 Techspace 没几家,不久前我去深圳特地拜访了当地的 Techspace,很喜欢那里的氛围,希望国内其他地方也能有更多这类空间供创客发挥。
|
||||
假如你有一个比较成型的想法,想在硬件领域做点事情,核心团队也基本组好,硬件软件交互基本都有专人了`
|
||||
// h.IsOver("W")
|
||||
h.InsertText("go get code.google.com/p/graphics\n-go/graphics", true, "")
|
||||
// h.InsertText("usr/bin/install: 无法创建一般文件'/usr/local/jpeg6/include/jconfig.", true)
|
||||
// h.InsertImage("/Users/life/Desktop/share.png")
|
||||
// h.NewP()
|
||||
h.InsertText(str, true, "")
|
||||
// h.InsertImage("/Users/life/Desktop/share.png")
|
||||
h.SaveToPngFile("/Users/life/Desktop/TestPath3.png")
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"github.com/robfig/gomemcache/memcache"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func Set(key string, value map[string]string, expiration int32) {
|
||||
// 把value转成byte
|
||||
bytes, _ := json.Marshal(value)
|
||||
if expiration == -1 {
|
||||
expiration = 30 * 24 * 60 * 60 // 30天
|
||||
}
|
||||
client.Set(&memcache.Item{Key: key, Value: bytes, Expiration: expiration})
|
||||
}
|
||||
|
||||
func Get(key string) map[string]string {
|
||||
item, err := client.Get(key)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := map[string]string{}
|
||||
json.Unmarshal(item.Value, &m)
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"github.com/robfig/gomemcache/memcache"
|
||||
)
|
||||
|
||||
var client *memcache.Client
|
||||
|
||||
func init() {
|
||||
// client = memcache.New("localhost:11211")
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package netutil
|
||||
import (
|
||||
"strings"
|
||||
"os"
|
||||
// "path/filepath"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
. "leanote/app/lea"
|
||||
)
|
||||
|
||||
// net的util
|
||||
|
||||
// toPath 文件保存的目录
|
||||
// 默认是/tmp
|
||||
// 返回文件的完整目录
|
||||
func WriteUrl(url string, toPath string) (path string, ok bool) {
|
||||
if url == "" {
|
||||
return;
|
||||
}
|
||||
content, err := GetContent(url)
|
||||
if err != nil {
|
||||
return;
|
||||
}
|
||||
|
||||
// a.html?a=a11&xxx
|
||||
url = trimQueryParams(url)
|
||||
_, ext := SplitFilename(url)
|
||||
if toPath == "" {
|
||||
toPath = "/tmp"
|
||||
}
|
||||
// dir := filepath.Dir(toPath)
|
||||
newFilename := NewGuid() + ext
|
||||
fullPath := toPath + "/" + newFilename
|
||||
/*
|
||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
// 写到文件中
|
||||
file, err := os.Create(fullPath)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file.Write(content)
|
||||
|
||||
path = fullPath
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// 得到内容
|
||||
func GetContent(url string) (content []byte, err error) {
|
||||
var resp *http.Response
|
||||
resp, err = http.Get(url)
|
||||
if(resp != nil && resp.Body != nil) {
|
||||
defer resp.Body.Close()
|
||||
} else {
|
||||
}
|
||||
if resp == nil || resp.Body == nil || err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
buf, err = ioutil.ReadAll(resp.Body)
|
||||
if(err != nil) {
|
||||
return
|
||||
}
|
||||
|
||||
content = buf;
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
// 将url ?, #后面的字符串去掉
|
||||
func trimQueryParams(url string) string {
|
||||
pos := strings.Index(url, "?");
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
}
|
||||
|
||||
pos = strings.Index(url, "#");
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
}
|
||||
|
||||
pos = strings.Index(url, "!");
|
||||
if pos != -1 {
|
||||
url = Substr(url, 0, pos);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"github.com/robfig/revel"
|
||||
"leanote/app/lea/memcache"
|
||||
// . "leanote/app/lea"
|
||||
)
|
||||
|
||||
// 使用filter
|
||||
// 很巧妙就使用了memcache来处理session
|
||||
// revel的session(cookie)只存sessionId, 其它信息存在memcache中
|
||||
|
||||
func SessionFilter(c *revel.Controller, fc []revel.Filter) {
|
||||
sessionId := c.Session.Id()
|
||||
|
||||
// 从memcache中得到cache, 赋给session
|
||||
cache := revel.Session(memcache.Get(sessionId))
|
||||
if cache == nil {
|
||||
cache = revel.Session{}
|
||||
cache.Id()
|
||||
}
|
||||
c.Session = cache
|
||||
|
||||
fc[0](c, fc[1:])
|
||||
|
||||
// 再把session保存之
|
||||
memcache.Set(sessionId, c.Session, -1)
|
||||
|
||||
// 只留下sessionId
|
||||
c.Session = revel.Session{revel.SESSION_ID_KEY: sessionId}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Compress and combine js files
|
||||
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
/*
|
||||
用golang exec 总是说找不到uglifyjs命令, 需要全部路径
|
||||
而且node, npm要在/usr/bin下, 已建ln
|
||||
*/
|
||||
|
||||
/*
|
||||
<script src="js/jquery-1.9.0.min.js"></script>
|
||||
|
||||
<!-- 以后将所有的js压缩合并成一个文件 -->
|
||||
<script src="js/jquery-cookie.js"></script>
|
||||
<script src="js/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="tinymce/tinymce.js"></script>
|
||||
<script src="js/common.js"></script>
|
||||
<script src="js/app/note.js"></script>
|
||||
<script src="js/app/tag.js"></script>
|
||||
<script src="js/app/notebook.js"></script>
|
||||
<script src="js/app/share.js"></script>
|
||||
<script src="js/object_id.js"></script>
|
||||
<script type="text/javascript" src="js/ZeroClipboard/ZeroClipboard.js"></script>
|
||||
*/
|
||||
|
||||
//var jss = []string{"js/jquery-cookie", "js/bootstrap"}
|
||||
var jss = []string{"js/jquery-cookie", "js/bootstrap",
|
||||
"js/common", "js/app/note", "js/app/tag", "js/app/notebook", "js/app/share",
|
||||
"js/object_id", "js/ZeroClipboard/ZeroClipboard"}
|
||||
|
||||
var base = "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/public/"
|
||||
var cmdPath = "/usr/local/bin/uglifyjs"
|
||||
|
||||
func cmdError(err error) {
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "The command failed to perform: %s (Command: %s, Arguments: %s)", err, "", "")
|
||||
} else {
|
||||
fmt.Println("OK")
|
||||
}
|
||||
}
|
||||
|
||||
// filename没有扩展名
|
||||
func compressJs(filename string) {
|
||||
source := base + filename + ".js"
|
||||
to := base + filename + "-min.js"
|
||||
cmd := exec.Command(cmdPath, source, "-o", to)
|
||||
_, err := cmd.CombinedOutput()
|
||||
|
||||
cmdError(err)
|
||||
}
|
||||
|
||||
func combineJs() {
|
||||
// 生成一个总文件
|
||||
cmd := exec.Command("rm", base + "js/all.js")
|
||||
_, err := cmd.CombinedOutput()
|
||||
cmdError(err)
|
||||
|
||||
for _, js := range jss {
|
||||
to := base + js + "-min.js"
|
||||
compressJs(js)
|
||||
|
||||
// 每个压缩后的文件放入之
|
||||
cmd2 := exec.Command("/bin/sh", "-c", "cat " + to + " >> " + base + "js/all.js")
|
||||
_, err := cmd2.CombinedOutput()
|
||||
cmdError(err)
|
||||
cmd2 = exec.Command("/bin/sh", "-c", "cat \n >> " + base + "js/all.js")
|
||||
_, err = cmd2.CombinedOutput()
|
||||
cmdError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 改note-dev->note
|
||||
func dev() {
|
||||
// 即替换note.js->note-min.js
|
||||
m := map[string]string{"note.js": "note-min.js",
|
||||
"app.js": "app-min.js",
|
||||
"page.js": "page-min.js",
|
||||
"common.js": "common-min.js",
|
||||
"notebook.js": "notebook-min.js",
|
||||
"share.js": "share-min.js",
|
||||
"tag.js": "tag-min.js",
|
||||
"jquery.contextmenu.js": "jquery.contextmenu-min.js",
|
||||
"editor/editor.js": "editor/editor-min.js",
|
||||
"/public/mdeditor/editor/scrollLink.js": "/public/mdeditor/editor/scrollLink-min.js",
|
||||
"console.log(o);": "",
|
||||
}
|
||||
path := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note-dev.html"
|
||||
target := "/Users/life/Documents/Go/package/src/github.com/leanote/leanote/src/views/note/note.html"
|
||||
|
||||
bs, _ := ioutil.ReadFile(path)
|
||||
content := string(bs)
|
||||
print(content)
|
||||
for key, value := range m {
|
||||
content = strings.Replace(content, key, value, -1)
|
||||
}
|
||||
ioutil.WriteFile(target, []byte(content), os.ModeAppend)
|
||||
}
|
||||
|
||||
// 压缩js成一块
|
||||
func tinymce() {
|
||||
// cmdStr := "node_modules/jake/bin/cli.js minify bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]"
|
||||
// cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify", "bundle[themes:modern,plugins:table,paste,advlist,autolink,link,image,lists,charmap,hr,searchreplace,visualblocks,visualchars,code,nav,tabfocus,contextmenu,directionality,codemirror,codesyntax,textcolor,fullpage]")
|
||||
cmd := exec.Command("/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master/node_modules/jake/bin/cli.js", "minify")
|
||||
cmd.Dir = "/Users/life/Documents/eclipse-workspace/go/leanote_release/tinymce-master"
|
||||
_, err := cmd.CombinedOutput()
|
||||
cmdError(err)
|
||||
}
|
||||
|
||||
func main() {
|
||||
dev();
|
||||
|
||||
// 其它零散的需要压缩的js
|
||||
otherJss := []string{"tinymce/tinymce", "js/app/page", "js/contextmenu/jquery.contextmenu",
|
||||
"mdeditor/editor/scrollLink",
|
||||
"mdeditor/editor/editor",
|
||||
"mdeditor/editor/jquery.waitforimages",
|
||||
"mdeditor/editor/pagedown/local/Markdown.local.zh",
|
||||
"mdeditor/editor/pagedown/Markdown.Editor",
|
||||
"mdeditor/editor/pagedown/Markdown.Sanitizer",
|
||||
"mdeditor/editor/pagedown/Markdown.Converter",
|
||||
"mdeditor/editor/Markdown.Extra",
|
||||
"mdeditor/editor/underscore",
|
||||
"mdeditor/editor/mathJax",
|
||||
"js/jQuery-slimScroll-1.3.0/jquery.slimscroll",
|
||||
}
|
||||
|
||||
for _, js := range otherJss {
|
||||
compressJs(js)
|
||||
}
|
||||
|
||||
// 先压缩后合并
|
||||
combineJs()
|
||||
|
||||
// 压缩tinymce
|
||||
tinymce()
|
||||
}
|
||||
@@ -0,0 +1,812 @@
|
||||
// GENERATED CODE - DO NOT EDIT
|
||||
package routes
|
||||
|
||||
import "github.com/revel/revel"
|
||||
|
||||
|
||||
type tBaseController struct {}
|
||||
var BaseController tBaseController
|
||||
|
||||
|
||||
func (_ tBaseController) E404(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("BaseController.E404", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tTestRunner struct {}
|
||||
var TestRunner tTestRunner
|
||||
|
||||
|
||||
func (_ tTestRunner) Index(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("TestRunner.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tTestRunner) Run(
|
||||
suite string,
|
||||
test string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "suite", suite)
|
||||
revel.Unbind(args, "test", test)
|
||||
return revel.MainRouter.Reverse("TestRunner.Run", args).Url
|
||||
}
|
||||
|
||||
func (_ tTestRunner) List(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("TestRunner.List", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tStatic struct {}
|
||||
var Static tStatic
|
||||
|
||||
|
||||
func (_ tStatic) Serve(
|
||||
prefix string,
|
||||
filepath string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "prefix", prefix)
|
||||
revel.Unbind(args, "filepath", filepath)
|
||||
return revel.MainRouter.Reverse("Static.Serve", args).Url
|
||||
}
|
||||
|
||||
func (_ tStatic) ServeModule(
|
||||
moduleName string,
|
||||
prefix string,
|
||||
filepath string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "moduleName", moduleName)
|
||||
revel.Unbind(args, "prefix", prefix)
|
||||
revel.Unbind(args, "filepath", filepath)
|
||||
return revel.MainRouter.Reverse("Static.ServeModule", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tFile struct {}
|
||||
var File tFile
|
||||
|
||||
|
||||
func (_ tFile) UploadImage(
|
||||
renderHtml string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "renderHtml", renderHtml)
|
||||
return revel.MainRouter.Reverse("File.UploadImage", args).Url
|
||||
}
|
||||
|
||||
func (_ tFile) UploadBlogLogo(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("File.UploadBlogLogo", args).Url
|
||||
}
|
||||
|
||||
func (_ tFile) UploadImageJson(
|
||||
renderHtml string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "renderHtml", renderHtml)
|
||||
return revel.MainRouter.Reverse("File.UploadImageJson", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tNotebook struct {}
|
||||
var Notebook tNotebook
|
||||
|
||||
|
||||
func (_ tNotebook) Index(
|
||||
notebook interface{},
|
||||
i int,
|
||||
name string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebook", notebook)
|
||||
revel.Unbind(args, "i", i)
|
||||
revel.Unbind(args, "name", name)
|
||||
return revel.MainRouter.Reverse("Notebook.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tNotebook) DeleteNotebook(
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Notebook.DeleteNotebook", args).Url
|
||||
}
|
||||
|
||||
func (_ tNotebook) AddNotebook(
|
||||
notebookId string,
|
||||
title string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "title", title)
|
||||
return revel.MainRouter.Reverse("Notebook.AddNotebook", args).Url
|
||||
}
|
||||
|
||||
func (_ tNotebook) UpdateNotebookTitle(
|
||||
notebookId string,
|
||||
title string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "title", title)
|
||||
return revel.MainRouter.Reverse("Notebook.UpdateNotebookTitle", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tNoteContentHistory struct {}
|
||||
var NoteContentHistory tNoteContentHistory
|
||||
|
||||
|
||||
func (_ tNoteContentHistory) ListHistories(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("NoteContentHistory.ListHistories", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tNote struct {}
|
||||
var Note tNote
|
||||
|
||||
|
||||
func (_ tNote) Index(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Note.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) ListNotes(
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Note.ListNotes", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) ListTrashNotes(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Note.ListTrashNotes", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) GetNoteContent(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("Note.GetNoteContent", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) UpdateNoteOrContent(
|
||||
noteOrContent controllers.NoteOrContent,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteOrContent", noteOrContent)
|
||||
return revel.MainRouter.Reverse("Note.UpdateNoteOrContent", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) DeleteNote(
|
||||
noteId string,
|
||||
userId string,
|
||||
isShared bool,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "userId", userId)
|
||||
revel.Unbind(args, "isShared", isShared)
|
||||
return revel.MainRouter.Reverse("Note.DeleteNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) DeleteTrash(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("Note.DeleteTrash", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) MoveNote(
|
||||
noteId string,
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Note.MoveNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) CopyNote(
|
||||
noteId string,
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Note.CopyNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) CopySharedNote(
|
||||
noteId string,
|
||||
notebookId string,
|
||||
fromUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "fromUserId", fromUserId)
|
||||
return revel.MainRouter.Reverse("Note.CopySharedNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) SearchNote(
|
||||
key string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "key", key)
|
||||
return revel.MainRouter.Reverse("Note.SearchNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) SearchNoteByTags(
|
||||
tags []string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "tags", tags)
|
||||
return revel.MainRouter.Reverse("Note.SearchNoteByTags", args).Url
|
||||
}
|
||||
|
||||
func (_ tNote) Html2Image(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("Note.Html2Image", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tShare struct {}
|
||||
var Share tShare
|
||||
|
||||
|
||||
func (_ tShare) AddShareNote(
|
||||
noteId string,
|
||||
emails []string,
|
||||
perm int,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "emails", emails)
|
||||
revel.Unbind(args, "perm", perm)
|
||||
return revel.MainRouter.Reverse("Share.AddShareNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) AddShareNotebook(
|
||||
notebookId string,
|
||||
emails []string,
|
||||
perm int,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "emails", emails)
|
||||
revel.Unbind(args, "perm", perm)
|
||||
return revel.MainRouter.Reverse("Share.AddShareNotebook", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) ListShareNotes(
|
||||
notebookId string,
|
||||
userId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "userId", userId)
|
||||
return revel.MainRouter.Reverse("Share.ListShareNotes", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) GetShareNoteContent(
|
||||
noteId string,
|
||||
sharedUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "sharedUserId", sharedUserId)
|
||||
return revel.MainRouter.Reverse("Share.GetShareNoteContent", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) ListNoteShareUserInfo(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("Share.ListNoteShareUserInfo", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) ListNotebookShareUserInfo(
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Share.ListNotebookShareUserInfo", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) UpdateShareNotePerm(
|
||||
noteId string,
|
||||
perm int,
|
||||
toUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "perm", perm)
|
||||
revel.Unbind(args, "toUserId", toUserId)
|
||||
return revel.MainRouter.Reverse("Share.UpdateShareNotePerm", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) UpdateShareNotebookPerm(
|
||||
notebookId string,
|
||||
perm int,
|
||||
toUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "perm", perm)
|
||||
revel.Unbind(args, "toUserId", toUserId)
|
||||
return revel.MainRouter.Reverse("Share.UpdateShareNotebookPerm", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) DeleteShareNote(
|
||||
noteId string,
|
||||
toUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "toUserId", toUserId)
|
||||
return revel.MainRouter.Reverse("Share.DeleteShareNote", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) DeleteShareNotebook(
|
||||
notebookId string,
|
||||
toUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "toUserId", toUserId)
|
||||
return revel.MainRouter.Reverse("Share.DeleteShareNotebook", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) DeleteShareNoteBySharedUser(
|
||||
noteId string,
|
||||
fromUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "fromUserId", fromUserId)
|
||||
return revel.MainRouter.Reverse("Share.DeleteShareNoteBySharedUser", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) DeleteShareNotebookBySharedUser(
|
||||
notebookId string,
|
||||
fromUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "fromUserId", fromUserId)
|
||||
return revel.MainRouter.Reverse("Share.DeleteShareNotebookBySharedUser", args).Url
|
||||
}
|
||||
|
||||
func (_ tShare) DeleteUserShareNoteAndNotebook(
|
||||
fromUserId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "fromUserId", fromUserId)
|
||||
return revel.MainRouter.Reverse("Share.DeleteUserShareNoteAndNotebook", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tUser struct {}
|
||||
var User tUser
|
||||
|
||||
|
||||
func (_ tUser) UpdateUsername(
|
||||
username string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "username", username)
|
||||
return revel.MainRouter.Reverse("User.UpdateUsername", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdatePwd(
|
||||
oldPwd string,
|
||||
pwd string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "oldPwd", oldPwd)
|
||||
revel.Unbind(args, "pwd", pwd)
|
||||
return revel.MainRouter.Reverse("User.UpdatePwd", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdateTheme(
|
||||
theme string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "theme", theme)
|
||||
return revel.MainRouter.Reverse("User.UpdateTheme", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) SendRegisterEmail(
|
||||
content string,
|
||||
toEmail string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "content", content)
|
||||
revel.Unbind(args, "toEmail", toEmail)
|
||||
return revel.MainRouter.Reverse("User.SendRegisterEmail", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) ReSendActiveEmail(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("User.ReSendActiveEmail", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdateEmailSendActiveEmail(
|
||||
email string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
return revel.MainRouter.Reverse("User.UpdateEmailSendActiveEmail", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdateEmail(
|
||||
token string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "token", token)
|
||||
return revel.MainRouter.Reverse("User.UpdateEmail", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) ActiveEmail(
|
||||
token string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "token", token)
|
||||
return revel.MainRouter.Reverse("User.ActiveEmail", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) AddAccount(
|
||||
email string,
|
||||
pwd string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
revel.Unbind(args, "pwd", pwd)
|
||||
return revel.MainRouter.Reverse("User.AddAccount", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdateColumnWidth(
|
||||
notebookWidth int,
|
||||
noteListWidth int,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookWidth", notebookWidth)
|
||||
revel.Unbind(args, "noteListWidth", noteListWidth)
|
||||
return revel.MainRouter.Reverse("User.UpdateColumnWidth", args).Url
|
||||
}
|
||||
|
||||
func (_ tUser) UpdateLeftIsMin(
|
||||
leftIsMin bool,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "leftIsMin", leftIsMin)
|
||||
return revel.MainRouter.Reverse("User.UpdateLeftIsMin", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tAuth struct {}
|
||||
var Auth tAuth
|
||||
|
||||
|
||||
func (_ tAuth) Login(
|
||||
email string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
return revel.MainRouter.Reverse("Auth.Login", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) DoLogin(
|
||||
email string,
|
||||
pwd string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
revel.Unbind(args, "pwd", pwd)
|
||||
return revel.MainRouter.Reverse("Auth.DoLogin", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) Logout(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Auth.Logout", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) Demo(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Auth.Demo", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) Register(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Auth.Register", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) DoRegister(
|
||||
email string,
|
||||
pwd string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
revel.Unbind(args, "pwd", pwd)
|
||||
return revel.MainRouter.Reverse("Auth.DoRegister", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) FindPassword(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Auth.FindPassword", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) DoFindPassword(
|
||||
email string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "email", email)
|
||||
return revel.MainRouter.Reverse("Auth.DoFindPassword", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) FindPassword2(
|
||||
token string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "token", token)
|
||||
return revel.MainRouter.Reverse("Auth.FindPassword2", args).Url
|
||||
}
|
||||
|
||||
func (_ tAuth) FindPasswordUpdate(
|
||||
token string,
|
||||
pwd string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "token", token)
|
||||
revel.Unbind(args, "pwd", pwd)
|
||||
return revel.MainRouter.Reverse("Auth.FindPasswordUpdate", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tBlog struct {}
|
||||
var Blog tBlog
|
||||
|
||||
|
||||
func (_ tBlog) SetNote2Blog(
|
||||
noteId string,
|
||||
isBlog bool,
|
||||
isTop bool,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
revel.Unbind(args, "isBlog", isBlog)
|
||||
revel.Unbind(args, "isTop", isTop)
|
||||
return revel.MainRouter.Reverse("Blog.SetNote2Blog", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) SetNotebook2Blog(
|
||||
notebookId string,
|
||||
isBlog bool,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
revel.Unbind(args, "isBlog", isBlog)
|
||||
return revel.MainRouter.Reverse("Blog.SetNotebook2Blog", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) Index(
|
||||
userId string,
|
||||
notebookId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userId", userId)
|
||||
revel.Unbind(args, "notebookId", notebookId)
|
||||
return revel.MainRouter.Reverse("Blog.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) View(
|
||||
noteId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "noteId", noteId)
|
||||
return revel.MainRouter.Reverse("Blog.View", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) SearchBlog(
|
||||
userId string,
|
||||
key string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userId", userId)
|
||||
revel.Unbind(args, "key", key)
|
||||
return revel.MainRouter.Reverse("Blog.SearchBlog", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) Set(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Blog.Set", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) SetUserBlogBase(
|
||||
userBlog interface{},
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userBlog", userBlog)
|
||||
return revel.MainRouter.Reverse("Blog.SetUserBlogBase", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) SetUserBlogComment(
|
||||
userBlog interface{},
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userBlog", userBlog)
|
||||
return revel.MainRouter.Reverse("Blog.SetUserBlogComment", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) SetUserBlogStyle(
|
||||
userBlog interface{},
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userBlog", userBlog)
|
||||
return revel.MainRouter.Reverse("Blog.SetUserBlogStyle", args).Url
|
||||
}
|
||||
|
||||
func (_ tBlog) AboutMe(
|
||||
userId string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "userId", userId)
|
||||
return revel.MainRouter.Reverse("Blog.AboutMe", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tIndex struct {}
|
||||
var Index tIndex
|
||||
|
||||
|
||||
func (_ tIndex) Index(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Index.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tIndex) Suggestion(
|
||||
addr string,
|
||||
suggestion string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "addr", addr)
|
||||
revel.Unbind(args, "suggestion", suggestion)
|
||||
return revel.MainRouter.Reverse("Index.Suggestion", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tMobile struct {}
|
||||
var Mobile tMobile
|
||||
|
||||
|
||||
func (_ tMobile) Index(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Mobile.Index", args).Url
|
||||
}
|
||||
|
||||
func (_ tMobile) Logout(
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
return revel.MainRouter.Reverse("Mobile.Logout", args).Url
|
||||
}
|
||||
|
||||
|
||||
type tOauth struct {}
|
||||
var Oauth tOauth
|
||||
|
||||
|
||||
func (_ tOauth) GithubCallback(
|
||||
code string,
|
||||
) string {
|
||||
args := make(map[string]string)
|
||||
|
||||
revel.Unbind(args, "code", code)
|
||||
return revel.MainRouter.Reverse("Oauth.GithubCallback", args).Url
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 登录与权限
|
||||
|
||||
type AuthService struct {
|
||||
}
|
||||
|
||||
// pwd已md5了
|
||||
func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||
return userService.LoginGetUserInfo(emailOrUsername, Md5(pwd))
|
||||
}
|
||||
|
||||
// 注册
|
||||
/*
|
||||
注册 leanote@leanote.com userId = "5368c1aa99c37b029d000001"
|
||||
添加 在博客上添加一篇欢迎note, note1 5368c1b919807a6f95000000
|
||||
|
||||
将nk1(只读), nk2(可写) 分享给该用户
|
||||
将note1 复制到用户的生活nk上
|
||||
*/
|
||||
// 1. 添加用户
|
||||
// 2. 将leanote共享给我
|
||||
// [ok]
|
||||
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
||||
// 用户是否已存在
|
||||
if userService.IsExistsUser(email) {
|
||||
return false, email + " 已被注册"
|
||||
}
|
||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||
return this.register(user)
|
||||
}
|
||||
|
||||
func (this *AuthService) register(user info.User) (bool, string) {
|
||||
if userService.AddUser(user) {
|
||||
// 添加笔记本, 生活, 学习, 工作
|
||||
notebook := info.Notebook{
|
||||
Seq: -1,
|
||||
UserId: user.UserId}
|
||||
title2Id := map[string]bson.ObjectId{"life": bson.NewObjectId(), "study": bson.NewObjectId(), "work": bson.NewObjectId()}
|
||||
for title, objectId := range title2Id {
|
||||
notebook.Title = title
|
||||
notebook.NotebookId = objectId
|
||||
notebook.UserId = user.UserId
|
||||
notebookService.AddNotebook(notebook);
|
||||
}
|
||||
|
||||
email := user.Email
|
||||
// 添加leanote -> 该用户的共享
|
||||
leanoteUserId := "5368c1aa99c37b029d000001";
|
||||
nk1 := "5368c1aa99c37b029d000002" // leanote
|
||||
welcomeNoteId := "5368c1b919807a6f95000000" // 欢迎来到leanote
|
||||
|
||||
shareService.AddShareNotebook(nk1, 0, leanoteUserId, email);
|
||||
shareService.AddShareNote(welcomeNoteId, 0, leanoteUserId, email);
|
||||
|
||||
// 将welcome copy给我
|
||||
note := noteService.CopySharedNote(welcomeNoteId, title2Id["life"].Hex(), leanoteUserId, user.UserId.Hex());
|
||||
|
||||
// 公开为博客
|
||||
noteUpdate := bson.M{"IsBlog": true}
|
||||
noteService.UpdateNote(user.UserId.Hex(), user.UserId.Hex(), note.NoteId.Hex(), noteUpdate)
|
||||
|
||||
//---------------
|
||||
// 添加一条userBlog
|
||||
blogService.UpdateUserBlog(info.UserBlog{UserId: user.UserId,
|
||||
Title: user.Username + " 's Blog",
|
||||
SubTitle: "love leanote!",
|
||||
AboutMe: "Hello, I am (^_^)",
|
||||
})
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
//--------------
|
||||
// 第三方注册
|
||||
|
||||
// 第三方得到用户名, 可能需要多次判断
|
||||
func (this *AuthService) getUsername(thirdType, thirdUsername string) (username string) {
|
||||
username = thirdType + "-" + thirdUsername
|
||||
i := 1
|
||||
for ;; {
|
||||
if !userService.IsExistsUserByUsername(username) {
|
||||
return
|
||||
}
|
||||
username = fmt.Sprintf("%v%v", username, i)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *AuthService) ThirdRegister(thirdType, thirdUserId, thirdUsername string) (exists bool, userInfo info.User) {
|
||||
userInfo = userService.GetUserInfoByThirdUserId(thirdUserId)
|
||||
if userInfo.UserId != "" {
|
||||
exists = true
|
||||
return
|
||||
}
|
||||
|
||||
username := this.getUsername(thirdType, thirdUsername)
|
||||
userInfo = info.User{UserId: bson.NewObjectId(),
|
||||
Username: username,
|
||||
ThirdUserId: thirdUserId,
|
||||
ThirdUsername: thirdUsername,
|
||||
}
|
||||
_, _ = this.register(userInfo)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "time"
|
||||
// "sort"
|
||||
)
|
||||
|
||||
// blog
|
||||
/*
|
||||
note, notebook都可设为blog
|
||||
关键是, 怎么得到blog列表? 还要分页
|
||||
|
||||
??? 不用新建, 直接使用notes表, 添加IsBlog字段. 新建表 blogs {NoteId, UserId, CreatedTime, IsTop(置顶)}, NoteId, UserId 为unique!!
|
||||
|
||||
// 设置一个note为blog
|
||||
添加到blogs中
|
||||
|
||||
// 设置/取消notebook为blog
|
||||
创建一个note时, 如果其notebookId已设为blog, 那么添加该note到blog中.
|
||||
设置一个notebook为blog时, 将其下所有的note添加到blogs里 -> 更新其IsBlog为true
|
||||
取消一个notebook不为blog时, 删除其下的所有note -> 更新其IsBlog为false
|
||||
|
||||
*/
|
||||
type BlogService struct {
|
||||
}
|
||||
|
||||
// 得到某博客具体信息
|
||||
func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||
note := noteService.GetBlogNote(noteId)
|
||||
|
||||
if note.NoteId == "" || !note.IsBlog {
|
||||
return
|
||||
}
|
||||
|
||||
// 内容
|
||||
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
||||
|
||||
// 组装成blogItem
|
||||
blog = info.BlogItem{note, noteContent.Content, false}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 得到用户共享的notebooks
|
||||
func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
||||
notebooks := []info.Notebook{}
|
||||
db.ListByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}, ¬ebooks)
|
||||
return notebooks
|
||||
}
|
||||
|
||||
// 博客列表
|
||||
// userId 表示谁的blog
|
||||
func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
||||
count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true);
|
||||
|
||||
if(notes == nil || len(notes) == 0) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 得到content, 并且每个都要substring
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
|
||||
// 直接得到noteContents表的abstract
|
||||
// 这里可能是乱序的
|
||||
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
||||
for _, noteContent := range noteContents {
|
||||
noteContentsMap[noteContent.NoteId] = noteContent
|
||||
}
|
||||
|
||||
// 组装成blogItem
|
||||
// 按照notes的顺序
|
||||
blogs := make([]info.BlogItem, len(noteIds))
|
||||
for i, note := range notes {
|
||||
hasMore := true
|
||||
var content string
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
||||
}
|
||||
return count, blogs
|
||||
}
|
||||
|
||||
func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
||||
count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true);
|
||||
|
||||
if(notes == nil || len(notes) == 0) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 得到content, 并且每个都要substring
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
|
||||
// 直接得到noteContents表的abstract
|
||||
// 这里可能是乱序的
|
||||
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
||||
for _, noteContent := range noteContents {
|
||||
noteContentsMap[noteContent.NoteId] = noteContent
|
||||
}
|
||||
|
||||
// 组装成blogItem
|
||||
// 按照notes的顺序
|
||||
blogs := make([]info.BlogItem, len(noteIds))
|
||||
for i, note := range notes {
|
||||
hasMore := true
|
||||
var content string
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore}
|
||||
}
|
||||
return count, blogs
|
||||
}
|
||||
|
||||
|
||||
//------------------------
|
||||
// 博客设置
|
||||
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
||||
userBlog := info.UserBlog{}
|
||||
db.Get(db.UserBlogs, userId, &userBlog)
|
||||
|
||||
if userBlog.Title == "" {
|
||||
userInfo := userService.GetUserInfo(userId)
|
||||
userBlog.Title = userInfo.Username + " 的博客"
|
||||
}
|
||||
|
||||
return userBlog
|
||||
}
|
||||
|
||||
// 修改之
|
||||
func (this *BlogService) UpdateUserBlog(userBlog info.UserBlog) bool {
|
||||
return db.Upsert(db.UserBlogs, bson.M{"_id": userBlog.UserId}, userBlog)
|
||||
}
|
||||
// 修改之UserBlogBase
|
||||
func (this *BlogService) UpdateUserBlogBase(userId string, userBlog info.UserBlogBase) bool {
|
||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
}
|
||||
func (this *BlogService) UpdateUserBlogComment(userId string, userBlog info.UserBlogComment) bool {
|
||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
}
|
||||
func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBlogStyle) bool {
|
||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "time"
|
||||
)
|
||||
|
||||
// 历史记录
|
||||
type NoteContentHistoryService struct {
|
||||
}
|
||||
|
||||
// 每个历史记录最大值
|
||||
var maxSize = 10
|
||||
|
||||
// 新建一个note, 不需要添加历史记录
|
||||
// 添加历史
|
||||
func (this *NoteContentHistoryService) AddHistory(noteId, userId string, eachHistory info.EachHistory) {
|
||||
// 检查是否是空
|
||||
if eachHistory.Content == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 先查是否存在历史记录, 没有则添加之
|
||||
history := info.NoteContentHistory{}
|
||||
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &history)
|
||||
if history.NoteId == "" {
|
||||
this.newHistory(noteId, userId, eachHistory)
|
||||
} else {
|
||||
// 判断是否超出 maxSize, 如果超出则pop最后一个, 再push之, 不用那么麻烦, 直接update吧, 虽然影响性能
|
||||
// TODO
|
||||
l := len(history.Histories)
|
||||
if l >= maxSize {
|
||||
history.Histories = history.Histories[l-maxSize:]
|
||||
}
|
||||
newHistory := []info.EachHistory{eachHistory}
|
||||
newHistory = append(newHistory, history.Histories...) // 在开头加了, 最近的在最前
|
||||
history.Histories = newHistory
|
||||
|
||||
// 更新之
|
||||
db.UpdateByIdAndUserId(db.NoteContentHistories, noteId, userId, history)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 新建历史
|
||||
func (this *NoteContentHistoryService) newHistory(noteId, userId string, eachHistory info.EachHistory) {
|
||||
history := info.NoteContentHistory{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Histories: []info.EachHistory{eachHistory},
|
||||
}
|
||||
|
||||
// 保存之
|
||||
db.Insert(db.NoteContentHistories, history)
|
||||
}
|
||||
|
||||
// 列表展示
|
||||
func (this *NoteContentHistoryService) ListHistories(noteId, userId string) []info.EachHistory {
|
||||
histories := info.NoteContentHistory{}
|
||||
db.GetByIdAndUserId(db.NoteContentHistories, noteId, userId, &histories)
|
||||
return histories.Histories
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NoteService struct {
|
||||
}
|
||||
|
||||
// 通过id, userId得到note
|
||||
func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
||||
note = info.Note{}
|
||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||
return
|
||||
}
|
||||
// 得到blog, blogService用
|
||||
// 不要传userId, 因为是公开的
|
||||
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
||||
note = info.Note{}
|
||||
db.GetByQ(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId), "IsBlog": true, "IsTrash": false}, ¬e)
|
||||
return
|
||||
}
|
||||
// 通过id, userId得到noteContent
|
||||
func (this *NoteService) GetNoteContent(noteContentId, userId string) (noteContent info.NoteContent) {
|
||||
noteContent = info.NoteContent{}
|
||||
db.GetByIdAndUserId(db.NoteContents, noteContentId, userId, ¬eContent)
|
||||
return
|
||||
}
|
||||
|
||||
// 列出note, 排序规则, 还有分页
|
||||
// CreatedTime, UpdatedTime, title 来排序
|
||||
func (this *NoteService) ListNotes(userId, notebookId string,
|
||||
isTrash bool, pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (count int, notes []info.Note) {
|
||||
notes = []info.Note{}
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsTrash": isTrash}
|
||||
if isBlog {
|
||||
query["IsBlog"] = true
|
||||
}
|
||||
if notebookId != "" {
|
||||
query["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||
}
|
||||
|
||||
q := db.Notes.Find(query);
|
||||
|
||||
// 总记录数
|
||||
count, _ = q.Count()
|
||||
|
||||
q.Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过noteIds来查询
|
||||
// ShareService调用
|
||||
func (this *NoteService) ListNotesByNoteIdsWithPageSort(noteIds []bson.ObjectId, userId string,
|
||||
pageNumber, pageSize int, sortField string, isAsc bool, isBlog bool) (notes []info.Note) {
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
notes = []info.Note{}
|
||||
|
||||
// 不是trash
|
||||
db.Notes.
|
||||
Find(bson.M{"_id": bson.M{"$in": noteIds}, "IsTrash": false}).
|
||||
Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
return
|
||||
}
|
||||
// shareService调用
|
||||
func (this *NoteService) ListNotesByNoteIds(noteIds []bson.ObjectId) (notes []info.Note) {
|
||||
notes = []info.Note{}
|
||||
|
||||
db.Notes.
|
||||
Find(bson.M{"_id": bson.M{"$in": noteIds}}).
|
||||
All(¬es)
|
||||
return
|
||||
}
|
||||
// blog需要
|
||||
func (this *NoteService) ListNoteContentsByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
|
||||
notes = []info.NoteContent{}
|
||||
|
||||
db.NoteContents.
|
||||
Find(bson.M{"_id": bson.M{"$in": noteIds}}).
|
||||
All(¬es)
|
||||
return
|
||||
}
|
||||
// 只得到abstract, 不需要content
|
||||
func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
|
||||
notes = []info.NoteContent{}
|
||||
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
||||
return
|
||||
}
|
||||
|
||||
// 添加笔记
|
||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||
// [ok]
|
||||
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
noteId := bson.NewObjectId();
|
||||
note.NoteId = noteId;
|
||||
}
|
||||
note.CreatedTime = time.Now()
|
||||
note.UpdatedTime = note.CreatedTime
|
||||
note.IsTrash = false
|
||||
note.UpdatedUserId = note.UserId
|
||||
|
||||
// 设为blog
|
||||
note.IsBlog = notebookService.IsBlog(note.NotebookId.Hex())
|
||||
|
||||
db.Insert(db.Notes, note)
|
||||
|
||||
// tag1
|
||||
tagService.AddTags(note.UserId.Hex(), note.Tags)
|
||||
|
||||
return note
|
||||
}
|
||||
|
||||
// 添加共享d笔记
|
||||
func (this *NoteService) AddSharedNote(note info.Note, myUserId bson.ObjectId) info.Note {
|
||||
// 判断我是否有权限添加
|
||||
if shareService.HasUpdateNotebookPerm(note.UserId.Hex(), myUserId.Hex(), note.NotebookId.Hex()) {
|
||||
note.CreatedUserId = myUserId // 是我给共享我的人创建的
|
||||
return this.AddNote(note)
|
||||
}
|
||||
return info.Note{}
|
||||
}
|
||||
|
||||
|
||||
// 添加笔记本内容
|
||||
// [ok]
|
||||
func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteContent {
|
||||
noteContent.CreatedTime = time.Now()
|
||||
noteContent.UpdatedTime = noteContent.CreatedTime
|
||||
noteContent.UpdatedUserId = noteContent.UserId
|
||||
db.Insert(db.NoteContents, noteContent)
|
||||
return noteContent;
|
||||
}
|
||||
|
||||
// 添加笔记和内容
|
||||
// 这里使用 info.NoteAndContent 接收?
|
||||
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
noteId := bson.NewObjectId()
|
||||
note.NoteId = noteId
|
||||
}
|
||||
noteContent.NoteId = note.NoteId
|
||||
if note.UserId != myUserId {
|
||||
note = this.AddSharedNote(note, myUserId)
|
||||
} else {
|
||||
note = this.AddNote(note)
|
||||
}
|
||||
if note.NoteId != "" {
|
||||
this.AddNoteContent(noteContent)
|
||||
}
|
||||
return note
|
||||
}
|
||||
|
||||
// 修改笔记
|
||||
// [ok] TODO perm还没测
|
||||
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||
if userId != updatedUserId {
|
||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||
Log("NO AUTH")
|
||||
return false
|
||||
} else {
|
||||
Log("HAS AUTH -----------")
|
||||
}
|
||||
}
|
||||
|
||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
|
||||
// 添加tag2
|
||||
if tags, ok := needUpdate["Tags"]; ok {
|
||||
tagService.AddTagsI(userId, tags)
|
||||
}
|
||||
|
||||
// 是否修改了isBlog
|
||||
// 也要修改noteContents的IsBlog
|
||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||
db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{"IsBlog": isBlog})
|
||||
}
|
||||
|
||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, needUpdate)
|
||||
}
|
||||
|
||||
// 这里要判断权限, 如果userId != updatedUserId, 那么需要判断权限
|
||||
// [ok] TODO perm还没测 [del]
|
||||
func (this *NoteService) UpdateNoteTitle(userId, updatedUserId, noteId, title string) bool {
|
||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||
if userId != updatedUserId {
|
||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||
println("NO AUTH")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId,
|
||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId), "Title": title, "UpdatedTime": time.Now()})
|
||||
}
|
||||
|
||||
// 修改笔记本内容
|
||||
// [ok] TODO perm未测
|
||||
func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, content, abstract string) bool {
|
||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||
if userId != updatedUserId {
|
||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||
Log("NO AUTH")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId,
|
||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||
"Content": content,
|
||||
"Abstract": abstract,
|
||||
"UpdatedTime": time.Now()}) {
|
||||
|
||||
// 这里, 添加历史记录
|
||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||
Content: content,
|
||||
UpdatedTime: time.Now(),
|
||||
})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 更新tags
|
||||
// [ok] [del]
|
||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
||||
}
|
||||
|
||||
// 移动note
|
||||
// trash, 正常的都可以用
|
||||
// 1. 要检查下notebookId是否是自己的
|
||||
// 2. 要判断之前是否是blog, 如果不是, 那么notebook是否是blog?
|
||||
func (this *NoteService) MoveNote(noteId, notebookId, userId string) info.Note {
|
||||
if notebookService.IsMyNotebook(notebookId, userId) {
|
||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||
bson.M{"$set": bson.M{"IsTrash": false,
|
||||
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||
|
||||
if re {
|
||||
// 更新blog状态
|
||||
this.updateToNotebookBlog(noteId, notebookId, userId)
|
||||
}
|
||||
|
||||
return this.GetNote(noteId, userId);
|
||||
}
|
||||
return info.Note{}
|
||||
}
|
||||
|
||||
// 如果自己的blog状态是true, 不用改变,
|
||||
// 否则, 如果notebookId的blog是true, 则改为true之
|
||||
// 返回blog状态
|
||||
func (this *NoteService) updateToNotebookBlog(noteId, notebookId, userId string) bool {
|
||||
if this.IsBlog(noteId) {
|
||||
return true
|
||||
}
|
||||
if notebookService.IsBlog(notebookId) {
|
||||
db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||
bson.M{"$set": bson.M{"IsBlog": true}})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
// 判断是否是blog
|
||||
func (this *NoteService) IsBlog(noteId string) bool {
|
||||
note := info.Note{}
|
||||
db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"IsBlog"}, ¬e);
|
||||
return note.IsBlog
|
||||
}
|
||||
|
||||
// 复制note
|
||||
// 正常的可以用
|
||||
// 先查, 再新建
|
||||
// 要检查下notebookId是否是自己的
|
||||
func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
|
||||
if notebookService.IsMyNotebook(notebookId, userId) {
|
||||
note := this.GetNote(noteId, userId)
|
||||
noteContent := this.GetNoteContent(noteId, userId)
|
||||
|
||||
// 重新生成noteId
|
||||
note.NoteId = bson.NewObjectId();
|
||||
note.NotebookId = bson.ObjectIdHex(notebookId)
|
||||
|
||||
noteContent.NoteId = note.NoteId
|
||||
this.AddNoteAndContent(note, noteContent, note.UserId);
|
||||
|
||||
// 更新blog状态
|
||||
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, userId)
|
||||
|
||||
note.IsBlog = isBlog
|
||||
return note
|
||||
}
|
||||
|
||||
return info.Note{}
|
||||
}
|
||||
|
||||
// 复制别人的共享笔记给我
|
||||
// TODO 判断是否共享了给我
|
||||
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
|
||||
if notebookService.IsMyNotebook(notebookId, myUserId) {
|
||||
note := this.GetNote(noteId, fromUserId)
|
||||
if note.NoteId == "" {
|
||||
return info.Note{}
|
||||
}
|
||||
noteContent := this.GetNoteContent(noteId, fromUserId)
|
||||
|
||||
// 重新生成noteId
|
||||
note.NoteId = bson.NewObjectId();
|
||||
note.NotebookId = bson.ObjectIdHex(notebookId)
|
||||
note.UserId = bson.ObjectIdHex(myUserId)
|
||||
note.IsTop = false
|
||||
note.IsBlog = false // 别人的可能是blog
|
||||
|
||||
// content
|
||||
noteContent.NoteId = note.NoteId
|
||||
noteContent.UserId = note.UserId
|
||||
|
||||
// 添加之
|
||||
note = this.AddNoteAndContent(note, noteContent, note.UserId);
|
||||
|
||||
// 更新blog状态
|
||||
isBlog := this.updateToNotebookBlog(note.NoteId.Hex(), notebookId, myUserId)
|
||||
|
||||
note.IsBlog = isBlog
|
||||
return note
|
||||
}
|
||||
|
||||
return info.Note{}
|
||||
}
|
||||
|
||||
// 通过noteId得到notebookId
|
||||
// shareService call
|
||||
// [ok]
|
||||
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
||||
note := &info.Note{}
|
||||
db.Get(db.Notes, noteId, note)
|
||||
return note.NotebookId
|
||||
}
|
||||
|
||||
//------------------
|
||||
// 搜索Note
|
||||
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
||||
notes = []info.Note{}
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
||||
}
|
||||
if isBlog {
|
||||
query["IsBlog"] = true
|
||||
}
|
||||
q := db.Notes.Find(query);
|
||||
|
||||
// 总记录数
|
||||
count, _ = q.Count()
|
||||
|
||||
q.Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
|
||||
// 如果 < pageSize 那么搜索content, 且id不在这些id之间的
|
||||
if len(notes) < pageSize {
|
||||
notes = this.searchNoteFromContent(notes, userId, key, pageSize, sortFieldR, isBlog)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 搜索noteContents, 补集pageSize个
|
||||
func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key string, pageSize int, sortField string, isBlog bool) []info.Note {
|
||||
var remain = pageSize - len(notes)
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
LogJ(noteIds)
|
||||
noteContents := []info.NoteContent{}
|
||||
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
||||
if isBlog {
|
||||
query["IsBlog"] = true
|
||||
}
|
||||
db.NoteContents.
|
||||
Find(query).
|
||||
Sort(sortField).
|
||||
Limit(remain).
|
||||
Select(bson.M{"_id": true}).
|
||||
All(¬eContents)
|
||||
var lenContent = len(noteContents)
|
||||
if(lenContent == 0) {
|
||||
return notes
|
||||
}
|
||||
|
||||
// 收集ids
|
||||
noteIds2 := make([]bson.ObjectId, lenContent)
|
||||
for i, content := range noteContents {
|
||||
noteIds2[i] = content.NoteId
|
||||
}
|
||||
|
||||
// Log(" content search ")
|
||||
// Log(lenContent)
|
||||
|
||||
// 得到notes
|
||||
notes2 := this.ListNotesByNoteIds(noteIds2)
|
||||
|
||||
// 合并之
|
||||
notes = append(notes, notes2...)
|
||||
return notes
|
||||
}
|
||||
|
||||
//----------------
|
||||
// tag搜索
|
||||
func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumber, pageSize int, sortField string, isAsc bool) (count int, notes []info.Note) {
|
||||
notes = []info.Note{}
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"Tags": bson.M{"$all": tags}}
|
||||
|
||||
q := db.Notes.Find(query);
|
||||
|
||||
// 总记录数
|
||||
count, _ = q.Count()
|
||||
|
||||
Log(count)
|
||||
|
||||
q.Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 笔记本
|
||||
|
||||
type NotebookService struct {
|
||||
}
|
||||
|
||||
// 排序
|
||||
func sortSubNotebooks(eachNotebooks info.SubNotebooks) info.SubNotebooks {
|
||||
// 遍历子, 则子往上进行排序
|
||||
for _, eachNotebook := range eachNotebooks {
|
||||
if eachNotebook.Subs != nil && len(eachNotebook.Subs) > 0 {
|
||||
eachNotebook.Subs = sortSubNotebooks(eachNotebook.Subs)
|
||||
}
|
||||
}
|
||||
|
||||
// 子排完了, 本层排
|
||||
sort.Sort(&eachNotebooks)
|
||||
return eachNotebooks
|
||||
}
|
||||
|
||||
// 整理(成有关系)并排序
|
||||
// GetNotebooks()调用
|
||||
// ShareService调用
|
||||
func ParseAndSortNotebooks(userNotebooks []info.Notebook, noParentDelete, needSort bool) info.SubNotebooks {
|
||||
// 整理成info.Notebooks
|
||||
// 第一遍, 建map
|
||||
// notebookId => info.Notebooks
|
||||
userNotebooksMap := make(map[bson.ObjectId]*info.Notebooks, len(userNotebooks))
|
||||
for _, each := range userNotebooks {
|
||||
newNotebooks := info.Notebooks{Subs: info.SubNotebooks{}}
|
||||
newNotebooks.NotebookId = each.NotebookId
|
||||
newNotebooks.Title = each.Title
|
||||
newNotebooks.Seq = each.Seq
|
||||
newNotebooks.UserId = each.UserId
|
||||
newNotebooks.ParentNotebookId = each.ParentNotebookId
|
||||
newNotebooks.NumberNotes = each.NumberNotes
|
||||
newNotebooks.IsTrash = each.IsTrash
|
||||
newNotebooks.IsBlog = each.IsBlog
|
||||
userNotebooksMap[each.NotebookId] = &newNotebooks
|
||||
}
|
||||
|
||||
// 第二遍, 追加到父下
|
||||
// nilObjectId := bson.ObjectIdHex("")
|
||||
for id, each := range userNotebooksMap {
|
||||
// 如果有父, 那么追加到父下, 并剪掉当前, 那么最后就只有根的元素
|
||||
if each.ParentNotebookId.Hex() != "" {
|
||||
if userNotebooksMap[each.ParentNotebookId] != nil {
|
||||
userNotebooksMap[each.ParentNotebookId].Subs = append(userNotebooksMap[each.ParentNotebookId].Subs, *each)
|
||||
// 并剪掉
|
||||
delete(userNotebooksMap, id)
|
||||
} else if noParentDelete {
|
||||
// 没有父, 且设置了要删除
|
||||
delete(userNotebooksMap, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第三遍, 得到所有根
|
||||
final := make(info.SubNotebooks, len(userNotebooksMap))
|
||||
i := 0
|
||||
for _, each := range userNotebooksMap {
|
||||
final[i] = *each
|
||||
i++
|
||||
}
|
||||
|
||||
// 最后排序
|
||||
if needSort {
|
||||
return sortSubNotebooks(final)
|
||||
}
|
||||
return final
|
||||
}
|
||||
|
||||
// 得到某notebook
|
||||
func (this *NotebookService) GetNotebook(notebookId, userId string) info.Notebook {
|
||||
notebook := info.Notebook{}
|
||||
db.GetByIdAndUserId(db.Notebooks, notebookId, userId, ¬ebook)
|
||||
return notebook
|
||||
}
|
||||
|
||||
// 得到用户下所有的notebook
|
||||
// 排序好之后返回
|
||||
// [ok]
|
||||
func (this *NotebookService) GetNotebooks(userId string) info.SubNotebooks {
|
||||
userNotebooks := []info.Notebook{}
|
||||
db.Notebooks.Find(bson.M{"UserId": bson.ObjectIdHex(userId)}).All(&userNotebooks)
|
||||
|
||||
if len(userNotebooks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ParseAndSortNotebooks(userNotebooks, true, true)
|
||||
}
|
||||
|
||||
// share调用, 不需要删除没有父的notebook
|
||||
// 不需要排序, 因为会重新排序
|
||||
// 通过notebookIds得到notebooks, 并转成层次有序
|
||||
func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.ObjectId) info.SubNotebooks {
|
||||
userNotebooks := []info.Notebook{}
|
||||
db.Notebooks.Find(bson.M{"_id": bson.M{"$in": notebookIds}}).All(&userNotebooks)
|
||||
|
||||
if len(userNotebooks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ParseAndSortNotebooks(userNotebooks, false, false)
|
||||
}
|
||||
|
||||
// 添加
|
||||
// [ok]
|
||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||
err := db.Notebooks.Insert(notebook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 判断是否是blog
|
||||
func (this *NotebookService) IsBlog(notebookId string) bool {
|
||||
notebook := info.Notebook{}
|
||||
db.GetByQWithFields(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId)}, []string{"IsBlog"}, ¬ebook);
|
||||
return notebook.IsBlog
|
||||
}
|
||||
|
||||
// 判断是否是我的notebook
|
||||
func (this *NotebookService) IsMyNotebook(notebookId, userId string) bool {
|
||||
return db.Has(db.Notebooks, bson.M{"_id": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)})
|
||||
}
|
||||
|
||||
// 更新笔记本信息
|
||||
// 太广, 不用
|
||||
/*
|
||||
func (this *NotebookService) UpdateNotebook(notebook info.Notebook) bool {
|
||||
return db.UpdateByIdAndUserId2(db.Notebooks, notebook.NotebookId, notebook.UserId, notebook)
|
||||
}
|
||||
*/
|
||||
|
||||
// 更新笔记本标题
|
||||
// [ok]
|
||||
func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title string) bool {
|
||||
return db.UpdateByIdAndUserIdField(db.Notebooks, notebookId, userId, "Title", title)
|
||||
}
|
||||
|
||||
// 更新notebook
|
||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
|
||||
// 如果有IsBlog之类的, 需要特殊处理
|
||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||
// 设为blog/取消
|
||||
if is, ok2 := isBlog.(bool); ok2 {
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||
db.UpdateByQMap(db.Notes, q, bson.M{"IsBlog": is})
|
||||
|
||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||
// 先查该notebook下所有notes, 得到id
|
||||
notes := []info.Note{}
|
||||
db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es)
|
||||
if len(notes) > 0 {
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, each := range notes {
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||
}
|
||||
|
||||
// 先查看该notebookId下是否有notes, 没有则删除
|
||||
func (this *NotebookService) DeleteNotebook(userId, notebookId string) (bool, string) {
|
||||
if db.Count(db.Notes, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false}) == 0 { // 不包含trash
|
||||
return db.DeleteByIdAndUserId(db.Notebooks, notebookId, userId), ""
|
||||
}
|
||||
return false, "笔记本下有笔记"
|
||||
}
|
||||
|
||||
// 排序
|
||||
// 传入 notebookId => Seq
|
||||
// 为什么要传入userId, 防止修改其它用户的信息 (恶意)
|
||||
// [ok]
|
||||
func (this *NotebookService) SortNotebooks(userId string, notebookId2Seqs map[string]int) bool {
|
||||
if len(notebookId2Seqs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for notebookId, seq := range notebookId2Seqs {
|
||||
if !db.UpdateByIdAndUserIdField2(db.Notebooks, bson.ObjectIdHex(notebookId), bson.ObjectIdHex(userId), "Seq", seq) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 找回密码
|
||||
// 修改密码
|
||||
var overHours = 2.0 // 小时后过期
|
||||
|
||||
type PwdService struct {
|
||||
}
|
||||
|
||||
// 1. 找回密码, 通过email找用户,
|
||||
// 用户存在, 生成code
|
||||
func (this *PwdService) FindPwd(email string) (ok bool, msg string) {
|
||||
ok = false
|
||||
userId := userService.GetUserId(email)
|
||||
if userId == "" {
|
||||
msg = "用户不存在"
|
||||
return
|
||||
}
|
||||
|
||||
token := tokenService.NewToken(userId, email, info.TokenPwd)
|
||||
if token == "" {
|
||||
return false, "db error"
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://leanote.com/findPassword/" + token
|
||||
body := fmt.Sprintf("请点击链接修改密码: <a href='%v'>%v</a>. %v小时后过期.", url, url, int(overHours));
|
||||
if !SendEmail(email, "leanote-找回密码", "找回密码", body) {
|
||||
return false, "邮箱发送失败"
|
||||
}
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
// 先验证
|
||||
func (this *PwdService) UpdatePwd(token, pwd string) (bool, string) {
|
||||
var tokenInfo info.Token
|
||||
var ok bool
|
||||
var msg string
|
||||
|
||||
// 先验证
|
||||
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenPwd); !ok {
|
||||
return ok, msg
|
||||
}
|
||||
|
||||
// 修改密码之
|
||||
ok = db.UpdateByQField(db.Users, bson.M{"_id": tokenInfo.UserId}, "Pwd", Md5(pwd))
|
||||
|
||||
// 删除token
|
||||
tokenService.DeleteToken(tokenInfo.UserId.Hex(), info.TokenPwd)
|
||||
|
||||
return ok, ""
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
All services. Called by controller
|
||||
@@ -0,0 +1,510 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 共享Notebook, Note服务
|
||||
type ShareService struct {
|
||||
}
|
||||
|
||||
//-----------------
|
||||
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
||||
|
||||
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
||||
// 每更新一次则启动一个goroutine异步更新
|
||||
// 共享只能共享本notebook下的, 如果其子也要共享, 必须设置其子!!!
|
||||
// 那么, 父, 子在shareNotebooks表中都会有记录
|
||||
|
||||
// 得到用户的所有*被*共享的Notebook
|
||||
// 1 得到别人共享给我的所有notebooks
|
||||
// 2 按parent进行层次化
|
||||
// 3 每个层按seq进行排序
|
||||
// 4 按用户分组
|
||||
// [ok]
|
||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||
//-------------
|
||||
// 查询HasShareNote表得到所有其它用户信息
|
||||
hasShareNotes := []info.HasShareNote{}
|
||||
db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes);
|
||||
|
||||
userIds := make([]bson.ObjectId, len(hasShareNotes))
|
||||
for i, each := range hasShareNotes {
|
||||
userIds[i] = each.UserId
|
||||
}
|
||||
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||
|
||||
//--------------------
|
||||
// 得到他们共享给我的notebooks
|
||||
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
db.ShareNotebooks.Find(bson.M{"ToUserId": bson.ObjectIdHex(userId)}).All(&shareNotebooks)
|
||||
|
||||
if len(shareNotebooks) == 0 {
|
||||
return nil, userInfos
|
||||
}
|
||||
|
||||
shareNotebooksLen := len(shareNotebooks)
|
||||
|
||||
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
||||
notebookIds := make([]bson.ObjectId, shareNotebooksLen)
|
||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
||||
for i, each := range shareNotebooks {
|
||||
// 默认的是没有notebookId的
|
||||
notebookIds[i] = each.NotebookId
|
||||
shareNotebooksMap[each.NotebookId] = each
|
||||
}
|
||||
|
||||
// 1, 2
|
||||
subNotebooks := notebookService.GetNotebooksByNotebookIds(notebookIds)
|
||||
// 填充其它信息变成SubShareNotebooks
|
||||
subShareNotebooks := this.parseToSubShareNotebooks(&subNotebooks, &shareNotebooksMap)
|
||||
|
||||
// 3 按用户进行分组成ShareNotebooksByUser
|
||||
shareNotebooksByUsersMap := map[bson.ObjectId] []info.ShareNotebooks{}
|
||||
// 先建立userId => []
|
||||
for _, eachSub := range subShareNotebooks {
|
||||
userId := eachSub.Notebook.UserId
|
||||
if _, ok := shareNotebooksByUsersMap[userId]; ok {
|
||||
shareNotebooksByUsersMap[userId] = append(shareNotebooksByUsersMap[userId], eachSub)
|
||||
} else {
|
||||
shareNotebooksByUsersMap[userId] = []info.ShareNotebooks{eachSub}
|
||||
}
|
||||
}
|
||||
shareNotebooksByUser := info.ShareNotebooksByUser{};
|
||||
for userId, eachShareNotebooks := range shareNotebooksByUsersMap {
|
||||
// 4, 按用户排序
|
||||
shareNotebooksByUser[userId.Hex()] = sortSubShareNotebooks(eachShareNotebooks)
|
||||
}
|
||||
|
||||
return shareNotebooksByUser, userInfos
|
||||
}
|
||||
|
||||
// 排序
|
||||
func sortSubShareNotebooks(eachNotebooks info.SubShareNotebooks) info.SubShareNotebooks {
|
||||
// 遍历子, 则子往上进行排序
|
||||
for _, eachNotebook := range eachNotebooks {
|
||||
if eachNotebook.Subs != nil && len(eachNotebook.Subs) > 0 {
|
||||
eachNotebook.Subs = sortSubShareNotebooks(eachNotebook.Subs)
|
||||
}
|
||||
}
|
||||
|
||||
// 子排完了, 本层排
|
||||
sort.Sort(&eachNotebooks)
|
||||
return eachNotebooks
|
||||
}
|
||||
|
||||
// 将普通的notebooks添加perm及shareNotebook信息
|
||||
func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNotebooks, shareNotebooksMap *map[bson.ObjectId]info.ShareNotebook) info.SubShareNotebooks {
|
||||
subShareNotebooks := info.SubShareNotebooks{}
|
||||
for _, each := range *subNotebooks {
|
||||
shareNotebooks := info.ShareNotebooks{}
|
||||
shareNotebooks.Notebook = each.Notebook // 基本信息有了
|
||||
shareNotebooks.ShareNotebook = (*shareNotebooksMap)[each.NotebookId] // perm有了
|
||||
|
||||
// 公用的, 单独赋值
|
||||
shareNotebooks.Seq = shareNotebooks.ShareNotebook.Seq
|
||||
shareNotebooks.NotebookId = shareNotebooks.ShareNotebook.NotebookId
|
||||
|
||||
// 还有其子, 递归解析之
|
||||
if each.Subs != nil && len(each.Subs) > 0 {
|
||||
shareNotebooks.Subs = this.parseToSubShareNotebooks(&each.Subs, shareNotebooksMap)
|
||||
}
|
||||
subShareNotebooks = append(subShareNotebooks, shareNotebooks)
|
||||
}
|
||||
|
||||
return subShareNotebooks
|
||||
}
|
||||
|
||||
//-------------
|
||||
|
||||
// 得到共享笔记本下的notes
|
||||
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
||||
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
||||
shareNotebook := info.ShareNotebook{}
|
||||
db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
|
||||
|
||||
if shareNotebook.NotebookId == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
perm := shareNotebook.Perm
|
||||
|
||||
// 2 得到该notebook下分页显示所有的notes
|
||||
_, notes := noteService.ListNotes(sharedUserId, notebookId, false, page, pageSize, sortField, isAsc, false);
|
||||
|
||||
// 3 添加权限信息
|
||||
// 3.1 如果该notebook自己有其它权限信息, 比如1, 那么覆盖notebook的权限信息
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, note := range notes {
|
||||
noteIds[i] = note.NoteId
|
||||
}
|
||||
notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId);
|
||||
|
||||
// 3.2 组合
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
||||
for i, each := range notes {
|
||||
thisPerm := perm;
|
||||
if selfPerm, ok := notePerms[each.NoteId]; ok {
|
||||
thisPerm = selfPerm
|
||||
}
|
||||
|
||||
notesWithPerm[i] = info.ShareNoteWithPerm{each, thisPerm}
|
||||
}
|
||||
return notesWithPerm
|
||||
}
|
||||
|
||||
// 得到note的perm信息
|
||||
func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||
shareNotes := []info.ShareNote{}
|
||||
db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||
|
||||
notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||
for _, each := range shareNotes {
|
||||
notesPerm[each.NoteId] = each.Perm
|
||||
}
|
||||
|
||||
return notesPerm
|
||||
}
|
||||
|
||||
// 得到默认的单个的notes 共享集
|
||||
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
||||
// 可以这样! 到时将零散的共享noteId放在用户基本数据中
|
||||
// 这里不好排序
|
||||
func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
||||
pageNumber, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||
|
||||
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
shareNotes := []info.ShareNote{}
|
||||
|
||||
db.ShareNotes.
|
||||
Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
|
||||
// Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(&shareNotes)
|
||||
|
||||
if len(shareNotes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
noteIds := make([]bson.ObjectId, len(shareNotes))
|
||||
for i, each := range shareNotes {
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
notes := noteService.ListNotesByNoteIds(noteIds)
|
||||
notesMap := make(map[bson.ObjectId]info.Note, len(notes))
|
||||
for _, each := range notes {
|
||||
notesMap[each.NoteId] = each
|
||||
}
|
||||
|
||||
// 将shareNotes与notes结合起来
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
|
||||
for i, each := range shareNotes {
|
||||
notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
|
||||
}
|
||||
return notesWithPerm
|
||||
}
|
||||
|
||||
func (this *ShareService) notes2NotesWithPerm(notes []info.Note) {
|
||||
|
||||
}
|
||||
|
||||
// 添加一个notebook共享
|
||||
// [ok]
|
||||
func (this *ShareService) AddShareNotebook1(shareNotebook info.ShareNotebook) bool {
|
||||
// 添加一条记录说明两者存在关系
|
||||
this.AddHasShareNote(shareNotebook.UserId.Hex(), shareNotebook.ToUserId.Hex());
|
||||
|
||||
shareNotebook.CreatedTime = time.Now()
|
||||
return db.Insert(db.ShareNotebooks, shareNotebook)
|
||||
}
|
||||
|
||||
// 添加共享笔记本
|
||||
func (this *ShareService) AddShareNotebook(notebookId string, perm int, userId, email string) (bool, string, string) {
|
||||
// 通过email得到被共享的userId
|
||||
toUserId := userService.GetUserId(email)
|
||||
if toUserId == "" {
|
||||
return false, "无该用户", ""
|
||||
}
|
||||
|
||||
// 添加一条记录说明两者存在关系
|
||||
this.AddHasShareNote(userId, toUserId);
|
||||
|
||||
// 先删除之
|
||||
db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||
});
|
||||
|
||||
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
ToUserId: bson.ObjectIdHex(toUserId),
|
||||
Perm: perm,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.ShareNotebooks, shareNotebook), "", toUserId
|
||||
}
|
||||
|
||||
// 添加一个note共享
|
||||
// [ok]
|
||||
/*
|
||||
func (this *ShareService) AddShareNote(shareNote info.ShareNote) bool {
|
||||
shareNote.CreatedTime = time.Now()
|
||||
return db.Insert(db.ShareNotes, shareNote)
|
||||
}
|
||||
*/
|
||||
func (this *ShareService) AddShareNote(noteId string, perm int, userId, email string) (bool, string, string) {
|
||||
// 通过email得到被共享的userId
|
||||
toUserId := userService.GetUserId(email)
|
||||
if toUserId == "" {
|
||||
return false, "无该用户", ""
|
||||
}
|
||||
|
||||
// 添加一条记录说明两者存在关系
|
||||
this.AddHasShareNote(userId, toUserId);
|
||||
|
||||
// 先删除之
|
||||
db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
|
||||
"UserId": bson.ObjectIdHex(userId),
|
||||
"ToUserId": bson.ObjectIdHex(toUserId),
|
||||
});
|
||||
|
||||
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
ToUserId: bson.ObjectIdHex(toUserId),
|
||||
Perm: perm,
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||
}
|
||||
|
||||
// updatedUserId是否有修改userId noteId的权限?
|
||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||
// 1. noteId是否被共享了?
|
||||
// 得到该note share的信息
|
||||
/*
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
*/
|
||||
if !db.Has(db.ShareNotes,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) {
|
||||
// noteId的notebookId是否被共享了?
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId.Hex() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId, "Perm": 1}) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// updatedUserId是否有修改userId notebookId的权限?
|
||||
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 共享note, notebook时使用
|
||||
func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
|
||||
db.Insert(db.HasShareNotes, info.HasShareNote{UserId: bson.ObjectIdHex(userId), ToUserId: bson.ObjectIdHex(toUserId)})
|
||||
return true;
|
||||
}
|
||||
|
||||
// userId是否被共享了noteId
|
||||
func (this *ShareService) hasSharedNote(noteId, myUserId string) bool {
|
||||
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
|
||||
}
|
||||
// noteId的notebook是否共享了给我
|
||||
func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
|
||||
note := noteService.GetNote(noteId, sharedUserId)
|
||||
if note.NoteId != "" {
|
||||
return db.Has(db.ShareNotebooks, bson.M{"NotebookId": note.NotebookId,
|
||||
"UserId": bson.ObjectIdHex(sharedUserId),
|
||||
"ToUserId": bson.ObjectIdHex(myUserId),
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 得到共享的笔记内容
|
||||
// 首先要判断这个note是否我被共享了
|
||||
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
||||
noteContent = info.NoteContent{}
|
||||
// 是否单独共享了该notebook
|
||||
// 或者, 其notebook共享了我
|
||||
if this.hasSharedNote(noteId, myUserId) || this.hasSharedNotebook(noteId, myUserId, sharedUserId) {
|
||||
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||
} else {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 查看note的分享信息
|
||||
// 分享给了哪些用户和权限
|
||||
// ShareNotes表 userId = me, noteId = ...
|
||||
// 还要查看该note的notebookId分享的信息
|
||||
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
||||
// 得到shareNote信息, 得到所有的ToUserId
|
||||
shareNotes := []info.ShareNote{}
|
||||
db.ListByQLimit(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}, &shareNotes, 100)
|
||||
|
||||
if len(shareNotes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
shareNotesMap := make(map[bson.ObjectId]info.ShareNote, len(shareNotes))
|
||||
for _, each := range shareNotes {
|
||||
shareNotesMap[each.ToUserId] = each
|
||||
}
|
||||
|
||||
toUserIds := make([]bson.ObjectId, len(shareNotes))
|
||||
for i, eachShareNote := range shareNotes {
|
||||
toUserIds[i] = eachShareNote.ToUserId
|
||||
}
|
||||
|
||||
note := noteService.GetNote(noteId, userId)
|
||||
if note.NoteId == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查看其notebook的shareNotebooks信息
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
db.ListByQ(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": note.NotebookId, "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.M{"$in": toUserIds}},
|
||||
&shareNotebooks)
|
||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, len(shareNotebooks))
|
||||
for _, each := range shareNotebooks {
|
||||
shareNotebooksMap[each.ToUserId] = each
|
||||
}
|
||||
|
||||
// 得到用户信息
|
||||
userInfos := userService.ListUserInfosByUserIds(toUserIds)
|
||||
|
||||
if len(userInfos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
shareUserInfos := make([]info.ShareUserInfo, len(userInfos))
|
||||
|
||||
for i, userInfo := range userInfos {
|
||||
_, hasNotebook := shareNotebooksMap[userInfo.UserId]
|
||||
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
|
||||
Email: userInfo.Email,
|
||||
Perm: shareNotesMap[userInfo.UserId].Perm,
|
||||
NotebookHasShared: hasNotebook,
|
||||
}
|
||||
}
|
||||
|
||||
return shareUserInfos
|
||||
}
|
||||
|
||||
// 得到notebook的share信息
|
||||
// TODO 这里必须要分页, 最多取100个用户; 限制
|
||||
func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) []info.ShareUserInfo {
|
||||
// notebook的shareNotebooks信息
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
|
||||
db.ListByQLimit(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)},
|
||||
&shareNotebooks, 100)
|
||||
|
||||
if len(shareNotebooks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 得到用户信息
|
||||
toUserIds := make([]bson.ObjectId, len(shareNotebooks))
|
||||
for i, each := range shareNotebooks {
|
||||
toUserIds[i] = each.ToUserId
|
||||
}
|
||||
userInfos := userService.ListUserInfosByUserIds(toUserIds)
|
||||
|
||||
if len(userInfos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, len(shareNotebooks))
|
||||
for _, each := range shareNotebooks {
|
||||
shareNotebooksMap[each.ToUserId] = each
|
||||
}
|
||||
|
||||
shareUserInfos := make([]info.ShareUserInfo, len(userInfos))
|
||||
for i, userInfo := range userInfos {
|
||||
shareUserInfos[i] = info.ShareUserInfo{ToUserId: userInfo.UserId,
|
||||
Email: userInfo.Email,
|
||||
Perm: shareNotebooksMap[userInfo.UserId].Perm,
|
||||
}
|
||||
}
|
||||
|
||||
return shareUserInfos
|
||||
}
|
||||
|
||||
|
||||
//----------------
|
||||
// 改变note share权限
|
||||
func (this *ShareService) UpdateShareNotePerm(noteId string, perm int, userId, toUserId string) bool {
|
||||
return db.UpdateByQField(db.ShareNotes,
|
||||
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)},
|
||||
"Perm",
|
||||
perm,
|
||||
)
|
||||
}
|
||||
|
||||
func (this *ShareService) UpdateShareNotebookPerm(notebookId string, perm int, userId, toUserId string) bool {
|
||||
return db.UpdateByQField(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)},
|
||||
"Perm",
|
||||
perm,
|
||||
)
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 删除share note
|
||||
func (this *ShareService) DeleteShareNote(noteId string, userId, toUserId string) bool {
|
||||
return db.DeleteAll(db.ShareNotes,
|
||||
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)})
|
||||
}
|
||||
|
||||
// 删除笔记时要删除该noteId的所有...
|
||||
func (this *ShareService) DeleteShareNoteAll(noteId string, userId string) bool {
|
||||
return db.DeleteAll(db.ShareNotes,
|
||||
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)})
|
||||
}
|
||||
// 删除share notebook
|
||||
func (this *ShareService) DeleteShareNotebook(notebookId string, userId, toUserId string) bool {
|
||||
return db.DeleteAll(db.ShareNotebooks,
|
||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)})
|
||||
}
|
||||
|
||||
// 删除userId分享给toUserId的所有
|
||||
func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string) bool {
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(toUserId)}
|
||||
db.DeleteAll(db.ShareNotebooks, query);
|
||||
db.DeleteAll(db.ShareNotes, query);
|
||||
db.DeleteAll(db.HasShareNotes, query);
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "time"
|
||||
// "sort"
|
||||
)
|
||||
|
||||
type SuggestionService struct {
|
||||
}
|
||||
|
||||
// 得到某博客具体信息
|
||||
func (this *SuggestionService) AddSuggestion(suggestion info.Suggestion) bool {
|
||||
if suggestion.Id == "" {
|
||||
suggestion.Id = bson.NewObjectId()
|
||||
}
|
||||
return db.Insert(db.Suggestions, suggestion)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "time"
|
||||
)
|
||||
|
||||
/*
|
||||
每添加,更新note时, 都将tag添加到tags表中
|
||||
*/
|
||||
type TagService struct {
|
||||
}
|
||||
|
||||
func (this *TagService) GetTags(userId string) []string {
|
||||
tag := info.Tag{}
|
||||
db.Get(db.Tags, userId, &tag)
|
||||
LogJ(tag)
|
||||
return tag.Tags
|
||||
}
|
||||
|
||||
func (this *TagService) AddTagsI(userId string, tags interface{}) bool {
|
||||
if ts, ok2 := tags.([]string); ok2 {
|
||||
return this.AddTags(userId, ts)
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (this *TagService) AddTags(userId string, tags []string) bool {
|
||||
for _, tag := range tags {
|
||||
if !db.Upsert(db.Tags,
|
||||
bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||
bson.M{"$addToSet": bson.M{"Tags": tag}}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"time"
|
||||
)
|
||||
|
||||
// token
|
||||
// 找回密码
|
||||
// 修改密码
|
||||
|
||||
type TokenService struct {
|
||||
}
|
||||
|
||||
// 生成token
|
||||
func (this *TokenService) NewToken(userId string, email string, tokenType int) string {
|
||||
token := info.Token{UserId: bson.ObjectIdHex(userId), Token: NewGuidWith(email), CreatedTime: time.Now(), Email: email, Type: tokenType}
|
||||
|
||||
if db.Upsert(db.Tokens, bson.M{"_id": token.UserId}, token) {
|
||||
return token.Token
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// 删除token
|
||||
func (this *TokenService) DeleteToken(userId string, tokenType int) bool {
|
||||
return db.Delete(db.Tokens, bson.M{"_id": bson.ObjectIdHex(userId), "Type": tokenType})
|
||||
}
|
||||
|
||||
func (this *TokenService) GetOverHours(tokenType int) float64 {
|
||||
if tokenType == info.TokenPwd {
|
||||
return info.PwdOverHours
|
||||
} else if tokenType == info.TokenUpdateEmail {
|
||||
return info.UpdateEmailOverHours
|
||||
} else {
|
||||
return info.ActiveEmailOverHours
|
||||
}
|
||||
}
|
||||
|
||||
// 验证token, 是否存在, 过时?
|
||||
func (this *TokenService) VerifyToken(token string, tokenType int) (ok bool, msg string, tokenInfo info.Token) {
|
||||
overHours = this.GetOverHours(tokenType)
|
||||
|
||||
ok = false
|
||||
if token == "" {
|
||||
msg = "不存在"
|
||||
return
|
||||
}
|
||||
|
||||
db.GetByQ(db.Tokens, bson.M{"Token": token}, &tokenInfo)
|
||||
|
||||
if tokenInfo.UserId == "" {
|
||||
msg = "不存在"
|
||||
return
|
||||
}
|
||||
|
||||
// 验证是否过时
|
||||
now := time.Now()
|
||||
duration := now.Sub(tokenInfo.CreatedTime)
|
||||
|
||||
if duration.Hours() > overHours {
|
||||
msg = "过期"
|
||||
return
|
||||
}
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"labix.org/v2/mgo/bson"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// 回收站
|
||||
// 可以移到noteSerice中
|
||||
|
||||
// 不能删除notebook, 如果其下有notes!
|
||||
// 这样回收站里只有note
|
||||
|
||||
// 删除笔记后(或删除笔记本)后入回收站
|
||||
// 把note, notebook设个标记即可!
|
||||
// 已经在trash里的notebook, note不能是共享!, 所以要删除共享
|
||||
|
||||
type TrashService struct {
|
||||
}
|
||||
|
||||
//---------------------
|
||||
|
||||
// 删除note
|
||||
// 应该放在回收站里
|
||||
// 有trashService
|
||||
func (this *TrashService) DeleteNote(noteId, userId string) bool {
|
||||
// 首先删除其共享
|
||||
if shareService.DeleteShareNoteAll(noteId, userId) {
|
||||
// 更新note isTrash = true
|
||||
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}})
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除别人共享给我的笔记
|
||||
// 先判断我是否有权限, 笔记是否是我创建的
|
||||
func (this *TrashService) DeleteSharedNote(noteId, userId, myUserId string) bool {
|
||||
note := noteService.GetNote(noteId, userId)
|
||||
if shareService.HasUpdatePerm(userId, myUserId, noteId) && note.CreatedUserId.Hex() == myUserId {
|
||||
return db.UpdateByIdAndUserId(db.Notes, noteId, userId, bson.M{"$set": bson.M{"IsTrash": true}})
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// recover
|
||||
func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
|
||||
re := db.UpdateByIdAndUserId(db.Notes, noteId, userId,
|
||||
bson.M{"$set": bson.M{"IsTrash": false,
|
||||
"NotebookId": bson.ObjectIdHex(notebookId)}})
|
||||
return re;
|
||||
}
|
||||
|
||||
// 删除trash
|
||||
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
|
||||
return db.DeleteByIdAndUserId(db.Notes, noteId, userId)
|
||||
}
|
||||
|
||||
// 列出note, 排序规则, 还有分页
|
||||
// CreatedTime, UpdatedTime, title 来排序
|
||||
func (this *TrashService) ListNotes(userId string,
|
||||
pageNumber, pageSize int, sortField string, isAsc bool) (notes []info.Note) {
|
||||
_, notes = noteService.ListNotes(userId, "", true, pageNumber, pageSize, sortField, isAsc, false)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"time"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
}
|
||||
|
||||
|
||||
// 添加用户
|
||||
func (this *UserService) AddUser(user info.User) bool {
|
||||
if user.UserId == "" {
|
||||
user.UserId = bson.NewObjectId()
|
||||
}
|
||||
user.CreatedTime = time.Now()
|
||||
|
||||
if user.Email != "" {
|
||||
user.Email = strings.ToLower(user.Email)
|
||||
|
||||
// 发送验证邮箱
|
||||
go func() {
|
||||
this.RegisterSendActiveEmail(user.UserId.Hex(), user.Email)
|
||||
}();
|
||||
}
|
||||
|
||||
return db.Insert(db.Users, user)
|
||||
}
|
||||
|
||||
// 通过email得到userId
|
||||
func (this *UserService) GetUserId(email string) string {
|
||||
email = strings.ToLower(email)
|
||||
user := info.User{}
|
||||
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
||||
return user.UserId.Hex()
|
||||
}
|
||||
|
||||
// 是否存在该用户 email
|
||||
func (this *UserService) IsExistsUser(email string) bool {
|
||||
if this.GetUserId(email) == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 是否存在该用户 username
|
||||
func (this *UserService) IsExistsUserByUsername(username string) bool {
|
||||
return db.Count(db.Users, bson.M{"Username": username}) >= 1
|
||||
}
|
||||
|
||||
// 得到用户信息, userId, username, email
|
||||
func (this *UserService) GetUserInfoByAny(idEmailUsername string) info.User {
|
||||
if IsObjectId(idEmailUsername) {
|
||||
return this.GetUserInfo(idEmailUsername)
|
||||
}
|
||||
|
||||
if strings.Contains(idEmailUsername, "@") {
|
||||
return this.GetUserInfoByEmail(idEmailUsername)
|
||||
}
|
||||
|
||||
return this.GetUserInfoByUsername(idEmailUsername)
|
||||
}
|
||||
|
||||
// 得到用户信息 userId
|
||||
func (this *UserService) GetUserInfo(userId string) info.User {
|
||||
user := info.User{}
|
||||
db.Get(db.Users, userId, &user)
|
||||
return user
|
||||
}
|
||||
// 得到用户信息 email
|
||||
func (this *UserService) GetUserInfoByEmail(email string) info.User {
|
||||
user := info.User{}
|
||||
db.GetByQ(db.Users, bson.M{"Email": email}, &user)
|
||||
return user
|
||||
}
|
||||
// 得到用户信息 username
|
||||
func (this *UserService) GetUserInfoByUsername(username string) info.User {
|
||||
user := info.User{}
|
||||
db.GetByQ(db.Users, bson.M{"Username": username}, &user)
|
||||
return user
|
||||
}
|
||||
|
||||
func (this *UserService) GetUserInfoByThirdUserId(thirdUserId string) info.User {
|
||||
user := info.User{}
|
||||
db.GetByQ(db.Users, bson.M{"ThirdUserId": thirdUserId}, &user)
|
||||
return user
|
||||
}
|
||||
func (this *UserService) ListUserInfosByUserIds(userIds []bson.ObjectId) []info.User {
|
||||
users := []info.User{}
|
||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||
return users
|
||||
}
|
||||
|
||||
// 通过ids得到users, 按id的顺序组织users
|
||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||
users := []info.User{}
|
||||
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users);
|
||||
|
||||
usersMap := map[bson.ObjectId]info.User{}
|
||||
for _, user := range users {
|
||||
usersMap[user.UserId] = user
|
||||
}
|
||||
|
||||
users2 := []info.User{};
|
||||
for _, userId := range userIds {
|
||||
if user, ok := usersMap[userId]; ok {
|
||||
users2 = append(users2, user)
|
||||
}
|
||||
}
|
||||
return users2
|
||||
}
|
||||
|
||||
// 使用email(username), pwd得到用户信息
|
||||
func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.User {
|
||||
emailOrUsername = strings.ToLower(emailOrUsername)
|
||||
|
||||
user := info.User{}
|
||||
if strings.Contains(emailOrUsername, "@") {
|
||||
db.GetByQ(db.Users, bson.M{"Email": emailOrUsername, "Pwd": md5Pwd}, &user)
|
||||
} else {
|
||||
db.GetByQ(db.Users, bson.M{"Username": emailOrUsername, "Pwd": md5Pwd}, &user)
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
// 更新username
|
||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||
if userId == "" || username == "" {
|
||||
return false, "用户已存在"
|
||||
}
|
||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||
username = strings.ToLower(username)
|
||||
|
||||
// 先判断是否存在
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
||||
return false, "用户已存在"
|
||||
}
|
||||
|
||||
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
//----------------------
|
||||
// 已经登录了的用户修改密码
|
||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||
userInfo := this.GetUserInfo(userId)
|
||||
if userInfo.Pwd != Md5(oldPwd) {
|
||||
return false, "旧密码错误"
|
||||
}
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
// 修改主题
|
||||
func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
||||
return ok
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 修改email
|
||||
|
||||
// 发送激活邮件
|
||||
|
||||
// AddUser调用
|
||||
// 可以使用一个goroutine
|
||||
func (this *UserService) RegisterSendActiveEmail(userId string, email string) bool {
|
||||
token := tokenService.NewToken(userId, email, info.TokenActiveEmail)
|
||||
|
||||
if token == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://leanote.com/user/activeEmail?token=" + token
|
||||
body := fmt.Sprintf("请点击链接验证邮箱: <a href='%v'>%v</a>. %v小时后过期.", url, url, tokenService.GetOverHours(info.TokenActiveEmail));
|
||||
if !SendEmail(email, "leanote-验证邮箱", "验证邮箱", body) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 发送给我 life@leanote.com
|
||||
SendEmail("life@leanote.com", "新增用户", "新增用户", "用户名" + email);
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 修改邮箱
|
||||
func (this *UserService) UpdateEmailSendActiveEmail(userId, email string) (ok bool, msg string) {
|
||||
// 先验证该email是否被注册了
|
||||
if userService.IsExistsUser(email) {
|
||||
ok = false
|
||||
msg = "该邮箱已注册"
|
||||
return
|
||||
}
|
||||
|
||||
token := tokenService.NewToken(userId, email, info.TokenUpdateEmail)
|
||||
|
||||
if token == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
url := "http://115.28.133.226/user/updateEmail?token=" + token
|
||||
body := "邮箱验证后您的登录邮箱为: <b>" + email + "</b><br />";
|
||||
body += fmt.Sprintf("请点击链接验证邮箱: <a href='%v'>%v</a>. %v小时后过期.", url, url, tokenService.GetOverHours(info.TokenUpdateEmail));
|
||||
if !SendEmail(email, "leanote-验证邮箱", "验证邮箱", body) {
|
||||
msg = "发送失败"
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// 注册后验证邮箱
|
||||
func (this *UserService) ActiveEmail(token string) (ok bool, msg, email string) {
|
||||
tokenInfo := info.Token{}
|
||||
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenActiveEmail); ok {
|
||||
// 修改之后的邮箱
|
||||
email = tokenInfo.Email
|
||||
userInfo := this.GetUserInfoByEmail(email)
|
||||
if userInfo.UserId == "" {
|
||||
ok = false
|
||||
msg = "不存在该用户"
|
||||
return
|
||||
}
|
||||
|
||||
// 修改之, 并将verified = true
|
||||
ok = db.UpdateByQMap(db.Users, bson.M{"_id": userInfo.UserId}, bson.M{"Verified": true})
|
||||
return
|
||||
}
|
||||
|
||||
ok = false
|
||||
msg = "该链接已过期"
|
||||
return
|
||||
}
|
||||
|
||||
// 修改邮箱
|
||||
// 在此之前, 验证token是否过期
|
||||
// 验证email是否有人注册了
|
||||
func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string) {
|
||||
tokenInfo := info.Token{}
|
||||
if ok, msg, tokenInfo = tokenService.VerifyToken(token, info.TokenUpdateEmail); ok {
|
||||
// 修改之后的邮箱
|
||||
email = tokenInfo.Email
|
||||
// 先验证该email是否被注册了
|
||||
if userService.IsExistsUser(email) {
|
||||
ok = false
|
||||
msg = "该邮箱已注册"
|
||||
return
|
||||
}
|
||||
|
||||
// 修改之, 并将verified = true
|
||||
ok = db.UpdateByQMap(db.Users, bson.M{"_id": tokenInfo.UserId}, bson.M{"Email": email, "Verified": true})
|
||||
return
|
||||
}
|
||||
|
||||
ok = false
|
||||
msg = "该链接已过期"
|
||||
return
|
||||
}
|
||||
|
||||
//---------
|
||||
// 第三方添加账号
|
||||
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
||||
// 判断email是否存在
|
||||
if this.IsExistsUser(email) {
|
||||
msg = "该用户已存在"
|
||||
return
|
||||
}
|
||||
|
||||
ok = db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"Email": email, "Pwd": Md5(pwd)})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//------------
|
||||
// 偏好设置
|
||||
|
||||
// 宽度
|
||||
func (this *UserService)UpdateColumnWidth(userId string, notebookWidth, noteListWidth int) bool {
|
||||
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"NotebookWidth": notebookWidth, "NoteListWidth": noteListWidth})
|
||||
}
|
||||
// 左侧是否隐藏
|
||||
func (this *UserService)UpdateLeftIsMin(userId string, leftIsMin bool) bool {
|
||||
return db.UpdateByQMap(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, bson.M{"LeftIsMin": leftIsMin})
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
)
|
||||
|
||||
// service 通用方法
|
||||
|
||||
// 分页, 排序处理
|
||||
func parsePageAndSort(pageNumber, pageSize int, sortField string, isAsc bool) (skipNum int, sortFieldR string) {
|
||||
skipNum = (pageNumber - 1) * pageSize
|
||||
if sortField == "" {
|
||||
sortField = "UpdatedTime"
|
||||
}
|
||||
if !isAsc {
|
||||
sortFieldR = "-" + sortField
|
||||
} else {
|
||||
sortFieldR = sortField
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
|
||||
)
|
||||
|
||||
// init service, for share service bettween services
|
||||
// 初始化, 实例service
|
||||
// 为了共享service
|
||||
|
||||
var notebookService *NotebookService
|
||||
var noteService *NoteService
|
||||
var noteContentHistoryService *NoteContentHistoryService
|
||||
var trashService *TrashService
|
||||
var shareService *ShareService
|
||||
var userService *UserService
|
||||
var tagService *TagService
|
||||
var blogService *BlogService
|
||||
var tokenService *TokenService
|
||||
|
||||
func init() {
|
||||
notebookService = &NotebookService{}
|
||||
noteService = &NoteService{}
|
||||
noteContentHistoryService = &NoteContentHistoryService{}
|
||||
trashService = &TrashService{}
|
||||
shareService = &ShareService{}
|
||||
userService = &UserService{}
|
||||
tagService = &TagService{}
|
||||
blogService = &BlogService{}
|
||||
tokenService = &TokenService{}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/robfig/revel"
|
||||
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "github.com/leanote/leanote/app/lea/memcache"
|
||||
// "github.com/leanote/leanote/app/lea/netutil"
|
||||
"github.com/leanote/leanote/app/lea/html2image"
|
||||
"time"
|
||||
"fmt"
|
||||
"labix.org/v2/mgo/bson"
|
||||
// "labix.org/v2/mgo"
|
||||
// "encoding/json"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
var userId = "5295d4c95b1dd58edb4a7f4f"
|
||||
var userIdO = bson.ObjectIdHex(userId)
|
||||
|
||||
var userId3 = "52b43ae4cfeeae33ef073b2b"
|
||||
var userId3O = bson.ObjectIdHex(userId3)
|
||||
|
||||
var toUserId = "52b4376bcfeeae33ef073b21"
|
||||
var toUserIdO = bson.ObjectIdHex(toUserId)
|
||||
|
||||
var notebookId = "52b2d051ea3ba3d3fb35910c"
|
||||
var notebookIdO = bson.ObjectIdHex(notebookId)
|
||||
var notebookId2O = bson.ObjectIdHex("52b2d051ea3ba3d3fb35910b")
|
||||
|
||||
var noteId = "52b2dd34ea3ba3d3fb35910d"
|
||||
var noteIdO = bson.ObjectIdHex(noteId)
|
||||
|
||||
func testNoteService() {
|
||||
println("testNoteService")
|
||||
noteService := &service.NoteService{}
|
||||
note := noteService.GetBlogNote("535f9e6b19807a4c8d000000")
|
||||
LogJ(note)
|
||||
/*
|
||||
_, notes := noteService.SearchNote("go", "52d3e8ac99c37b7f0d000001", 1, 30, "", false, true);
|
||||
LogJ(notes)
|
||||
*/
|
||||
return;
|
||||
|
||||
/*
|
||||
noteService.AddNote(info.Note{UserId: userIdO,
|
||||
NotebookId: notebookIdO,
|
||||
Title: "life you", Tags: []string{"red", "yellow"}})
|
||||
*/
|
||||
|
||||
noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||
NoteId: bson.ObjectIdHex("52b4531dcfeeae33ef073b33"),
|
||||
Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||
|
||||
// noteService.UpdateNoteContent(userId, userId, "52b2dd34ea3ba3d3fb35910d", "life2---------")
|
||||
|
||||
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||
|
||||
// println(bson.IsObjectIdHex(id))
|
||||
|
||||
// note := noteService.Get(id)
|
||||
// fmt.Println(note)
|
||||
|
||||
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||
}
|
||||
|
||||
func testNotebookService() {
|
||||
service := &service.NotebookService{}
|
||||
Log(service.IsBlog("52ccb959bcbf21610d000001"))
|
||||
|
||||
return;
|
||||
|
||||
notebooks := service.GetNotebooks(userId3)
|
||||
LogJ(notebooks)
|
||||
|
||||
// b, _ := json.MarshalIndent(notebooks, "", " ")
|
||||
// fmt.Println(string(b))
|
||||
|
||||
// service.UpdateNotebookTitle("52b2cf9eea3ba3d3fb359108", userId, "JS")
|
||||
|
||||
// service.SortNotebooks(userId, map[string]int{"52b2d051ea3ba3d3fb35910c": 4, "52b2d051ea3ba3d3fb35910b": 3})
|
||||
|
||||
/*
|
||||
service.AddNotebook(info.Notebook{UserId: userId3O,
|
||||
ParentNotebookId: bson.ObjectIdHex("52b43c1fcfeeae33ef073b2e"),
|
||||
Title: "Mac-life",
|
||||
Seq: 0})
|
||||
*/
|
||||
|
||||
println("xxx")
|
||||
}
|
||||
|
||||
func testShareService() {
|
||||
service := &service.ShareService{}
|
||||
|
||||
// service.AddShareNote("52bd127dbcbf216d0b000000", 1, "5295d4c95b1dd58edb4a7f4f", "c@a.com")
|
||||
LogJ(service.ListNoteShareUserInfo("52cd11a1bcbf215680000000", "5295d4c95b1dd58edb4a7f4f"))
|
||||
return;
|
||||
|
||||
/*
|
||||
service.AddShareNotebook(info.ShareNotebook{UserId: userId3O, ToUserId: userIdO,
|
||||
NotebookId: bson.ObjectIdHex("52b43c38cfeeae33ef073b30")})
|
||||
*/
|
||||
|
||||
notebooks,_ := service.GetShareNotebooks(userId)
|
||||
LogJ(notebooks)
|
||||
|
||||
// noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||
// NoteId: bson.ObjectIdHex("52b2dd34ea3ba3d3fb35910d"), Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||
|
||||
|
||||
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||
|
||||
// println(bson.IsObjectIdHex(id))
|
||||
|
||||
// note := noteService.Get(id)
|
||||
// fmt.Println(note)
|
||||
|
||||
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||
}
|
||||
|
||||
|
||||
func testAuthService() {
|
||||
userService := &service.UserService{}
|
||||
LogJ(userService.GetUserInfo("52d26b4e99c37b609a000001"))
|
||||
// userService.AddUser(info.User{UserId: bson.ObjectIdHex("52d26b4e99c37b609a000001"), Email: "leanote@leanote.com", Pwd:"abc"})
|
||||
return;
|
||||
|
||||
authService := &service.AuthService{}
|
||||
authService.Register("f@a.com", "abc")
|
||||
|
||||
// fmt.Println(authService.LogonGetUserInfo("a@a.com", "abc"))
|
||||
|
||||
// noteService.AddNoteContent(info.NoteContent{UserId: userIdO,
|
||||
// NoteId: bson.ObjectIdHex("52b2dd34ea3ba3d3fb35910d"), Content:"xxxxxxxxxxxxxxxxxxxxlifeyou can m<div><p></p></div>"})
|
||||
|
||||
// noteService.AddNote(info.Note{Title: "life", Tags: []string{"life", "life2"}})
|
||||
|
||||
// println(bson.IsObjectIdHex(id))
|
||||
|
||||
// note := noteService.Get(id)
|
||||
// fmt.Println(note)
|
||||
|
||||
// noteService.UpdateTags(id, []string{"lifedd", "life2"});
|
||||
}
|
||||
|
||||
func testTagService() {
|
||||
service := &service.TagService{}
|
||||
// service.AddTags("5295d4c95b1dd58edb4a7f4f", []string{"life", "blue", "yellow"})
|
||||
// service.AddTags("5295d4c95b1dd58edb4a7f4f", []string{"what", "can", "make"})
|
||||
LogJ(service.GetTags("5295d4c95b1dd58edb4a7f4f"))
|
||||
}
|
||||
|
||||
func testHtml2Image() {
|
||||
start := time.Now()
|
||||
Log("start...")
|
||||
// TestFillString()
|
||||
|
||||
|
||||
html2image.ToImage("uid", "username", "noteId", "开发一款属于自己的编程语言,开发一款属于自己的编程语言听起来是不是很酷?", `
|
||||
<div class="each-post">
|
||||
<p>
|
||||
一个合格的 Techspace 需要有足够专业的器材、场地和资源,你可以和你的团队在里面进行激光切割、快速贴片甚至加工木材等操作,在相对独立的空间内又能同周围的同道友人互相激发切磋。国内现有的 Techspace 没几家,不久前我去深圳特地拜访了当地的 Techspace,很喜欢那里的氛围,希望国内其他地方也能有更多这类空间供创客发挥。
|
||||
假如你有一个比较成型的想法,想在硬件领域做点事情,核心团队也基本组好,硬件软件交互基本都有专人了。</p>
|
||||
<p><a>这时候你的首要目标</a>,就是找个地方,按照你的计划,尽早做出一个可用的原型。Techspace可能是一个合适的地方。
|
||||
一个合格的 Techspace 需要有足够专业的器材、场地和资源,你可以和你的团队在里面进行激光切割、快速贴片甚至加工木材等操作,在相对独立的空间内又能同周围的同道友人互相激发切磋。国内现有的 Techspace 没几家,不久前我去深圳特地拜访了当地的 Techspace,很喜欢那里的氛围,希望国内其他地方也能有更多这类空间供创客发挥。
|
||||
深圳 Techspace 位于工业区,园区内有奥迪、BMW 等企业的厂房,在大门口我停下来问保安,M10 栋在哪里?保安答,去 Techspace?最里面靠右手那栋。惊叹于保安的机智,我也在想,莫非有许多朋友都慕名来到这巨大园区寻访 Techspace?
|
||||
穿过一片工业区里的高楼和各种建筑材料
|
||||
</p>
|
||||
<!--
|
||||
<pre class="">cd jpeg-9a/<br>./configure --enable-shared --enable-static
|
||||
make<br>make --- install</pre>
|
||||
<p>
|
||||
life you can, !!@kk
|
||||
</p>
|
||||
|
||||
-->
|
||||
</div>
|
||||
`, "/Users/life/Desktop/a.png")
|
||||
fmt.Printf("time cost %v\n", time.Now().Sub(start))
|
||||
}
|
||||
func main() {
|
||||
revel.BasePath = "/Users/life/Documents/Go/package/src/leanote"
|
||||
// a, b := SplitFilename("http://ab/c/a.gif#??")
|
||||
// println(a)
|
||||
// println(b)
|
||||
|
||||
// path, ok := netutil.WriteUrl("http://a.36krcnd.com/photo/2014/9bd1a07c0973d79ca05ad13c3c2e16b8.png!slider", "/tmp")
|
||||
// println(path)
|
||||
// testHtml2Image();
|
||||
|
||||
// println(IsObjectId("52d26b4e99c37b609a000001"))
|
||||
|
||||
// b := `请点击链接验证邮箱: <a href="">http://leanote.com/user/activeEmail?token=d8ca086cce5550a6227f9dc84dbac09d</a>. 48小时后过期.`
|
||||
// SendEmail("lifephp@gmail.com", "leanote-验证邮箱", "验证邮", b)
|
||||
|
||||
//_, err := mgo.Dial("mongodb://leanote:nKFAkxKnWkEQy8Vv2LlM@115.28.133.226:27017/leanote")
|
||||
|
||||
// testNotebookService();
|
||||
testNoteService();
|
||||
// testShareService()
|
||||
// testAuthService()
|
||||
|
||||
// testTagService();
|
||||
/*
|
||||
filename := "你好59.26.png"
|
||||
ext := SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||
ext = strings.ToLower(ext)
|
||||
print(ext)
|
||||
52d26ab199c37b5f80000001
|
||||
|
||||
Log(bson.NewObjectId())
|
||||
Log(bson.NewObjectId())
|
||||
Log(bson.NewObjectId())
|
||||
|
||||
*/
|
||||
// Log(TransferExt("/你好a/b/a.gif", ".jpg"))
|
||||
// TransToGif("/Users/life/Desktop/a2.png", 0, false)
|
||||
|
||||
// Log(IsUsername("xx**x"))
|
||||
|
||||
/*
|
||||
memcache.Set("xx", map[string]string{"A":"you"}, 0)
|
||||
a := memcache.Get("xx")
|
||||
Log(a)
|
||||
*/
|
||||
}
|
||||
+751
@@ -0,0 +1,751 @@
|
||||
// GENERATED CODE - DO NOT EDIT
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"reflect"
|
||||
"github.com/revel/revel"
|
||||
_ "github.com/leanote/leanote/app"
|
||||
controllers "github.com/leanote/leanote/app/controllers"
|
||||
_ "github.com/leanote/leanote/app/db"
|
||||
info "github.com/leanote/leanote/app/info"
|
||||
_ "github.com/leanote/leanote/app/lea/binder"
|
||||
_ "github.com/leanote/leanote/app/lea/memcache"
|
||||
_ "github.com/leanote/leanote/app/service"
|
||||
controllers1 "github.com/revel/revel/modules/static/app/controllers"
|
||||
_ "github.com/revel/revel/modules/testrunner/app"
|
||||
controllers0 "github.com/revel/revel/modules/testrunner/app/controllers"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
revel.RegisterController((*controllers.BaseController)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "E404",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers0.TestRunner)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
46: []string{
|
||||
"testSuites",
|
||||
},
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Run",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "suite", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "test", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
69: []string{
|
||||
"error",
|
||||
},
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "List",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers1.Static)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Serve",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ServeModule",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "moduleName", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.File)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "UploadImage",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "renderHtml", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UploadBlogLogo",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UploadImageJson",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "renderHtml", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Notebook)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebook", Type: reflect.TypeOf((*info.Notebook)(nil)) },
|
||||
&revel.MethodArg{Name: "i", Type: reflect.TypeOf((*int)(nil)) },
|
||||
&revel.MethodArg{Name: "name", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteNotebook",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "AddNotebook",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "title", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateNotebookTitle",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "title", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.NoteContentHistory)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "ListHistories",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Note)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ListNotes",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ListTrashNotes",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "GetNoteContent",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateNoteOrContent",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteOrContent", Type: reflect.TypeOf((*controllers.NoteOrContent)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "userId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "isShared", Type: reflect.TypeOf((*bool)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteTrash",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "MoveNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "CopyNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "CopySharedNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "fromUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SearchNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "key", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SearchNoteByTags",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "tags", Type: reflect.TypeOf((*[]string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Html2Image",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Share)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "AddShareNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "emails", Type: reflect.TypeOf((*[]string)(nil)) },
|
||||
&revel.MethodArg{Name: "perm", Type: reflect.TypeOf((*int)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "AddShareNotebook",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "emails", Type: reflect.TypeOf((*[]string)(nil)) },
|
||||
&revel.MethodArg{Name: "perm", Type: reflect.TypeOf((*int)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ListShareNotes",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "userId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "GetShareNoteContent",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "sharedUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ListNoteShareUserInfo",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ListNotebookShareUserInfo",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateShareNotePerm",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "perm", Type: reflect.TypeOf((*int)(nil)) },
|
||||
&revel.MethodArg{Name: "toUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateShareNotebookPerm",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "perm", Type: reflect.TypeOf((*int)(nil)) },
|
||||
&revel.MethodArg{Name: "toUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteShareNote",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "toUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteShareNotebook",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "toUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteShareNoteBySharedUser",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "fromUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteShareNotebookBySharedUser",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "fromUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DeleteUserShareNoteAndNotebook",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "fromUserId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.User)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "UpdateUsername",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "username", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdatePwd",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "oldPwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "pwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateTheme",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "theme", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SendRegisterEmail",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "content", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "toEmail", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ReSendActiveEmail",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateEmailSendActiveEmail",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateEmail",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "token", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "ActiveEmail",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "token", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "AddAccount",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "pwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateColumnWidth",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookWidth", Type: reflect.TypeOf((*int)(nil)) },
|
||||
&revel.MethodArg{Name: "noteListWidth", Type: reflect.TypeOf((*int)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "UpdateLeftIsMin",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "leftIsMin", Type: reflect.TypeOf((*bool)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Auth)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Login",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DoLogin",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "pwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Logout",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Demo",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Register",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DoRegister",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "pwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "FindPassword",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "DoFindPassword",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "email", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "FindPassword2",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "token", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "FindPasswordUpdate",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "token", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "pwd", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Blog)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "SetNote2Blog",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "isBlog", Type: reflect.TypeOf((*bool)(nil)) },
|
||||
&revel.MethodArg{Name: "isTop", Type: reflect.TypeOf((*bool)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SetNotebook2Blog",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "isBlog", Type: reflect.TypeOf((*bool)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "notebookId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "View",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "noteId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SearchBlog",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "key", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Set",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SetUserBlogBase",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userBlog", Type: reflect.TypeOf((*info.UserBlogBase)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SetUserBlogComment",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userBlog", Type: reflect.TypeOf((*info.UserBlogComment)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "SetUserBlogStyle",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userBlog", Type: reflect.TypeOf((*info.UserBlogStyle)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "AboutMe",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "userId", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Index)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Suggestion",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "addr", Type: reflect.TypeOf((*string)(nil)) },
|
||||
&revel.MethodArg{Name: "suggestion", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Mobile)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "Index",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
&revel.MethodType{
|
||||
Name: "Logout",
|
||||
Args: []*revel.MethodArg{
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.RegisterController((*controllers.Oauth)(nil),
|
||||
[]*revel.MethodType{
|
||||
&revel.MethodType{
|
||||
Name: "GithubCallback",
|
||||
Args: []*revel.MethodArg{
|
||||
&revel.MethodArg{Name: "code", Type: reflect.TypeOf((*string)(nil)) },
|
||||
},
|
||||
RenderArgNames: map[int][]string{
|
||||
},
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
revel.DefaultValidationKeys = map[string]map[int]string{
|
||||
}
|
||||
revel.TestSuites = []interface{}{
|
||||
}
|
||||
|
||||
revel.Run(*port)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{{set . "title" "Home"}}
|
||||
{{template "header.html" .}}
|
||||
|
||||
<header class="hero-unit" style="background-color:#A9F16C">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="hero-text">
|
||||
<h1>It works!</h1>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
{{template "flash.html" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer.html" .}}
|
||||
@@ -0,0 +1,21 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
关于我
|
||||
</div>
|
||||
<div class="created-time">
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{.userBlog.AboutMe | raw}}
|
||||
</div>
|
||||
|
||||
<!-- comment -->
|
||||
{{template "blog/comment.html" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "Blog/footer.html" .}}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{if .userBlog.CanComment}}
|
||||
<div id="disqus_thread"></div>
|
||||
<!-- comment -->
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||
var disqus_shortname = '{{.userBlog.DisqusId}}'; // required: replace example with your forum shortname
|
||||
var disqus_identifier = '{{.userBlog.UserId.Hex}}/{{.blog.NoteId.Hex}}/{{.blog.Title}}'; // 博客链接
|
||||
|
||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
|
||||
{{end}}
|
||||
@@ -0,0 +1,62 @@
|
||||
<div id="footerContainer">
|
||||
{{$userId := .userBlog.UserId.Hex}}
|
||||
<div class="container" id="footer">
|
||||
<div class="col-md-4">
|
||||
<h3>导航</h3>
|
||||
<ul>
|
||||
<li><a href="/blog/{{$userId}}">首页</a></li>
|
||||
{{range .notebooks}}
|
||||
<li>
|
||||
<a href="/blog/{{$userId}}/{{.NotebookId.Hex}}">{{.Title}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li><a href="/blog/aboutMe/{{$userId}}">关于我</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h3>最近发表</h3>
|
||||
<ul>
|
||||
{{range .recentBlogs}}
|
||||
<li title="{{.Title}}"><a href="/blog/view/{{.NoteId.Hex}}/">{{.Title}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h3>快速链接</h3>
|
||||
<ul>
|
||||
<li><a href="/note">我的笔记</a></li>
|
||||
<li><a href="/login">登录</a></li>
|
||||
<li><a href="http://leanote.com" target="_blank">leanote</a></li>
|
||||
<li><a href="https://github.com/leanote/leanote" target="_blank">leanote github</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap-min.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
/*
|
||||
$("#searchInput").click(function() {
|
||||
$("#search").width("130px");
|
||||
$("#searchInput").width("100px");
|
||||
});
|
||||
$("#searchInput").blur(function() {
|
||||
$("#search").width(0);
|
||||
$("#searchInput").width(0);
|
||||
});
|
||||
*/
|
||||
});
|
||||
// 搜索
|
||||
function search(e) {
|
||||
var key = $("#searchInput").val();
|
||||
if(!key) {
|
||||
location.href = "/blog/" + UserInfo.Username;
|
||||
} else {
|
||||
var tpl = '<form action="/blog/searchBlog/' + UserInfo.Username +'" method="get">';
|
||||
tpl += '<input name="key" value="' + key + '" />';
|
||||
tpl += "</form";
|
||||
$(tpl).submit();
|
||||
}
|
||||
}␍</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="author" content="leanote">
|
||||
|
||||
<title>{{.title}}</title>
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link id="styleLink" href="/css/blog/{{if .userBlog.Style}}{{.userBlog.Style}}{{else}}blog_default{{end}}.css" rel="stylesheet">
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="headerAndNav" >
|
||||
<div id="headerContainer" class="container">
|
||||
<!-- 头部可放博客名, 导航 -->
|
||||
<div id="header">
|
||||
{{$userId := .userBlog.UserId.Hex}} <!-- 可不要了 -->
|
||||
{{$username := .userInfo.Username}}
|
||||
<h1>
|
||||
<a href="/blog/{{$username}}" id="logo">
|
||||
{{if .userBlog.Logo}}
|
||||
<img src="{{.userBlog.Logo}}" title="{{.userBlog.Title}}"/>
|
||||
{{else}}
|
||||
{{.userBlog.Title | raw}}
|
||||
{{end}}
|
||||
</a>
|
||||
</h1>
|
||||
<div id="blogDesc">
|
||||
{{.userBlog.SubTitle | raw}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Static navbar -->
|
||||
<div class="navbar navbar-default">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
{{$navNotebookId := .notebookId}}
|
||||
<li class="{{if .index}}active{{end}}"><a href="/blog/{{$username}}">首页</a></li>
|
||||
{{range .notebooks}}
|
||||
{{$notebookId := .NotebookId.Hex}}
|
||||
<li class="{{if eq $navNotebookId $notebookId}}active{{else}}{{end}}">
|
||||
<a href="/blog/{{$username}}/{{$notebookId}}"
|
||||
>{{.Title}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li class="{{if .aboutMe}}active{{end}}"><a href="/blog/aboutMe/{{$username}}">关于我</a></li>
|
||||
{{if .isMe}}
|
||||
<li class="{{if .set}}active{{end}}"><a href="/blog/set" >博客设置</a></li>
|
||||
<li><a href="/note" >{{msg . "myNote"}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
<form class="navbar-form navbar-right" id="search" onsubmit="search(event);return false;">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="searchIcon" onclick="search(event);"><i class="fa fa-search"></i></span>
|
||||
<input type="text" placeholder="search" id="searchInput" class="form-control" value="{{.key}}">
|
||||
</div>
|
||||
</form>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var UserInfo = {UserId: "{{$userId}}", Email: "{{.userInfo.Email}}", Username: "{{.userInfo.Username}}"};
|
||||
</script>
|
||||
@@ -0,0 +1,71 @@
|
||||
<link href="/public/mdeditor/editor/google-code-prettify/prettify.css" type="text/css" rel="stylesheet">
|
||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||
|
||||
<script>
|
||||
$("pre").addClass("prettyprint linenums");
|
||||
prettyPrint();
|
||||
</script>
|
||||
|
||||
<!--
|
||||
<script type="text/javascript" src="/js/syntaxhighlighter/scripts/shCore.js"></script>
|
||||
<link href="/js/syntaxhighlighter/styles/shCore.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/js/syntaxhighlighter/styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var pathPrefix = "/js/syntaxhighlighter/scripts/";
|
||||
var map = {
|
||||
"brush: jscript": "shBrushJScript.js",
|
||||
"brush: c#": "shBrushCSharp.js",
|
||||
"brush: css": "shBrushCss.js",
|
||||
"brush: cpp": "shBrushCpp.js",
|
||||
"brush: java": "shBrushJava.js",
|
||||
"brush: xml": "shBrushXml.js",
|
||||
"brush: php": "shBrushPhp.js",
|
||||
"brush: perl": "shBrushPerl.js",
|
||||
"brush: python": "shBrushPython.js",
|
||||
"brush: ruby": "shBrushRuby.js",
|
||||
"brush: sql": "shBrushSql.js"}
|
||||
var needLoadCount = 0;
|
||||
var alreadyLoadCount = 0;
|
||||
$('pre[class]').each(function() {
|
||||
var brush = $(this).attr("class");
|
||||
var js = map[brush]
|
||||
if (js) {
|
||||
needLoadCount++;
|
||||
map[brush] = null; // 不要重复加载
|
||||
loadJS(pathPrefix + js, function () {
|
||||
alreadyLoadCount++;
|
||||
if (alreadyLoadCount == needLoadCount) {
|
||||
//setTimeout(function() {
|
||||
SyntaxHighlighter.highlight();
|
||||
//}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function loadJS(url, callback) {
|
||||
$.getScript(url, function() {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
function loadJS(url, callback, charset) {
|
||||
var script = document.createElement('script');
|
||||
script.onload = script.onreadystatechange = function () {
|
||||
if (script && script.readyState && /^(?!(?:loaded|complete)$)/.test(script.readyState)) return;
|
||||
script.onload = script.onreadystatechange = null;
|
||||
script.src = '';
|
||||
script.parentNode.removeChild(script);
|
||||
script = null;
|
||||
if (callback) callback();
|
||||
};
|
||||
script.charset = charset || document.charset || document.characterSet;
|
||||
script.src = url;
|
||||
try { document.getElementsByTagName("head")[0].appendChild(script); } catch (e) { }
|
||||
}
|
||||
*/
|
||||
</script>
|
||||
-->
|
||||
@@ -0,0 +1,44 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<div id="postsContainer">
|
||||
<div class="container">
|
||||
{{if .notebookId}}
|
||||
<h2>分类 {{.notebook.Title}}</h2>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="posts">
|
||||
{{range .blogs}}
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
<a href="/blog/view/{{.NoteId.Hex}}" title="全文">
|
||||
{{.Title}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="created-time">
|
||||
<i class="fa fa-bookmark-o" style="color: #666"></i>
|
||||
{{if .Tags}}
|
||||
{{blogTags .Tags}}
|
||||
{{else}}
|
||||
无
|
||||
{{end}}
|
||||
|
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 更新 {{.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 创建 {{.CreatedTime | datetime}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{.Content | raw}}
|
||||
</div>
|
||||
<a class="more" href="/blog/view/{{.NoteId.Hex}}" title="更多">More...</a>
|
||||
</div>
|
||||
{{end}}
|
||||
<!-- 分页 -->
|
||||
<ul class="pager">
|
||||
{{page .userInfo.Username .notebookId .page .pageSize .count}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "Blog/footer.html" .}}
|
||||
{{template "Blog/highlight.html"}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<div id="postsContainer">
|
||||
<div class="container">
|
||||
<h2>搜索 {{.key}} </h2>
|
||||
</div>
|
||||
|
||||
<div id="posts">
|
||||
{{range .blogs}}
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
<a href="/blog/view/{{.NoteId.Hex}}" title="全文">
|
||||
{{.Title}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="created-time">
|
||||
<i class="fa fa-bookmark-o" style="color: #666"></i>
|
||||
{{if .Tags}}
|
||||
{{blogTags .Tags}}
|
||||
{{else}}
|
||||
无
|
||||
{{end}}
|
||||
|
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 更新 {{.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 创建 {{.CreatedTime | datetime}}
|
||||
</div>
|
||||
<div class="desc">
|
||||
{{.Content | raw}}
|
||||
</div>
|
||||
<a class="more" href="/blog/view/{{.NoteId.Hex}}" title="更多">More...</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if not .blogs }}
|
||||
<div class="each-post">
|
||||
无
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "Blog/footer.html" .}}
|
||||
{{template "Blog/highlight.html"}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,301 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<!-- -->
|
||||
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css"
|
||||
type="text/css">
|
||||
<style>
|
||||
.tab-pane {
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<ul id="myTab" class="nav nav-tabs">
|
||||
<li class="active"><a href="#baseInfo" data-toggle="tab">基本设置</a></li>
|
||||
<li class=""><a href="#commentInfo" data-toggle="tab">评论设置</a></li>
|
||||
<li class=""><a href="#styleInfo" data-toggle="tab">主题设置</a></li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane" id="styleInfo">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="Style" class="col-sm-2 control-label">主题</label>
|
||||
<div class="col-sm-10">
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_default"
|
||||
{{if not .userBlog.Style}}
|
||||
checked="checked"
|
||||
{{else}}
|
||||
{{if eq .userBlog.Style "blog_default"}}
|
||||
checked="checked"
|
||||
{{end}}
|
||||
{{end}}>
|
||||
默认 </label>
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_daqi"
|
||||
{{if eq .userBlog.Style "blog_daqi"}}checked="checked"{{end}}>
|
||||
大气</label>
|
||||
<label><input type="radio" name="Style"
|
||||
value="blog_left_fixed"
|
||||
{{if eq .userBlog.Style "blog_left_fixed"}}checked="checked"{{end}}>
|
||||
左侧导航固定</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="commentInfo">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="subTitle" class="col-sm-2 control-label">开启评论</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="checkbox" id="CanComment" name="CanComment"
|
||||
{{if .userBlog.CanComment}}checked="checked"{{end}} >
|
||||
<br />
|
||||
leanote采用 <a href="http://disqus.com" target="_blank">Disqus</a>
|
||||
作为评论系统
|
||||
<div id="disqusSet">
|
||||
<label for="DisqusId">Disqus Id</label> <input type="text"
|
||||
class="form-control" style="display: inline; width: 50%"
|
||||
id="DisqusId" name="DisqusId"
|
||||
value="{{if .userBlog.DisqusId}}{{.userBlog.DisqusId}}{{else}}leanote{{end}}">
|
||||
<br /> (请填写您申请的Disqus唯一url前缀, 建议您申请Disqus帐号, 这样可以自己管理评论.
|
||||
或使用leanote的默认Disqus Id. <a target="_blank"
|
||||
href="/blog/view/52db8463e01c530ef8000001">需要帮助?</a>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane active" id="baseInfo">
|
||||
<div class="form-horizontal" role="form" id="userBlogForm">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<div class="alert alert-success" id="msg"
|
||||
style="display: none; margin-bottom: 3px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-sm-2 control-label">博客名称</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="Title" name="Title"
|
||||
placeholder="比如: leanote的博客"
|
||||
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 的博客{{end}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="logo" class="col-sm-2 control-label">博客Logo</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="hidden" name="Logo" id="Logo"
|
||||
value="{{.userBlog.Logo}}" />
|
||||
<form id="formLogo" action="/file/uploadBlogLogo" method="post"
|
||||
enctype="multipart/form-data" target="logoTarget"
|
||||
onsubmit="inProgress()">
|
||||
<input type="file" class="form-control" id="logo2" name="file"
|
||||
onChange='$("#formLogo").submit();' /> 上传logo将显示logo(替代博客标题)
|
||||
<div id="logoImg"
|
||||
{{if .userBlog.Logo }}
|
||||
{{else}}
|
||||
style="display: none"{{end}}
|
||||
>
|
||||
<img src="{{.userBlog.Logo}}" style="height: 40px" /> <a
|
||||
href="#" id="deleteLogo">删除</a>
|
||||
</div>
|
||||
</form>
|
||||
<iframe id="logoTarget" name="logoTarget" src="#"
|
||||
style="display: none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="subTitle" class="col-sm-2 control-label">博客描述</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="SubTitle"
|
||||
name="SubTitle" value="{{.userBlog.SubTitle}}"
|
||||
placeholder="比如: leanote, 不只是笔记">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="aboutMe" class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<div id="popularToolbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="aboutMe" class="col-sm-2 control-label">关于我</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea id="AboutMe" name="AboutMe">{{.userBlog.AboutMe}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button class="btn btn-success">保存</button>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{template "Blog/footer.html" .}}
|
||||
|
||||
<script src="/js/common-min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
tinymce.init({
|
||||
selector : "#AboutMe",
|
||||
content_css : [ "/css/bootstrap.css", "/css/editor.css" ],
|
||||
skin : "custom",
|
||||
language : "zh_CN",
|
||||
height : 300,
|
||||
width : "100%",
|
||||
plugins : [
|
||||
"advlist autolink link image lists charmap hr ",
|
||||
"searchreplace visualblocks visualchars code tabfocus",
|
||||
"table contextmenu directionality textcolor paste fullpage textcolor" ],
|
||||
|
||||
toolbar1 : "formatselect fontselect fontsizeselect | forecolor backcolor | bold italic underline strikethrough | image | bullist numlist | alignleft aligncenter alignright alignjustify",
|
||||
toolbar2 : "outdent indent blockquote | link unlink | table | hr removeformat | subscript superscript | visualchars visualblocks | searchreplace | code",
|
||||
|
||||
menubar : false,
|
||||
toolbar_items_size : 'small',
|
||||
statusbar : false,
|
||||
font_formats : "Arial=arial,helvetica,sans-serif;"
|
||||
+ "Arial Black=arial black,avant garde;"
|
||||
+ "Times New Roman=times new roman,times;"
|
||||
+ "Courier New=courier new,courier;"
|
||||
+ "Tahoma=tahoma,arial,helvetica,sans-serif;"
|
||||
+ "Verdana=verdana,geneva;" + "宋体=SimSun;"
|
||||
+ "新宋体=NSimSun;" + "黑体=SimHei;"
|
||||
+ "微软雅黑=Microsoft YaHei",
|
||||
block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p"
|
||||
});
|
||||
$("#deleteLogo").click(function() {
|
||||
$("#Logo").val("");
|
||||
$("#logoImg").hide();
|
||||
});
|
||||
|
||||
$("#CanComment").click(function() {
|
||||
if ($(this).is(":checked")) {
|
||||
$("#disqusSet").show();
|
||||
} else {
|
||||
$("#disqusSet").hide();
|
||||
}
|
||||
});
|
||||
$("#CanComment").trigger("click").trigger("click"); // 恶心的想法
|
||||
|
||||
|
||||
// 基本设置
|
||||
$("#baseInfo .btn-success").click(function() {
|
||||
var data = {
|
||||
Title : $("#Title").val(),
|
||||
SubTitle : $("#SubTitle").val(),
|
||||
Logo : $("#Logo").val(),
|
||||
AboutMe : getEditorContent()
|
||||
}
|
||||
|
||||
post("/blog/setUserBlogBase", data, function(ret) {
|
||||
showMsg2($("#baseInfo .msg"), "保存成功", 2000);
|
||||
$("#blogDesc").html(data.SubTitle);
|
||||
$("#logo").html(data.Title);
|
||||
if(data.Logo) {
|
||||
$("#logo").html(t('<img src="?" />', data.Logo));
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
// 评论
|
||||
$("#commentInfo .btn-success").click(function(e) {
|
||||
e.preventDefault();
|
||||
var data = {
|
||||
CanComment : $("#CanComment").is(":checked"),
|
||||
DisqusId : $("#DisqusId").val(),
|
||||
}
|
||||
post("/blog/setUserBlogComment", data, function(ret) {
|
||||
showMsg2($("#commentInfo .msg"), "保存成功", 2000);
|
||||
}, this);
|
||||
});
|
||||
// 主题
|
||||
$("#styleInfo .btn-success").click(function(e) {
|
||||
e.preventDefault();
|
||||
var data = {
|
||||
Style : $("input[name='Style']:checked").val()
|
||||
}
|
||||
post("/blog/setUserBlogStyle", data, function(ret) {
|
||||
showMsg2($("#styleInfo .msg"), "保存成功", 2000);
|
||||
}, this);
|
||||
});
|
||||
$("input[name='Style']").click(function() {
|
||||
$("#styleLink").attr("href", "/css/blog/" + $(this).val() + ".css");
|
||||
});
|
||||
});
|
||||
|
||||
function inProgress() {
|
||||
}
|
||||
|
||||
// filename, result, resultCode
|
||||
function uploadFinish(ret) {
|
||||
if (ret) {
|
||||
if (ret.resultCode == '1') {
|
||||
$("#logoImg img").attr("src", ret.filename).parent().show();
|
||||
$("#Logo").val(ret.filename);
|
||||
return;
|
||||
}
|
||||
alert(ret.result);
|
||||
return;
|
||||
}
|
||||
// 上传出错
|
||||
alert("上传出错");
|
||||
}
|
||||
|
||||
function submit() {
|
||||
var tpl = '<form action="/blog/setBlog" method="post"><input name="Title" value="?" />';
|
||||
tpl += '<input name="SubTitle" value="?" />';
|
||||
tpl += '<input name="Logo" value="?" />';
|
||||
tpl += '<input name="CanComment" value="?" />';
|
||||
tpl += '<input name="DisqusId" value="?" />';
|
||||
tpl += '<input name="Style" value="?" />';
|
||||
tpl += '<textarea name="AboutMe">?</textarea>';
|
||||
tpl += "</form";
|
||||
var data = {
|
||||
Title : $("#Title").val(),
|
||||
SubTitle : $("#SubTitle").val(),
|
||||
Logo : $("#Logo").val(),
|
||||
AboutMe : getEditorContent(),
|
||||
CanComment : $("#CanComment").is(":checked"),
|
||||
DisqusId : $("#DisqusId").val(),
|
||||
Style : $("input[name='Style']:checked").val()
|
||||
}
|
||||
if (!data.DisqusId) {
|
||||
data.DisqusId = "leanote";
|
||||
}
|
||||
$(t(tpl, data.Title, data.SubTitle, data.Logo,
|
||||
data.CanComment, data.DisqusId, data.Style,
|
||||
data.AboutMe)).submit();
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,139 @@
|
||||
{{template "Blog/header.html" .}}
|
||||
|
||||
<!-- -->
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<div class="each-post">
|
||||
<div class="title">
|
||||
{{.blog.Title}}
|
||||
</div>
|
||||
<div class="created-time">
|
||||
<i class="fa fa-bookmark-o" style="color: #666"></i>
|
||||
{{if .blog.Tags}}
|
||||
{{blogTags .blog.Tags}}
|
||||
{{else}}
|
||||
无
|
||||
{{end}}
|
||||
|
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 更新 {{.blog.UpdatedTime | datetime}} |
|
||||
<i class="fa fa-calendar" style="color: #666"></i> 创建 {{.blog.CreatedTime | datetime}}
|
||||
</div>
|
||||
|
||||
<div class="desc" id="content">
|
||||
{{if .blog.IsMarkdown }}
|
||||
<div id="markdownContent" style="display: none">
|
||||
<!-- 用textarea装html, 防止得到的值失真 -->
|
||||
<textarea>
|
||||
{{.blog.Content | raw}}
|
||||
</textarea>
|
||||
</div>
|
||||
<div style="padding: 20px; text-align: center">
|
||||
<img src="/images/loading-32.gif" />
|
||||
</div>
|
||||
{{else}}
|
||||
{{.blog.Content | raw}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<!-- comment -->
|
||||
{{template "blog/comment.html" .}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{template "Blog/footer.html" .}}
|
||||
{{template "Blog/highlight.html"}}
|
||||
|
||||
<!-- Nav -->
|
||||
<style>
|
||||
#blogNav {
|
||||
display: none;
|
||||
background-color: #fff;
|
||||
opacity: 0.7;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
#blogNavContent {
|
||||
overflow-y: auto;
|
||||
max-height: 250px;
|
||||
display: none;
|
||||
}
|
||||
#blogNavNav {
|
||||
cursor: pointer;
|
||||
}
|
||||
#blogNav a {
|
||||
color: #666;
|
||||
}
|
||||
#blogNav:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
#blogNav a:hover {
|
||||
color: #0fb264;
|
||||
}
|
||||
#blogNav ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
#blogNav ul .nav-h1 {
|
||||
}
|
||||
#blogNav ul .nav-h2 {
|
||||
margin-left: 20px;
|
||||
}
|
||||
#blogNav ul .nav-h3 {
|
||||
margin-left: 30px;
|
||||
}
|
||||
#blogNav ul .nav-h4 {
|
||||
margin-left: 40px;
|
||||
}
|
||||
#blogNav ul .nav-h5 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
</style>
|
||||
<div id="blogNav">
|
||||
<div id="blogNavNav">
|
||||
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||
<span>{{msg . "nav"}}</span>
|
||||
</div>
|
||||
<div id="blogNavContent" style="max-width: 200px">
|
||||
</div>
|
||||
</div>
|
||||
<script src="/public/js/app/blog/nav.js"></script>
|
||||
|
||||
{{if .blog.IsMarkdown }}
|
||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh.js"></script>
|
||||
<script src="/public/mdeditor/editor/Markdown.Extra.js"></script>
|
||||
|
||||
<!--mathjax-->
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||
</script>
|
||||
<script src="/public/mdeditor/editor/mathJax.js"></script>
|
||||
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<script>
|
||||
var content = $.trim($("#markdownContent textarea").val());
|
||||
|
||||
// $("#markdownContent").html("");
|
||||
var converter = Markdown.getSanitizingConverter();
|
||||
Markdown.Extra.init(converter, {extensions: ["tables", "fenced_code_gfm", "def_list"]});
|
||||
var html = converter.makeHtml(content);
|
||||
$("#content").html(html);
|
||||
$("pre").addClass("prettyprint linenums");
|
||||
prettyPrint();
|
||||
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
|
||||
|
||||
initNav();
|
||||
</script>
|
||||
{{else}}
|
||||
<script>
|
||||
$(function() {
|
||||
initNav();
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<title>404</title>
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Helvetica, Arial, Sans;
|
||||
background: #EEEEEE;
|
||||
}
|
||||
.block {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
#header h1 {
|
||||
font-weight: normal;
|
||||
font-size: 28px;
|
||||
margin: 0;
|
||||
}
|
||||
#more {
|
||||
color: #666;
|
||||
font-size: 80%;
|
||||
border: none;
|
||||
}
|
||||
#header {
|
||||
background: #FFFFCC;
|
||||
}
|
||||
#header p {
|
||||
color: #333;
|
||||
}
|
||||
#routes {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
#routes h2 {
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
#routes ol {
|
||||
|
||||
}
|
||||
#routes li {
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="header" class="block">
|
||||
{{with .Error}}
|
||||
<h1>
|
||||
{{.Title}}
|
||||
</h1>
|
||||
<p>
|
||||
{{.Description}}
|
||||
</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="routes" class="block">
|
||||
<h2>These routes have been tried, in this order :</h2>
|
||||
<ol>
|
||||
{{range .Router.Routes}}
|
||||
<li>{{pad .Method 10}}{{pad .Path 50}}{{.Action}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
{{if eq .RunMode "dev"}}
|
||||
{{template "errors/404-dev.html" .}}
|
||||
{{else}}
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>error-404</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
This page cann't found.
|
||||
<br />
|
||||
<a href="javascript:history.go(-1)">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -0,0 +1,118 @@
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Helvetica, Arial, Sans;
|
||||
background: #EEEEEE;
|
||||
}
|
||||
.block {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
#header h1 {
|
||||
font-weight: normal;
|
||||
font-size: 28px;
|
||||
margin: 0;
|
||||
}
|
||||
#more {
|
||||
color: #666;
|
||||
font-size: 80%;
|
||||
border: none;
|
||||
}
|
||||
#header {
|
||||
background: #fcd2da;
|
||||
}
|
||||
#header p {
|
||||
color: #333;
|
||||
}
|
||||
#source {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
#source h2 {
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
#source .lineNumber {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
#source .line {
|
||||
clear: both;
|
||||
color: #333;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
#source pre {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#source .error {
|
||||
color: #c00 !important;
|
||||
}
|
||||
#source .error .lineNumber {
|
||||
background: #c00;
|
||||
}
|
||||
#source a {
|
||||
text-decoration: none;
|
||||
}
|
||||
#source a:hover * {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
#source a:hover pre {
|
||||
background: #FAFFCF !important;
|
||||
}
|
||||
#source em {
|
||||
font-style: normal;
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
}
|
||||
#source strong {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
{{with .Error}}
|
||||
<div id="header" class="block">
|
||||
<h1>
|
||||
{{.Title}}
|
||||
</h1>
|
||||
<p>
|
||||
{{if .SourceType}}
|
||||
The {{.SourceType}} <strong>{{.Path}}</strong> does not compile: <strong>{{.Description}}</strong>
|
||||
{{else}}
|
||||
{{.Description}}
|
||||
{{end}}
|
||||
</p>
|
||||
</div>
|
||||
{{if .Path}}
|
||||
<div id="source" class="block">
|
||||
<h2>In {{.Path}}
|
||||
{{if .Line}}
|
||||
(around {{if .Line}}line {{.Line}}{{end}}{{if .Column}} column {{.Column}}{{end}})
|
||||
{{end}}
|
||||
</h2>
|
||||
{{range .ContextSource}}
|
||||
<div class="line {{if .IsError}}error{{end}}">
|
||||
<span class="lineNumber">{{.Line}}:</span>
|
||||
<pre>{{.Source}}</pre>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .MetaError}}
|
||||
<div id="source" class="block">
|
||||
<h2>Additionally, an error occurred while handling this error.</h2>
|
||||
<div class="line error">
|
||||
{{.MetaError}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{if eq .RunMode "dev"}}
|
||||
{{template "errors/500-dev.html" .}}
|
||||
{{else}}
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>error-500</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
Sorry, we got a error.
|
||||
<br />
|
||||
<a href="javascript:history.go(-1)">Back</a>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>图片上传结果</title>
|
||||
<script language="javascript" type="text/javascript">
|
||||
window.parent.window.uploadFinish({
|
||||
filename:'{{.fileUrlPath}}',
|
||||
result: '{{.resultMsg}}',
|
||||
resultCode: '{{.resultCode}}'
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript">
|
||||
window.parent.window.leanoteImagesDialog.uploadFinish({
|
||||
filename:'{{.fileUrlPath}}',
|
||||
result: '{{.resultMsg}}',
|
||||
resultCode: '{{.resultCode}}'
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
@@ -0,0 +1,83 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<style>
|
||||
</style>
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>leanote | {{msg . "findPassword"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 110px"><label for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "findPassword"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$("#email").focus();
|
||||
if($("#email").val()) {
|
||||
$("#pwd").focus();
|
||||
}
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#loginBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
var email = $("#email").val();
|
||||
if(!email) {
|
||||
showMsg("{{msg . "inputEmail"}}", "email");
|
||||
return;
|
||||
} else {
|
||||
var myreg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
|
||||
if(!myreg.test(email)) {
|
||||
showMsg("{{msg . "wrongEmail"}}", "email");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#loginBtn").html("{{msg . "ing"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/doFindPassword", {email: email}, function(e) {
|
||||
$("#loginBtn").html("{{msg . "findPassword"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
var msg = "{{msg . "findPasswordSendEmailOver"}}";
|
||||
var loginAddress = getEmailLoginAddress(email);
|
||||
if(loginAddress) {
|
||||
msg += ' <a target="_blank" href="' + loginAddress + '">{{msg . "checkEmai"}}</a>';
|
||||
}
|
||||
$("#loginMsg").html(msg).show().removeClass("alert-danger").addClass("alert-success");
|
||||
} else {
|
||||
showMsg(e.Msg, "email");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,99 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>leanote | {{msg . "updatePassword"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="form-group">
|
||||
</div>
|
||||
<div class="alert alert-danger" id="loginMsg"> </div>
|
||||
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 350px"><label for="email">{{msg . "email"}}</label>
|
||||
<br />
|
||||
{{.findPwd.Email}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "updatePassword"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
$(function() {
|
||||
$("#pwd").focus();
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#loginBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var pwd = $("#pwd").val();
|
||||
var pwd2 = $("#pwd2").val();
|
||||
|
||||
if(!pwd) {
|
||||
showMsg("{{msg . "inputPassword"}}", "pwd");
|
||||
return;
|
||||
} else {
|
||||
if(pwd.length < 6) {
|
||||
showMsg("{{msg . "notGoodPassword"}}", "pwd");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!pwd2) {
|
||||
showMsg("{{msg . "inputPassword2"}}", "pwd2");
|
||||
return;
|
||||
} else {
|
||||
if(pwd != pwd2) {
|
||||
showMsg("{{msg . "confirmPassword"}}", "pwd2");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#loginBtn").html("{{msg . "ing"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/findPasswordUpdate", {pwd: pwd, token: "{{.findPwd.Token}}"}, function(e) {
|
||||
$("#loginBtn").html("{{msg . "updatePassword"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
$("#loginBtn").html("{{msg . "updatePasswordSuccessRedirectToLogin"}}");
|
||||
location.href = "/login?email={{.findPwd.Email}}";
|
||||
} else {
|
||||
showMsg(e.Msg, "pwd");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>leanote {{msg . "findPassword"}} - {{msg . "findPasswordTimeout"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg" style="display: block">
|
||||
{{msg . "findPasswordTimeout"}}, <a href="/findPassword">{{msg . "reFindPassword"}}</a>
|
||||
</div>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<div id="footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<i class="fa fa-envelope-o fa-3x icon-muted"></i>
|
||||
<h2>Contact</h2>
|
||||
<a href="http://weibo.com/leanotecom" target="_blank"><i class="fa fa-weibo"></i></a>
|
||||
<br />
|
||||
leanote@leanote.com
|
||||
<div id="beian">
|
||||
<a href="http://www.miibeian.gov.cn" target="_blank">沪ICP备14006011号</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<i class="fa fa-globe fa-3x icon-muted"></i>
|
||||
<h2>Join Us</h2>
|
||||
<a href="https://github.com/leanote/leanote">github leanote</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="author" content="leanote">
|
||||
<title>{{.title}}</title>
|
||||
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/css/index.css" rel="stylesheet">
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="headerContainer" style="background-color:#fff" class="navbar-fixed-top">
|
||||
<div class="container" style="clearfix" id="header">
|
||||
<div class="pull-left">
|
||||
<h1>
|
||||
<a href="/index">
|
||||
<img src="/images/logo.png" id="" style="height: 40px" title="leanote, Your own cloud note!"/>
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" id="loginBtns">
|
||||
{{if .userInfo.Email}}
|
||||
{{msg . "hi"}}, {{.userInfo.Username}}
|
||||
<a href="/note">{{msg . "myNote"}}</a>
|
||||
<a href="/logout">{{msg . "logout"}}</a>
|
||||
{{else}}
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
<a href="/register" class="btn-register">{{msg . "register"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<ul id="blogNav" class="pull-right">
|
||||
<li><a href="/index#" target="body" class="smooth-scroll">{{msg . "home"}}</a></li>
|
||||
<li><a href="/index#aboutLeanote" target="#aboutLeanote" class="smooth-scroll">{{msg . "aboutLeanote"}}</a> </li>
|
||||
<li><a id="leanoteBlog" href="http://leanote.com/blog/leanote" target="_blank" class="">{{msg . "leanoteBlog"}}</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note!">
|
||||
<meta name="author" content="leanote">
|
||||
<title>{{.title}}</title>
|
||||
|
||||
<link href="/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/css/index.css" rel="stylesheet">
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -0,0 +1,86 @@
|
||||
{{template "home/header.html" .}}
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<section>
|
||||
<div class="header">
|
||||
<h2>leanote, Your own cloud note!</h2>
|
||||
<p>Knowledge, Sharing, Cooperation, Blog... all just in leanote</p>
|
||||
|
||||
<div>
|
||||
<a class="btn btn-primary" href="https://github.com/leanote/leanote">Fork leanote from Github</a>
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/demo">Try it</a>
|
||||
|
||||
|
||||
OR
|
||||
|
||||
|
||||
<a class="btn btn-default" href="/register">{{msg . "register"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview" style="position: relative;">
|
||||
<div>
|
||||
<div class="img-header">
|
||||
<img src="/images/home/mac-btns.png"/>
|
||||
</div>
|
||||
<img src="/images/home/preview2.png" style="width: 750px;" />
|
||||
</div>
|
||||
<div class="mobile">
|
||||
<div class="mobile-header">
|
||||
<img src="/images/home/mac-dot.png" />
|
||||
</div>
|
||||
<img class="mobile-image" src="/images/home/mobile.png" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container" id="aboutLeanote">
|
||||
<h2>{{msg . "aboutLeanote"}}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "knowledge"}}</h3>
|
||||
<p>{{msg . "knowledgeInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "share"}}</h3>
|
||||
<p>{{msg . "shareInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "cooperation"}}</h3>
|
||||
<p>{{msg . "cooperationInfo"}}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h3>{{msg . "blog"}}</h3>
|
||||
<p>{{msg . "blogInfo"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "home/footer.html"}}
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
/*
|
||||
var u = navigator.userAgent;
|
||||
var isMobile = u.indexOf('Android')>-1 || u.indexOf('Linux')>-1;
|
||||
if(isMobile || $("body").width() < 600) {
|
||||
location.href = "/mobile/index";
|
||||
}
|
||||
*/
|
||||
// 平滑滚动
|
||||
$(".smooth-scroll").click(function(e) {
|
||||
e.preventDefault();
|
||||
var t = $(this).attr("target");
|
||||
var targetOffset = $(t).offset().top - 80;
|
||||
$('html,body').animate({scrollTop: targetOffset}, 300);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,103 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
<div>
|
||||
<a class="back" href="javascript:history.go(-1);" tabindex="-1">←Back</a>
|
||||
</div>
|
||||
<div>
|
||||
<h1>leanote | {{msg . "login"}}</h1>
|
||||
<form class="form-inline" id="boxForm" >
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="email">{{msg . "usernameOrEmail"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email" value="{{.email}}">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">{{msg . "login"}}</button>
|
||||
<br />
|
||||
<a href="/findPassword">{{msg . "forgetPassword"}}</a>
|
||||
<br />
|
||||
<a href="/register">{{msg . "register"}}</a> {{msg . "or"}}
|
||||
<a href="/demo">{{msg . "try"}}</a>
|
||||
<div style="border-top: 1px dashed #666;margin:2px 0">
|
||||
{{msg . "3th"}}: <a id="github">github<i class="fa fa-github"></i></a>
|
||||
<span id="thirdLoginLoading" style="display: none"> <img src="/images/loading-a-20-2.gif" />正在登录...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$("#email").focus();
|
||||
if($("#email").val()) {
|
||||
$("#pwd").focus();
|
||||
}
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#loginBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
var email = $("#email").val();
|
||||
var pwd = $("#pwd").val();
|
||||
if(!email) {
|
||||
showMsg("{{msg . "inputUsername"}}", "email");
|
||||
return;
|
||||
}
|
||||
if(!pwd) {
|
||||
showMsg("{{msg . "inputPassword"}}", "pwd");
|
||||
return;
|
||||
} else {
|
||||
if(pwd.length < 6) {
|
||||
showMsg("{{msg . "wrongPassword"}}", "pwd");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#loginBtn").html("{{msg . "logining"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/doLogin", {email: email, pwd: pwd}, function(e) {
|
||||
$("#loginBtn").html("{{msg . "login"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
$("#loginBtn").html("{{msg . "loginSuccess"}}...");
|
||||
location.href = '/note';
|
||||
} else {
|
||||
showMsg(e.Msg, "pwd");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// github
|
||||
$("#github").click(function() {
|
||||
$("#thirdLoginLoading").show();
|
||||
location.href="https://github.com/login/oauth/authorize?access_type=&approval_prompt=&client_id=3790fbf1fc14bc6c5d85&redirect_uri=http%3A%2F%2Fleanote.com%2Foauth%2FgithubCallback&response_type=code&scope=user&state=";
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<div class="modal fade bs-modal-sm" id="leanoteDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">操作</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
..................
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
@@ -0,0 +1,115 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
<section id="box">
|
||||
<div>
|
||||
<a class="back" href="javascript:history.go(-1);" tabindex="-1">←Back</a>
|
||||
</div>
|
||||
<div>
|
||||
<h1>leanote | {{msg . "register"}}</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<div class="alert alert-danger" id="loginMsg"></div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="email">{{msg . "email"}}</label>
|
||||
<input type="text" class="form-control" id="email" name="email">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "password"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
{{msg . "passwordTips"}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="registerBtn" class="btn btn-success" style="width: 100%">{{msg . "register"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
<div id="quickLinks">
|
||||
<a href="/login">{{msg . "login"}}</a>
|
||||
|
||||
<a href="/index">{{msg . "home"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/js/bootstrap.js"></script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$("#email").focus();
|
||||
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#registerBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
var email = $("#email").val();
|
||||
var pwd = $("#pwd").val();
|
||||
var pwd2 = $("#pwd2").val();
|
||||
if(!email) {
|
||||
showMsg("{{msg . "inputEmail"}}", "email");
|
||||
return;
|
||||
} else {
|
||||
var myreg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[0-9a-zA-Z]{2,3}$/;
|
||||
if(!myreg.test(email)) {
|
||||
showMsg("{{msg . "wrongEmail"}}", "email");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!pwd) {
|
||||
showMsg("{{msg . "inputPassword"}}", "pwd");
|
||||
return;
|
||||
} else {
|
||||
if(pwd.length < 6) {
|
||||
showMsg("{{msg . "notGoodPassword"}}", "pwd");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!pwd2) {
|
||||
showMsg("{{msg . "inputPassword2"}}", "pwd2");
|
||||
return;
|
||||
} else {
|
||||
if(pwd != pwd2) {
|
||||
showMsg("{{msg . "confirmPassword"}}", "pwd2");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#registerBtn").html("{{msg . "ing"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/doRegister", {email: email, pwd: pwd}, function(e) {
|
||||
$("#registerBtn").html("{{msg . "register"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
$("#registerBtn").html("{{msg . "registerSuccessAndRdirectToNote"}}");
|
||||
location.href = '/note';
|
||||
} else {
|
||||
showMsg(e.Msg, "email");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,178 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<title>leanote</title>
|
||||
<link href="/public/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/mobile/css/base.css" rel="stylesheet" type="text/css">
|
||||
<link href="/public/css/bootstrap.css" rel="stylesheet" />
|
||||
<link href="/public/mobile/css/leanote.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
// console.log(o);
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="preloader">
|
||||
<div id="status">
|
||||
<p class="center-text">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="all-elements" style="height: 100%">
|
||||
<div id="sidebar" class="page-sidebar sidebar-content-background">
|
||||
<div class="page-sidebar-scroll">
|
||||
<div>
|
||||
<div class="sidebar-section">
|
||||
<a href="#" class="sidebar-close"></a>
|
||||
<em>leanote</em>
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
<div id="userInfo">
|
||||
{{.userInfo.Username}}
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
|
||||
<div class="sidebar-navigation">
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-newest">最新笔记</a>
|
||||
</div>
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-myNotebooks">我的笔记本</a>
|
||||
</div>
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-myTags">我的标签</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-decoration"></div>
|
||||
<div class="sidebar-navigation">
|
||||
<div class="nav-item">
|
||||
<a href="#" class="nav-logout">退出</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="page-content" style="position: absolute;background-color: #fff;width: 100%;">
|
||||
<!-- notebooks -->
|
||||
<div id="notebooks">
|
||||
<!-- 头部 -->
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
我的笔记本
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom: 0">
|
||||
<ul id="notebookList">
|
||||
</ul>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
添加笔记本
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- note -->
|
||||
<div id="notes">
|
||||
<!-- 头部 -->
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
XX的笔记
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom:0">
|
||||
<div id="noteItemList">
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
添加笔记
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- view -->
|
||||
<div id="view">
|
||||
<div class="content-controls clearfix">
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-angle-left back"></i>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<span class="g-title">
|
||||
笔记标题
|
||||
</span>
|
||||
</div>
|
||||
<!-- 其它按钮 -->
|
||||
<div class="pull-right btns">
|
||||
<i class="fa fa-pencil" id="editBtn"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="each-container">
|
||||
<div class="each-content" style="bottom:0">
|
||||
<img id="loading" style="width: 30px; margin: auto; margin-top: 100px; height: 30px; display: none" src="/public/mobile/images/status.gif" />
|
||||
<div id="noteContent"></div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="each-footer">
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||
<script src="/public/mobile/js/snap.js"></script>
|
||||
<script src="/public/js/i18n/msg.{{.locale}}.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-common.js"></script>
|
||||
<script>
|
||||
var UserInfo = json({{.userInfoJson}});
|
||||
var notebooks = json({{.notebooks}});
|
||||
</script>
|
||||
<!--
|
||||
// var shareNotebooks = json({{.shareNotebooks}});
|
||||
// var sharedUserInfos = json({{.sharedUserInfos}});
|
||||
// var tagsJson = json({{.tagsJson}});
|
||||
-->
|
||||
<script src="/public/mobile/js/app/mobile-notebook.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-tag.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-note.js"></script>
|
||||
<script src="/public/mobile/js/app/mobile-page.js"></script>
|
||||
<script>
|
||||
Notebook.RenderNotebooks(notebooks);
|
||||
// Share.RenderShareNotebooks(sharedUserInfos, shareNotebooks);
|
||||
// Tag.renderTagNav(tagsJson);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE HTML>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<title>leanote login</title>
|
||||
|
||||
<link href="/public/css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="/public/mobile/styles/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="/public/mobile/styles/colors/default.css" rel="stylesheet" type="text/css" id="pagestyle">
|
||||
<link href="/public/mobile/styles/framework.css" rel="stylesheet" type="text/css">
|
||||
<link href="/public/css/bootstrap.css" rel="stylesheet" />
|
||||
<link href="/public/mobile/styles/life.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<style>
|
||||
.alert {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.form-control {
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-transition: nonoe;
|
||||
transition: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="preloader">
|
||||
<div id="status">
|
||||
<p class="center-text">
|
||||
loading...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center">
|
||||
<img src="/public/mobile/images/blog01.jpg" style="width: 100%"/>
|
||||
<form id="loginForm" style="width: 90%; margin: auto;">
|
||||
<div class="form-group">
|
||||
<h2 style="margin-top:10px">leanote 登录</h2>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="loginMsg" style="display: none"></div>
|
||||
<div class="form-group">
|
||||
<input class="form-control" id="email" name="email" placeholder="用户名或Email" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="pwd" name="pwd" placeholder="密码">
|
||||
</div>
|
||||
<button id="loginBtn" class="btn btn-success" style="width: 100%">登录</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="/public/mobile/scripts/jquery.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$("#status").fadeOut(); // will first fade out the loading animation
|
||||
$("#preloader").delay(350).fadeOut("slow"); // will fade out the white DIV that covers the website.
|
||||
function showMsg(msg, id) {
|
||||
$("#loginMsg").html(msg).show();
|
||||
if(id) {
|
||||
$("#" + id).focus();
|
||||
}
|
||||
}
|
||||
function hideMsg() {
|
||||
$("#loginMsg").hide();
|
||||
}
|
||||
$("#loginBtn").click(function(e){
|
||||
e.preventDefault();
|
||||
var email = $("#email").val();
|
||||
var pwd = $("#pwd").val();
|
||||
if(!email) {
|
||||
showMsg("{{msg . "inputUsername"}}", "email");
|
||||
return;
|
||||
}
|
||||
if(!pwd) {
|
||||
showMsg("{{msg . "inputPassword"}}", "pwd");
|
||||
return;
|
||||
} else {
|
||||
if(pwd.length < 6) {
|
||||
showMsg("{{msg . "wrongPassword"}}", "pwd");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$("#loginBtn").html("{{msg . "logining"}}...").addClass("disabled");
|
||||
// hideMsg();
|
||||
|
||||
$.post("/doLogin", {email: email, pwd: pwd}, function(e) {
|
||||
$("#loginBtn").html("{{msg . "login"}}").removeClass("disabled");
|
||||
if(e.Ok) {
|
||||
$("#loginBtn").html("{{msg . "loginSuccess"}}...");
|
||||
location.href = '/mobile/index';
|
||||
} else {
|
||||
showMsg(e.Msg, "pwd");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">历史记录</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
||||
<table class="table table-hover" id="shareNotebookTable">
|
||||
<tbody>
|
||||
{{range $i, $v := .histories}}
|
||||
<tr>
|
||||
<td>
|
||||
{{raw $v.Content}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
@@ -0,0 +1,953 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="author" content="life">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note">
|
||||
<title>leanote, {{msg . "moto"}}</title>
|
||||
|
||||
<link href="css/bootstrap.css" rel="stylesheet" />
|
||||
<!-- 先加载, 没有样式, 宽度不定 -->
|
||||
<link rel="stylesheet" href="tinymce/skins/custom/skin.min.css" type="text/css" />
|
||||
<!-- leanote css -->
|
||||
<link rel="stylesheet" href="css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />
|
||||
<link href="css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet" />
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
console.log(o);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="pageInner">
|
||||
|
||||
<!-- 头部 -->
|
||||
<!-- <div id="headerContainer"> -->
|
||||
<div id="header">
|
||||
|
||||
<!-- <div id="headerLeft" class="pull-left">
|
||||
</div>
|
||||
-->
|
||||
<div id="logo" class="pull-left">
|
||||
<span>lea</span>note
|
||||
<!-- <img style="height: 45px;" src="/images/logo.png" title="leanote, 不一样的笔记" alt="leanote">
|
||||
-->
|
||||
</div>
|
||||
<div id="switcher" class="pull-left">
|
||||
<i class="fa fa-align-justify" id="leftSwitcher" title="{{msg . "leftHidden"}}"></i>
|
||||
<span id="leftSwitcher2" title="{{msg . "leftShow"}}">lea</span>
|
||||
</div>
|
||||
<!-- search -->
|
||||
<div class="pull-left">
|
||||
<form class="navbar-form form-inline col-lg-2 hidden-xs" id="searchNote">
|
||||
<input class="form-control" placeholder="Search" type="text" id="searchNoteInput">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 全局按钮 -->
|
||||
<div class="pull-left" style="line-height: 40px; margin-top: 10px;">
|
||||
|
||||
<!-- 新建笔记 -->
|
||||
<div id="newMyNote">
|
||||
<a id="newNoteBtn" title="{{msg . "newNote"}}">
|
||||
<i class="fa fa-file-o"></i>
|
||||
{{msg . "newNote"}}
|
||||
</a>
|
||||
|
|
||||
<a id="newNoteMarkdownBtn" title="{{msg . "newMarkdown"}}">
|
||||
Markdown
|
||||
</a>
|
||||
- <span id="curNotebookForNewNote" notebookId=""></span>
|
||||
<div class="dropdown" style="display: inline-block">
|
||||
<a class="ios7-a dropdown-toggle"
|
||||
id="dropdownMenu2" data-toggle="dropdown">
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2" style="width: 180px;left: -5px;" id="notebookNavForNewNote">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 只为新建别人的笔记 -->
|
||||
<div id="newSharedNote" style="display: none">
|
||||
<a id="newSharedNoteBtn">
|
||||
<i class="fa fa-file-o"></i>
|
||||
{{msg . "newNote"}}
|
||||
</a>
|
||||
|
|
||||
<a id="newShareNoteMarkdownBtn" title="{{msg . "newMarkdown"}}">
|
||||
Markdown
|
||||
</a>
|
||||
- <span id="curNotebookForNewSharedNote" notebookId="" userId=""></span>
|
||||
<div class="dropdown" style="display: inline-block">
|
||||
<a class="ios7-a dropdown-toggle"
|
||||
id="dropdownMenu2" data-toggle="dropdown">
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2" style="width: 180px;left: -5px;" id="notebookNavForNewSharedNote">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-left" style="line-height: 40px; margin-top: 10px; margin-left: 10px;" id="leanoteMsg">
|
||||
<span id="msg" style="display: inline-block;"></span>
|
||||
<img id="loading" style="visibility: hidden" src="/images/loading-a-20.gif" />
|
||||
{{if eq .userInfo.Email "demo@leanote.com"}}
|
||||
<span>
|
||||
{{msg . "demoRegister"}}
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="pull-left alert-warning" style="line-height: 20px; margin-top: 10px; margin-left: 0px; display: none" id="verifyMsg">
|
||||
您还没有验证邮箱, 验证邮件已发送至 {{.userInfo.Email}}.
|
||||
<br />
|
||||
<a class=".nowToActive">现在去验证</a> <a id="reSendActiveEmail">重新发送</a> <a id="wrongEmail">邮箱填错了?</a>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="pull-right" style="margin: 0 10px" id="myProfile">
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" style="line-height: 60px;">
|
||||
<!--
|
||||
<img src="images/avatar.png" style="height: 40px; border: 1px solid #ccc" />
|
||||
-->
|
||||
<span class="username">
|
||||
{{if .userInfo.UsernameRaw}}
|
||||
{{.userInfo.UsernameRaw}}
|
||||
{{else}}
|
||||
{{.userInfo.Username}}
|
||||
{{end}}
|
||||
</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu li-a" role="menu">
|
||||
<li role="presentation" id="setInfo">
|
||||
<i class="fa fa-info"></i>
|
||||
{{msg . "accountSetting"}}
|
||||
</li>
|
||||
<li role="presentation" id="setTheme">
|
||||
<i class="fa fa-sun-o"></i>
|
||||
{{msg . "themeSetting"}}
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation" id="yourSuggestions">
|
||||
<i class="fa fa-comment-o"></i>
|
||||
{{msg . "yourSuggestions"}}
|
||||
</li>
|
||||
-->
|
||||
<li role="presentation" onclick="logout()">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
{{msg . "logout"}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="margin: 0 10px" id="topNav">
|
||||
<a target="_blank" href="/blog/{{.userInfo.Username}}">
|
||||
{{msg . "myBlog"}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<ul id="setting" class="pull-right">
|
||||
<li class="dropdown messages">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span aria-hidden="true" class="icon se7en-flag"></span>
|
||||
<div class="sr-only">Messages</div>
|
||||
<p class="counter">3</p>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#"> c@c.com 共享了笔记给你 是否接受? </a></li>
|
||||
<li><a href="#"> d@c.com 共享了笔记给你 是否接受? </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown settings">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span aria-hidden="true" class="icon se7en-gear"></span>
|
||||
<div class="sr-only">Settings</div>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="settings-link blue"><span></span>Blue</a></li>
|
||||
<li><a class="settings-link green"><span></span>Green</a></li>
|
||||
<li><a class="settings-link orange"><span></span>Orange</a>
|
||||
</li>
|
||||
<li><a class="settings-link magenta"><span></span>Magenta</a>
|
||||
</li>
|
||||
<li><a class="settings-link gray"><span></span>Gray</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
-->
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
|
||||
<div id="mainContainer" class="clearfix">
|
||||
<div id="mainMask">
|
||||
<img src="/images/loading-30.gif" />
|
||||
<br />
|
||||
<br />
|
||||
loading...
|
||||
</div>
|
||||
<div id="leftNotebook">
|
||||
<div id="notebook">
|
||||
<div class="folderNote opened" id="myNotebooks">
|
||||
<div class="folderHeader clearfix">
|
||||
<i class="fa fa-book pull-left fa-left"></i>
|
||||
<span class="pull-left">
|
||||
{{msg . "notebook"}}
|
||||
</span>
|
||||
<div class="pull-right" id="addNotebookPlus" title="{{msg . "addNotebook"}}">
|
||||
<i class="fa fa-plus" title="{{msg . "addNotebook"}}"></i>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="folderBody" id="notebookList">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="folderNote closed" id="myTag">
|
||||
<div class="folderHeader">
|
||||
<i class="fa fa-bookmark fa-left"></i>
|
||||
<span>
|
||||
{{msg . "tag"}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="folderBody" id="tagNav">
|
||||
<li><a> <span class="label label-red">{{msg . "red"}}</span></a></li>
|
||||
<li><a> <span class="label label-blue">{{msg . "blue"}}</span></a></li>
|
||||
<li><a> <span class="label label-yellow">{{msg . "yellow"}}</span></a></li>
|
||||
<li><a> <span class="label label-green">{{msg . "green"}}</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="folderNote closed" id="">
|
||||
<div class="folderHeader">
|
||||
<i class="fa fa-user fa-left"></i>
|
||||
<span>
|
||||
共享
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="folderBody" id="shareNotebooks">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 缩小版 -->
|
||||
<div id="notebookMin">
|
||||
<!-- 这里隐藏, 不要 -->
|
||||
<div target="#notebookList" title="{{msg . "notebook"}}" class="minContainer">
|
||||
<i class="fa fa-book"></i>
|
||||
<ul class="dropdown-menu" id="minNotebookList">
|
||||
</ul>
|
||||
</div>
|
||||
<div target="#tagNav" title="{{msg . "myTag"}}" class="minContainer">
|
||||
<i class="fa fa-bookmark"></i>
|
||||
<ul class="dropdown-menu" id="minTagNav">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="minShareNotebooks">
|
||||
<!--
|
||||
<div class="minContainer" target="" title="">
|
||||
<i class="fa fa-user"></i>
|
||||
<ul class="dropdown-menu">
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
底下隐藏/展开
|
||||
<div id="notebookBottom">
|
||||
<i class="fa fa-angle-left" id="leftSwitcher"></i>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="noteSplit" id="notebookSplitter"></div>
|
||||
|
||||
<div id="noteAndEditor">
|
||||
<div id="noteList">
|
||||
<div class="clearfix" id="notesAndSort" style="position: relative">
|
||||
|
||||
<div class="pull-left">
|
||||
|
||||
<!-- 我的笔记本 -->
|
||||
<div class="dropdown" id="myNotebookNavForListNav">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<!-- 如果notebook过多, 则会产生滚动 -->
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
aria-labelledby="dropdownMenu1" style="left: 5px;" id="notebookNavForListNote">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 共享的笔记本 -->
|
||||
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu2" data-toggle="dropdown">
|
||||
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
aria-labelledby="dropdownMenu2" style="left: 5px;" id="sharedNotebookNavForListNote">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pull-left" id="tagSearch" style="line-height: 38px">
|
||||
</div>
|
||||
<div id="sortType">
|
||||
<div class="dropdown">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
||||
data-toggle="dropdown">
|
||||
<!--
|
||||
<i class="fa fa-sort-alpha-asc">
|
||||
</i>Sort <i class="fa fa-angle-down"></i>
|
||||
-->
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
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 role="menuitem" tabindex="-1"
|
||||
href="#">修改日期</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
href="#">标题</a></li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
href="#">Separated </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 笔记列表 -->
|
||||
<!-- wrap 为了slimScroll -->
|
||||
<div id="noteItemListWrap" style="position: absolute; left: 0; right: 0; top: 41px; bottom: 3px">
|
||||
<div id="noteItemList">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noteSplit" id="noteSplitter"></div>
|
||||
|
||||
<div id="note">
|
||||
<!-- 只读模式 -->
|
||||
<div id="noteRead">
|
||||
<div id="noteReadContainer">
|
||||
<div id="noteReadTop">
|
||||
<h2 id="noteReadTitle"></h2>
|
||||
<div class="clearfix">
|
||||
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-bookmark-o"></i>
|
||||
<span id="noteReadTags"></span>
|
||||
</div>
|
||||
|
||||
<!-- 修改时间 -->
|
||||
<div class="pull-left" style="margin-left: 10px;">
|
||||
<i class="fa fa-calendar"></i>{{msg . "update"}}
|
||||
<span id="noteReadUpdatedTime"></span>
|
||||
</div>
|
||||
<!-- 修改时间 -->
|
||||
<div class="pull-left" style="margin-left: 10px;">
|
||||
<i class="fa fa-calendar"></i>{{msg . "create"}}
|
||||
<span id="noteReadCreatedTime"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="noteReadContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 遮罩, 为了resize3Columns用 -->
|
||||
<div id="noteMask"
|
||||
style="position: absolute; top: 0px; bottom: 0px; right: 0; left: 10px; z-index: -1"></div>
|
||||
<div id="editorMask">
|
||||
该笔记本下空空如也...何不
|
||||
<br />
|
||||
<div id="editorMaskBtns">
|
||||
<br />
|
||||
<a class="note">新建笔记</a>
|
||||
<a class="markdown">新建Markdown笔记</a>
|
||||
</div>
|
||||
<div id="editorMaskBtnsEmpty">
|
||||
Sorry, 这里不能添加笔记的.
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteTop">
|
||||
<!-- 左侧放tag, 右侧放按钮, 比如save, info, move, delete -->
|
||||
<div id="tool" class="clearfix">
|
||||
<!-- tag可以参考 mac的文件tag, 预定义一些颜色, 用户也可以自己输入-->
|
||||
|
||||
<!--
|
||||
<div class="pull-left" id="noteTitleDiv">
|
||||
<input name="noteTitle" id="noteTitle" value="" placeholder="无标题">
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="pull-left" id="tag">
|
||||
<div id="tags" style="display: inline-block; line-height: 25px;">
|
||||
</div>
|
||||
|
||||
<div class="dropdown" style="display: inline-block"
|
||||
id="tagDropdown">
|
||||
<i class="fa fa-bookmark-o"></i>
|
||||
<a
|
||||
class="metro-a dropdown-toggle" data-toggle="dropdown"
|
||||
id="addTagTrigger" style="cursor: text; padding-left: 0">
|
||||
{{msg . "clickAddTag"}}
|
||||
</a>
|
||||
<input type="text" id="addTagInput" />
|
||||
<ul class="dropdown-menu" role="menu" id="tagColor">
|
||||
<li role="presentation"><span class="label label-red">{{msg . "red"}}</span>
|
||||
</li>
|
||||
<li role="presentation"><span class="label label-blue">{{msg . "blue"}}</span>
|
||||
</li>
|
||||
<li role="presentation"><span class="label label-yellow">{{msg . "yellow"}}</span></li>
|
||||
<li role="presentation"><span class="label label-green">{{msg . "green"}}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ul class="pull-right" id="editorTool">
|
||||
<li><a class="ios7-a " id="saveBtn" title="ctrl+s"
|
||||
data-toggle="dropdown">{{msg . "save"}}</a></li>
|
||||
<li><a class="ios7-a " id="tipsBtn"
|
||||
data-toggle="dropdown">{{msg . "editorTips"}}</a></li>
|
||||
<li><a class="ios7-a " id="contentHistory"
|
||||
data-toggle="dropdown">{{msg . "history"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="noteTitleDiv">
|
||||
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="editor">
|
||||
<!-- 编辑器 -->
|
||||
<div id="mceToolbar" style="">
|
||||
<div id="popularToolbar"
|
||||
style="position: absolute; right: 30px; left: 0"></div>
|
||||
<a
|
||||
style="dispaly: block; position: absolute; cursor: pointer; right: 10px; padding: 3px 10px"
|
||||
id="moreBtn"> <i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div id="leanoteNav">
|
||||
<h1>
|
||||
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||
<span>{{msg . "nav"}}</span>
|
||||
</h1>
|
||||
<div id="leanoteNavContent">
|
||||
</div>
|
||||
</div>
|
||||
<!-- 由此可以算高度 -->
|
||||
<div id="editorContent" name="editorContent">
|
||||
{{.noteContent}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mdEditor">
|
||||
<div id="wmd-button-bar" id="mdBar"></div>
|
||||
<!-- 为了scroll -->
|
||||
|
||||
<div class="clearfix" id="mdEditorPreview">
|
||||
<div id="left-column" class="pull-left">
|
||||
<div id="wmd-panel-editor" class="wmd-panel-editor">
|
||||
<textarea class="wmd-input theme" id="wmd-input" spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right-column" class="pull-right">
|
||||
<div id="wmd-panel-preview" class="wmd-panel-preview preview-container">
|
||||
<div id="wmd-preview" class="wmd-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="md-section-helper"></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- mdEditor -->
|
||||
<!-- Hidden Popup Modal -->
|
||||
<div class="modal fade bs-modal-sm" id="editorDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="editorDialog-title">操作</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<i></i>
|
||||
</span>
|
||||
<input type="text" class="form-control" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary" id="editorDialog-confirm">确认</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 弹出框 模板 -->
|
||||
<div class="modal fade bs-modal-sm" id="leanoteDialogRemote" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
</div>
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="leanoteDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">操作</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
内容区
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="sendRegisterEmailDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">邀请好友</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form role="form">
|
||||
<div class="form-group">
|
||||
<div id="registerEmailMsg" class="alert alert-warning" style="display: none">
|
||||
</div>
|
||||
<input type="hidden" id="toEmail"/>
|
||||
<label for="emailContent">邮件内容</label>
|
||||
<textarea class="form-control" id="emailContent">Hi, 我是李铁, leanote非常好用, 快来注册吧.</textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-success" id="registerEmailBtn">发送</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="setThemeDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">主题设置</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<style>
|
||||
#themeForm td {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
#themeForm img {
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
<table id="themeForm">
|
||||
<tr>
|
||||
<td>
|
||||
<label>
|
||||
<img src="/images/slider/all.gif" height="100px">
|
||||
<br />
|
||||
<input type="radio" name="theme" value="default"> {{msg . "default"}}
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<label>
|
||||
<img src="/images/slider/all-simple.gif" height="100px">
|
||||
<br />
|
||||
<input type="radio" name="theme" value="simple"> {{msg . "simple"}}
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 编辑器提示 -->
|
||||
<div class="modal fade bs-modal-sm" id="tipsDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "editorTips"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{msg . "editorTipsInfo"}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<div class="modal fade bs-modal-sm" id="imageDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content" style="height: 460px;" >
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "uploadImage"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe style="" height="360" src="" scrolling="no" frameBorder="0" width="99%"></iframe>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 您的建议
|
||||
<div class="modal fade bs-modal-sm" id="suggestionsDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "yourSuggestions"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="margin-bottom:20px;">
|
||||
{{msg . "suggestionsInfo"}}<br />
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning" id="suggestionMsg" style="display: none"> </div>
|
||||
<textarea style="width: 100%; height: 100px" id="suggestionTextarea" placeholder="{{msg . "suggestions"}}"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="suggestionBtn" class="btn btn-success" >{{msg . "submit"}}</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- modal 静态区域 -->
|
||||
<div class="display: hidden">
|
||||
|
||||
<!-- 长微博 -->
|
||||
<div id="html2ImageDialog">
|
||||
<div class="modal-body">
|
||||
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow: scroll;" class="weibo">
|
||||
<span class="text">
|
||||
leanote正在努力为你生成长微博...
|
||||
</span>
|
||||
<br />
|
||||
<img src="/images/loading-24.gif"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "cancel"}}</button>
|
||||
<button type="button" class="btn btn-success sendWeiboBtn disabled">{{msg . "send"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 长微博 -->
|
||||
<div id="reSendActiveEmailDialog">
|
||||
<div class="modal-body">
|
||||
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow: scroll;" class="weibo">
|
||||
<span class="text">
|
||||
<img src="/images/loading-24.gif"/>
|
||||
正在发送邮件到{{.userInfo.Email}}...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-success viewEmailBtn disabled">查看邮件</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 帐户设置 -->
|
||||
<div id="dialogSetInfo">
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="myTabs">
|
||||
<li><a href="#baseInfo" data-toggle="tab">{{msg . "basicInfo"}}</a></li>
|
||||
<li><a href="#emailInfo" data-toggle="tab">{{msg . "updateEmail"}}</a></li>
|
||||
<li><a href="#updatePwd" data-toggle="tab">{{msg . "updatePassword"}}</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="baseInfo">
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="username">用户名设置</label>
|
||||
<div class="alert alert-danger" id="usernameMsg" style="display: none"></div>
|
||||
<input type="text" class="form-control" id="username">
|
||||
你的邮箱是 {{.userInfo.Email}}, 可以再设置一个唯一的用户名.
|
||||
<br />
|
||||
用户名至少4位, 不可含特殊字符.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="usernameBtn" class="btn btn-success">提交</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="emailInfo">
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
当前邮箱为: <span id="curEmail">{{.userInfo.Email}}</span>
|
||||
{{if .userInfo.Verified}}
|
||||
已验证
|
||||
{{else}}
|
||||
未验证
|
||||
<a class="raw nowToActive">现在去验证</a>
|
||||
<a class="raw reSendActiveEmail">重新发送</a>
|
||||
{{end}}
|
||||
<br />
|
||||
<label for="email">修改邮箱</label>
|
||||
<div class="alert alert-danger" id="emailMsg" style="display: none"></div>
|
||||
<input type="text" class="form-control" id="email">
|
||||
邮箱修改后, 验证之后才有效, 验证之后新的邮箱地址将会作为登录帐号使用.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="emailBtn" class="btn btn-success">发送验证邮箱</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="updatePwd">
|
||||
<form>
|
||||
<table style="width: 80%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="alert alert-danger" id="pwdMsg" style="display: none"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 80px">
|
||||
<label for="pwd">{{msg . "oldPassword"}}</label>
|
||||
<input type="password" class="form-control" id="oldPwd" name="oldPwd">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "newPassword"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="pwdBtn" class="btn btn-success" style="width: 100%">{{msg . "submit"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 账号设置, 是通过third 登录进来的 -->
|
||||
<div id="thirdDialogSetInfo">
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="thirdMyTabs">
|
||||
<li><a href="#accountInfo" data-toggle="tab">创建帐号</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="accountInfo">
|
||||
您现在使用的是第三方帐号登录leanote, 您也可以注册leanote帐号登录, 赶紧注册一个吧.
|
||||
<br />
|
||||
注册成功后仍可以使用第三方帐号登录leanote并管理您现有的笔记.
|
||||
<form>
|
||||
<div class="alert alert-danger" id="thirdAccountMsg" style="display: none"></div>
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdEmail">邮箱</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" class="form-control" id="thirdEmail">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdPwd">密码</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="password" class="form-control" id="thirdPwd">
|
||||
</td>
|
||||
<td>
|
||||
密码至少6位
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdPwd2">重复密码</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="password" class="form-control" id="thirdPwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button id="accountBtn" class="btn btn-success" style="width: 100%">提交</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide" id="copyDiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/jquery-1.9.0.min.js"></script>
|
||||
<script src="js/i18n/msg.{{.locale}}.js"></script>
|
||||
<script src="js/common.js"></script>
|
||||
<script>
|
||||
var UrlPrefix = "http://leanote.com"; // 为了发weibo
|
||||
var UserInfo = json({{.userInfoJson}});
|
||||
var notebooks = json({{.notebooks}});
|
||||
var shareNotebooks = json({{.shareNotebooks}});
|
||||
var sharedUserInfos = json({{.sharedUserInfos}});
|
||||
var notes = json({{.notes}});
|
||||
var noteContentJson = json({{.noteContentJson}});
|
||||
var tagsJson = json({{.tagsJson}});
|
||||
</script>
|
||||
|
||||
<!-- 渲染view -->
|
||||
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
|
||||
<script src="js/app/page.js"></script>
|
||||
|
||||
<script src="tinymce/tinymce.min.js"></script>
|
||||
<script src="js/jquery-cookie-min.js"></script>
|
||||
<script src="js/bootstrap-min.js"></script>
|
||||
<script src="js/app/note.js"></script>
|
||||
<script src="js/app/tag.js"></script>
|
||||
<script src="js/app/notebook.js"></script>
|
||||
<script src="js/app/share.js"></script>
|
||||
<script src="js/object_id-min.js"></script>
|
||||
<script src="js/ZeroClipboard/ZeroClipboard-min.js"></script>
|
||||
<script>
|
||||
Notebook.renderNotebooks(notebooks);
|
||||
Share.renderShareNotebooks(sharedUserInfos, shareNotebooks);
|
||||
|
||||
Note.renderNotes(notes);
|
||||
if(!isEmpty(notes)) {
|
||||
Note.changeNote(notes[0].NoteId);
|
||||
}
|
||||
|
||||
Note.setNoteCache(noteContentJson);
|
||||
Note.renderNoteContent(noteContentJson)
|
||||
|
||||
Tag.renderTagNav(tagsJson);
|
||||
</script>
|
||||
|
||||
<!-- mdEditor -->
|
||||
<link href="/public/mdeditor/editor/editor.css" rel="stylesheet">
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/Markdown.Extra-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/underscore-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/scrollLink.js"></script>
|
||||
<!--mathjax-->
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||
</script>
|
||||
<script src="/public/mdeditor/editor/mathJax-min.js"></script>
|
||||
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<script src="/public/mdeditor/editor/jquery.waitforimages-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||
<script src="/public/mdeditor/editor/editor.js"></script>
|
||||
<!-- mdEditor end -->
|
||||
|
||||
<!-- context-menu -->
|
||||
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
|
||||
<script src="/js/contextmenu/jquery.contextmenu.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+953
@@ -0,0 +1,953 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="author" content="life">
|
||||
<meta name="keywords" content="leanote,leanote.com">
|
||||
<meta name="description" content="leanote, your own cloud note">
|
||||
<title>leanote, {{msg . "moto"}}</title>
|
||||
|
||||
<link href="css/bootstrap.css" rel="stylesheet" />
|
||||
<!-- 先加载, 没有样式, 宽度不定 -->
|
||||
<link rel="stylesheet" href="tinymce/skins/custom/skin.min.css" type="text/css" />
|
||||
<!-- leanote css -->
|
||||
<link rel="stylesheet" href="css/theme/{{if .userInfo.Theme}}{{.userInfo.Theme}}{{else}}default{{end}}.css" type="text/css" id="themeLink" />
|
||||
<link href="css/font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet" />
|
||||
|
||||
<script>
|
||||
function log(o) {
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="pageInner">
|
||||
|
||||
<!-- 头部 -->
|
||||
<!-- <div id="headerContainer"> -->
|
||||
<div id="header">
|
||||
|
||||
<!-- <div id="headerLeft" class="pull-left">
|
||||
</div>
|
||||
-->
|
||||
<div id="logo" class="pull-left">
|
||||
<span>lea</span>note
|
||||
<!-- <img style="height: 45px;" src="/images/logo.png" title="leanote, 不一样的笔记" alt="leanote">
|
||||
-->
|
||||
</div>
|
||||
<div id="switcher" class="pull-left">
|
||||
<i class="fa fa-align-justify" id="leftSwitcher" title="{{msg . "leftHidden"}}"></i>
|
||||
<span id="leftSwitcher2" title="{{msg . "leftShow"}}">lea</span>
|
||||
</div>
|
||||
<!-- search -->
|
||||
<div class="pull-left">
|
||||
<form class="navbar-form form-inline col-lg-2 hidden-xs" id="searchNote">
|
||||
<input class="form-control" placeholder="Search" type="text" id="searchNoteInput">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 全局按钮 -->
|
||||
<div class="pull-left" style="line-height: 40px; margin-top: 10px;">
|
||||
|
||||
<!-- 新建笔记 -->
|
||||
<div id="newMyNote">
|
||||
<a id="newNoteBtn" title="{{msg . "newNote"}}">
|
||||
<i class="fa fa-file-o"></i>
|
||||
{{msg . "newNote"}}
|
||||
</a>
|
||||
|
|
||||
<a id="newNoteMarkdownBtn" title="{{msg . "newMarkdown"}}">
|
||||
Markdown
|
||||
</a>
|
||||
- <span id="curNotebookForNewNote" notebookId=""></span>
|
||||
<div class="dropdown" style="display: inline-block">
|
||||
<a class="ios7-a dropdown-toggle"
|
||||
id="dropdownMenu2" data-toggle="dropdown">
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2" style="width: 180px;left: -5px;" id="notebookNavForNewNote">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 只为新建别人的笔记 -->
|
||||
<div id="newSharedNote" style="display: none">
|
||||
<a id="newSharedNoteBtn">
|
||||
<i class="fa fa-file-o"></i>
|
||||
{{msg . "newNote"}}
|
||||
</a>
|
||||
|
|
||||
<a id="newShareNoteMarkdownBtn" title="{{msg . "newMarkdown"}}">
|
||||
Markdown
|
||||
</a>
|
||||
- <span id="curNotebookForNewSharedNote" notebookId="" userId=""></span>
|
||||
<div class="dropdown" style="display: inline-block">
|
||||
<a class="ios7-a dropdown-toggle"
|
||||
id="dropdownMenu2" data-toggle="dropdown">
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu2" style="width: 180px;left: -5px;" id="notebookNavForNewSharedNote">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-left" style="line-height: 40px; margin-top: 10px; margin-left: 10px;" id="leanoteMsg">
|
||||
<span id="msg" style="display: inline-block;"></span>
|
||||
<img id="loading" style="visibility: hidden" src="/images/loading-a-20.gif" />
|
||||
{{if eq .userInfo.Email "demo@leanote.com"}}
|
||||
<span>
|
||||
{{msg . "demoRegister"}}
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="pull-left alert-warning" style="line-height: 20px; margin-top: 10px; margin-left: 0px; display: none" id="verifyMsg">
|
||||
您还没有验证邮箱, 验证邮件已发送至 {{.userInfo.Email}}.
|
||||
<br />
|
||||
<a class=".nowToActive">现在去验证</a> <a id="reSendActiveEmail">重新发送</a> <a id="wrongEmail">邮箱填错了?</a>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="pull-right" style="margin: 0 10px" id="myProfile">
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" style="line-height: 60px;">
|
||||
<!--
|
||||
<img src="images/avatar.png" style="height: 40px; border: 1px solid #ccc" />
|
||||
-->
|
||||
<span class="username">
|
||||
{{if .userInfo.UsernameRaw}}
|
||||
{{.userInfo.UsernameRaw}}
|
||||
{{else}}
|
||||
{{.userInfo.Username}}
|
||||
{{end}}
|
||||
</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu li-a" role="menu">
|
||||
<li role="presentation" id="setInfo">
|
||||
<i class="fa fa-info"></i>
|
||||
{{msg . "accountSetting"}}
|
||||
</li>
|
||||
<li role="presentation" id="setTheme">
|
||||
<i class="fa fa-sun-o"></i>
|
||||
{{msg . "themeSetting"}}
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation" id="yourSuggestions">
|
||||
<i class="fa fa-comment-o"></i>
|
||||
{{msg . "yourSuggestions"}}
|
||||
</li>
|
||||
-->
|
||||
<li role="presentation" onclick="logout()">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
{{msg . "logout"}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="margin: 0 10px" id="topNav">
|
||||
<a target="_blank" href="/blog/{{.userInfo.Username}}">
|
||||
{{msg . "myBlog"}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<ul id="setting" class="pull-right">
|
||||
<li class="dropdown messages">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span aria-hidden="true" class="icon se7en-flag"></span>
|
||||
<div class="sr-only">Messages</div>
|
||||
<p class="counter">3</p>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#"> c@c.com 共享了笔记给你 是否接受? </a></li>
|
||||
<li><a href="#"> d@c.com 共享了笔记给你 是否接受? </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown settings">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span aria-hidden="true" class="icon se7en-gear"></span>
|
||||
<div class="sr-only">Settings</div>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="settings-link blue"><span></span>Blue</a></li>
|
||||
<li><a class="settings-link green"><span></span>Green</a></li>
|
||||
<li><a class="settings-link orange"><span></span>Orange</a>
|
||||
</li>
|
||||
<li><a class="settings-link magenta"><span></span>Magenta</a>
|
||||
</li>
|
||||
<li><a class="settings-link gray"><span></span>Gray</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
-->
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
|
||||
<div id="mainContainer" class="clearfix">
|
||||
<div id="mainMask">
|
||||
<img src="/images/loading-30.gif" />
|
||||
<br />
|
||||
<br />
|
||||
loading...
|
||||
</div>
|
||||
<div id="leftNotebook">
|
||||
<div id="notebook">
|
||||
<div class="folderNote opened" id="myNotebooks">
|
||||
<div class="folderHeader clearfix">
|
||||
<i class="fa fa-book pull-left fa-left"></i>
|
||||
<span class="pull-left">
|
||||
{{msg . "notebook"}}
|
||||
</span>
|
||||
<div class="pull-right" id="addNotebookPlus" title="{{msg . "addNotebook"}}">
|
||||
<i class="fa fa-plus" title="{{msg . "addNotebook"}}"></i>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="folderBody" id="notebookList">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="folderNote closed" id="myTag">
|
||||
<div class="folderHeader">
|
||||
<i class="fa fa-bookmark fa-left"></i>
|
||||
<span>
|
||||
{{msg . "tag"}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="folderBody" id="tagNav">
|
||||
<li><a> <span class="label label-red">{{msg . "red"}}</span></a></li>
|
||||
<li><a> <span class="label label-blue">{{msg . "blue"}}</span></a></li>
|
||||
<li><a> <span class="label label-yellow">{{msg . "yellow"}}</span></a></li>
|
||||
<li><a> <span class="label label-green">{{msg . "green"}}</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="folderNote closed" id="">
|
||||
<div class="folderHeader">
|
||||
<i class="fa fa-user fa-left"></i>
|
||||
<span>
|
||||
共享
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="folderBody" id="shareNotebooks">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 缩小版 -->
|
||||
<div id="notebookMin">
|
||||
<!-- 这里隐藏, 不要 -->
|
||||
<div target="#notebookList" title="{{msg . "notebook"}}" class="minContainer">
|
||||
<i class="fa fa-book"></i>
|
||||
<ul class="dropdown-menu" id="minNotebookList">
|
||||
</ul>
|
||||
</div>
|
||||
<div target="#tagNav" title="{{msg . "myTag"}}" class="minContainer">
|
||||
<i class="fa fa-bookmark"></i>
|
||||
<ul class="dropdown-menu" id="minTagNav">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="minShareNotebooks">
|
||||
<!--
|
||||
<div class="minContainer" target="" title="">
|
||||
<i class="fa fa-user"></i>
|
||||
<ul class="dropdown-menu">
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
底下隐藏/展开
|
||||
<div id="notebookBottom">
|
||||
<i class="fa fa-angle-left" id="leftSwitcher"></i>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="noteSplit" id="notebookSplitter"></div>
|
||||
|
||||
<div id="noteAndEditor">
|
||||
<div id="noteList">
|
||||
<div class="clearfix" id="notesAndSort" style="position: relative">
|
||||
|
||||
<div class="pull-left">
|
||||
|
||||
<!-- 我的笔记本 -->
|
||||
<div class="dropdown" id="myNotebookNavForListNav">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<span id="curNotebookForListNote">{{msg . "all"}}</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<!-- 如果notebook过多, 则会产生滚动 -->
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
aria-labelledby="dropdownMenu1" style="left: 5px;" id="notebookNavForListNote">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 共享的笔记本 -->
|
||||
<div class="dropdown" id="sharedNotebookNavForListNav" style="display: none">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu2" data-toggle="dropdown">
|
||||
<span id="curSharedNotebookForListNote">{{msg . "all"}}</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
aria-labelledby="dropdownMenu2" style="left: 5px;" id="sharedNotebookNavForListNote">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pull-left" id="tagSearch" style="line-height: 38px">
|
||||
</div>
|
||||
<div id="sortType">
|
||||
<div class="dropdown">
|
||||
<a class="ios7-a dropdown-toggle" id="dropdownMenu1"
|
||||
data-toggle="dropdown">
|
||||
<!--
|
||||
<i class="fa fa-sort-alpha-asc">
|
||||
</i>Sort <i class="fa fa-angle-down"></i>
|
||||
-->
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu"
|
||||
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 role="menuitem" tabindex="-1"
|
||||
href="#">修改日期</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
href="#">标题</a></li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
href="#">Separated </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 笔记列表 -->
|
||||
<!-- wrap 为了slimScroll -->
|
||||
<div id="noteItemListWrap" style="position: absolute; left: 0; right: 0; top: 41px; bottom: 3px">
|
||||
<div id="noteItemList">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noteSplit" id="noteSplitter"></div>
|
||||
|
||||
<div id="note">
|
||||
<!-- 只读模式 -->
|
||||
<div id="noteRead">
|
||||
<div id="noteReadContainer">
|
||||
<div id="noteReadTop">
|
||||
<h2 id="noteReadTitle"></h2>
|
||||
<div class="clearfix">
|
||||
|
||||
<div class="pull-left">
|
||||
<i class="fa fa-bookmark-o"></i>
|
||||
<span id="noteReadTags"></span>
|
||||
</div>
|
||||
|
||||
<!-- 修改时间 -->
|
||||
<div class="pull-left" style="margin-left: 10px;">
|
||||
<i class="fa fa-calendar"></i>{{msg . "update"}}
|
||||
<span id="noteReadUpdatedTime"></span>
|
||||
</div>
|
||||
<!-- 修改时间 -->
|
||||
<div class="pull-left" style="margin-left: 10px;">
|
||||
<i class="fa fa-calendar"></i>{{msg . "create"}}
|
||||
<span id="noteReadCreatedTime"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="noteReadContent">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 遮罩, 为了resize3Columns用 -->
|
||||
<div id="noteMask"
|
||||
style="position: absolute; top: 0px; bottom: 0px; right: 0; left: 10px; z-index: -1"></div>
|
||||
<div id="editorMask">
|
||||
该笔记本下空空如也...何不
|
||||
<br />
|
||||
<div id="editorMaskBtns">
|
||||
<br />
|
||||
<a class="note">新建笔记</a>
|
||||
<a class="markdown">新建Markdown笔记</a>
|
||||
</div>
|
||||
<div id="editorMaskBtnsEmpty">
|
||||
Sorry, 这里不能添加笔记的.
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteTop">
|
||||
<!-- 左侧放tag, 右侧放按钮, 比如save, info, move, delete -->
|
||||
<div id="tool" class="clearfix">
|
||||
<!-- tag可以参考 mac的文件tag, 预定义一些颜色, 用户也可以自己输入-->
|
||||
|
||||
<!--
|
||||
<div class="pull-left" id="noteTitleDiv">
|
||||
<input name="noteTitle" id="noteTitle" value="" placeholder="无标题">
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="pull-left" id="tag">
|
||||
<div id="tags" style="display: inline-block; line-height: 25px;">
|
||||
</div>
|
||||
|
||||
<div class="dropdown" style="display: inline-block"
|
||||
id="tagDropdown">
|
||||
<i class="fa fa-bookmark-o"></i>
|
||||
<a
|
||||
class="metro-a dropdown-toggle" data-toggle="dropdown"
|
||||
id="addTagTrigger" style="cursor: text; padding-left: 0">
|
||||
{{msg . "clickAddTag"}}
|
||||
</a>
|
||||
<input type="text" id="addTagInput" />
|
||||
<ul class="dropdown-menu" role="menu" id="tagColor">
|
||||
<li role="presentation"><span class="label label-red">{{msg . "red"}}</span>
|
||||
</li>
|
||||
<li role="presentation"><span class="label label-blue">{{msg . "blue"}}</span>
|
||||
</li>
|
||||
<li role="presentation"><span class="label label-yellow">{{msg . "yellow"}}</span></li>
|
||||
<li role="presentation"><span class="label label-green">{{msg . "green"}}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ul class="pull-right" id="editorTool">
|
||||
<li><a class="ios7-a " id="saveBtn" title="ctrl+s"
|
||||
data-toggle="dropdown">{{msg . "save"}}</a></li>
|
||||
<li><a class="ios7-a " id="tipsBtn"
|
||||
data-toggle="dropdown">{{msg . "editorTips"}}</a></li>
|
||||
<li><a class="ios7-a " id="contentHistory"
|
||||
data-toggle="dropdown">{{msg . "history"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="noteTitleDiv">
|
||||
<input name="noteTitle" id="noteTitle" value="" placeholder="{{msg . "unTitled"}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="editor">
|
||||
<!-- 编辑器 -->
|
||||
<div id="mceToolbar" style="">
|
||||
<div id="popularToolbar"
|
||||
style="position: absolute; right: 30px; left: 0"></div>
|
||||
<a
|
||||
style="dispaly: block; position: absolute; cursor: pointer; right: 10px; padding: 3px 10px"
|
||||
id="moreBtn"> <i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div id="leanoteNav">
|
||||
<h1>
|
||||
<i class="fa fa-align-justify" title="文档导航"></i>
|
||||
<span>{{msg . "nav"}}</span>
|
||||
</h1>
|
||||
<div id="leanoteNavContent">
|
||||
</div>
|
||||
</div>
|
||||
<!-- 由此可以算高度 -->
|
||||
<div id="editorContent" name="editorContent">
|
||||
{{.noteContent}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mdEditor">
|
||||
<div id="wmd-button-bar" id="mdBar"></div>
|
||||
<!-- 为了scroll -->
|
||||
|
||||
<div class="clearfix" id="mdEditorPreview">
|
||||
<div id="left-column" class="pull-left">
|
||||
<div id="wmd-panel-editor" class="wmd-panel-editor">
|
||||
<textarea class="wmd-input theme" id="wmd-input" spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right-column" class="pull-right">
|
||||
<div id="wmd-panel-preview" class="wmd-panel-preview preview-container">
|
||||
<div id="wmd-preview" class="wmd-preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="md-section-helper"></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- mdEditor -->
|
||||
<!-- Hidden Popup Modal -->
|
||||
<div class="modal fade bs-modal-sm" id="editorDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="editorDialog-title">操作</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<i></i>
|
||||
</span>
|
||||
<input type="text" class="form-control" placeholder="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary" id="editorDialog-confirm">确认</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 弹出框 模板 -->
|
||||
<div class="modal fade bs-modal-sm" id="leanoteDialogRemote" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
</div>
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="leanoteDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">操作</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
内容区
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="sendRegisterEmailDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">邀请好友</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form role="form">
|
||||
<div class="form-group">
|
||||
<div id="registerEmailMsg" class="alert alert-warning" style="display: none">
|
||||
</div>
|
||||
<input type="hidden" id="toEmail"/>
|
||||
<label for="emailContent">邮件内容</label>
|
||||
<textarea class="form-control" id="emailContent">Hi, 我是李铁, leanote非常好用, 快来注册吧.</textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-success" id="registerEmailBtn">发送</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="modal fade bs-modal-sm" id="setThemeDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">主题设置</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<style>
|
||||
#themeForm td {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
#themeForm img {
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
<table id="themeForm">
|
||||
<tr>
|
||||
<td>
|
||||
<label>
|
||||
<img src="/images/slider/all.gif" height="100px">
|
||||
<br />
|
||||
<input type="radio" name="theme" value="default"> {{msg . "default"}}
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<label>
|
||||
<img src="/images/slider/all-simple.gif" height="100px">
|
||||
<br />
|
||||
<input type="radio" name="theme" value="simple"> {{msg . "simple"}}
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 编辑器提示 -->
|
||||
<div class="modal fade bs-modal-sm" id="tipsDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "editorTips"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{msg . "editorTipsInfo"}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<div class="modal fade bs-modal-sm" id="imageDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content" style="height: 460px;" >
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "uploadImage"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<iframe style="" height="360" src="" scrolling="no" frameBorder="0" width="99%"></iframe>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- 您的建议
|
||||
<div class="modal fade bs-modal-sm" id="suggestionsDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" class="modalTitle">{{msg . "yourSuggestions"}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="margin-bottom:20px;">
|
||||
{{msg . "suggestionsInfo"}}<br />
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning" id="suggestionMsg" style="display: none"> </div>
|
||||
<textarea style="width: 100%; height: 100px" id="suggestionTextarea" placeholder="{{msg . "suggestions"}}"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="suggestionBtn" class="btn btn-success" >{{msg . "submit"}}</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- modal 静态区域 -->
|
||||
<div class="display: hidden">
|
||||
|
||||
<!-- 长微博 -->
|
||||
<div id="html2ImageDialog">
|
||||
<div class="modal-body">
|
||||
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow: scroll;" class="weibo">
|
||||
<span class="text">
|
||||
leanote正在努力为你生成长微博...
|
||||
</span>
|
||||
<br />
|
||||
<img src="/images/loading-24.gif"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "cancel"}}</button>
|
||||
<button type="button" class="btn btn-success sendWeiboBtn disabled">{{msg . "send"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 长微博 -->
|
||||
<div id="reSendActiveEmailDialog">
|
||||
<div class="modal-body">
|
||||
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow: scroll;" class="weibo">
|
||||
<span class="text">
|
||||
<img src="/images/loading-24.gif"/>
|
||||
正在发送邮件到{{.userInfo.Email}}...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-success viewEmailBtn disabled">查看邮件</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 帐户设置 -->
|
||||
<div id="dialogSetInfo">
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="myTabs">
|
||||
<li><a href="#baseInfo" data-toggle="tab">{{msg . "basicInfo"}}</a></li>
|
||||
<li><a href="#emailInfo" data-toggle="tab">{{msg . "updateEmail"}}</a></li>
|
||||
<li><a href="#updatePwd" data-toggle="tab">{{msg . "updatePassword"}}</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="baseInfo">
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="username">用户名设置</label>
|
||||
<div class="alert alert-danger" id="usernameMsg" style="display: none"></div>
|
||||
<input type="text" class="form-control" id="username">
|
||||
你的邮箱是 {{.userInfo.Email}}, 可以再设置一个唯一的用户名.
|
||||
<br />
|
||||
用户名至少4位, 不可含特殊字符.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="usernameBtn" class="btn btn-success">提交</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="emailInfo">
|
||||
<form>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
当前邮箱为: <span id="curEmail">{{.userInfo.Email}}</span>
|
||||
{{if .userInfo.Verified}}
|
||||
已验证
|
||||
{{else}}
|
||||
未验证
|
||||
<a class="raw nowToActive">现在去验证</a>
|
||||
<a class="raw reSendActiveEmail">重新发送</a>
|
||||
{{end}}
|
||||
<br />
|
||||
<label for="email">修改邮箱</label>
|
||||
<div class="alert alert-danger" id="emailMsg" style="display: none"></div>
|
||||
<input type="text" class="form-control" id="email">
|
||||
邮箱修改后, 验证之后才有效, 验证之后新的邮箱地址将会作为登录帐号使用.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="emailBtn" class="btn btn-success">发送验证邮箱</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="updatePwd">
|
||||
<form>
|
||||
<table style="width: 80%">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="alert alert-danger" id="pwdMsg" style="display: none"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 80px">
|
||||
<label for="pwd">{{msg . "oldPassword"}}</label>
|
||||
<input type="password" class="form-control" id="oldPwd" name="oldPwd">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd">{{msg . "newPassword"}}</label>
|
||||
<input type="password" class="form-control" id="pwd" name="pwd">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="pwd2">{{msg . "password2"}}</label>
|
||||
<input type="password" class="form-control" id="pwd2" name="pwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<button id="pwdBtn" class="btn btn-success" style="width: 100%">{{msg . "submit"}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 账号设置, 是通过third 登录进来的 -->
|
||||
<div id="thirdDialogSetInfo">
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="thirdMyTabs">
|
||||
<li><a href="#accountInfo" data-toggle="tab">创建帐号</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="accountInfo">
|
||||
您现在使用的是第三方帐号登录leanote, 您也可以注册leanote帐号登录, 赶紧注册一个吧.
|
||||
<br />
|
||||
注册成功后仍可以使用第三方帐号登录leanote并管理您现有的笔记.
|
||||
<form>
|
||||
<div class="alert alert-danger" id="thirdAccountMsg" style="display: none"></div>
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdEmail">邮箱</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" class="form-control" id="thirdEmail">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdPwd">密码</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="password" class="form-control" id="thirdPwd">
|
||||
</td>
|
||||
<td>
|
||||
密码至少6位
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="thirdPwd2">重复密码</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="password" class="form-control" id="thirdPwd2">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button id="accountBtn" class="btn btn-success" style="width: 100%">提交</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide" id="copyDiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/jquery-1.9.0.min.js"></script>
|
||||
<script src="js/i18n/msg.{{.locale}}.js"></script>
|
||||
<script src="js/common-min.js"></script>
|
||||
<script>
|
||||
var UrlPrefix = "http://leanote.com"; // 为了发weibo
|
||||
var UserInfo = json({{.userInfoJson}});
|
||||
var notebooks = json({{.notebooks}});
|
||||
var shareNotebooks = json({{.shareNotebooks}});
|
||||
var sharedUserInfos = json({{.sharedUserInfos}});
|
||||
var notes = json({{.notes}});
|
||||
var noteContentJson = json({{.noteContentJson}});
|
||||
var tagsJson = json({{.tagsJson}});
|
||||
</script>
|
||||
|
||||
<!-- 渲染view -->
|
||||
<script src="/js/jQuery-slimScroll-1.3.0/jquery.slimscroll.js"></script>
|
||||
<script src="js/app/page-min.js"></script>
|
||||
|
||||
<script src="tinymce/tinymce.min.js"></script>
|
||||
<script src="js/jquery-cookie-min.js"></script>
|
||||
<script src="js/bootstrap-min.js"></script>
|
||||
<script src="js/app/note-min.js"></script>
|
||||
<script src="js/app/tag-min.js"></script>
|
||||
<script src="js/app/notebook-min.js"></script>
|
||||
<script src="js/app/share-min.js"></script>
|
||||
<script src="js/object_id-min.js"></script>
|
||||
<script src="js/ZeroClipboard/ZeroClipboard-min.js"></script>
|
||||
<script>
|
||||
Notebook.renderNotebooks(notebooks);
|
||||
Share.renderShareNotebooks(sharedUserInfos, shareNotebooks);
|
||||
|
||||
Note.renderNotes(notes);
|
||||
if(!isEmpty(notes)) {
|
||||
Note.changeNote(notes[0].NoteId);
|
||||
}
|
||||
|
||||
Note.setNoteCache(noteContentJson);
|
||||
Note.renderNoteContent(noteContentJson)
|
||||
|
||||
Tag.renderTagNav(tagsJson);
|
||||
</script>
|
||||
|
||||
<!-- mdEditor -->
|
||||
<link href="/public/mdeditor/editor/editor.css" rel="stylesheet">
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Converter-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Sanitizer-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/Markdown.Editor-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/pagedown/local/Markdown.local.zh-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/Markdown.Extra-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/underscore-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/scrollLink-min.js"></script>
|
||||
<!--mathjax-->
|
||||
<script type="text/x-mathjax-config">
|
||||
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||
</script>
|
||||
<script src="/public/mdeditor/editor/mathJax-min.js"></script>
|
||||
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<script src="/public/mdeditor/editor/jquery.waitforimages-min.js"></script>
|
||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||
<script src="/public/mdeditor/editor/editor-min.js"></script>
|
||||
<!-- mdEditor end -->
|
||||
|
||||
<!-- context-menu -->
|
||||
<link rel="stylesheet" href="/js/contextmenu/css/contextmenu.css" type="text/css" />
|
||||
<script src="/js/contextmenu/jquery.contextmenu-min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
{{set . "title" "Home"}}
|
||||
{{template "header.html" .}}
|
||||
|
||||
<header class="hero-unit" style="background-color:red">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="hero-text">
|
||||
<h1>Hello, life</h1>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
{{template "flash.html" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer.html" .}}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{template "home/header_box.html" .}}
|
||||
|
||||
<section id="box">
|
||||
<div>
|
||||
<h1>
|
||||
leanote | we got a error
|
||||
</h1>
|
||||
<form class="form-inline" id="boxForm">
|
||||
<p>
|
||||
Sorry, we can't get your infomation.
|
||||
<br />
|
||||
Please <a href="/login">Sign in</a> Or <a href="/register?email={{.email}}">Sign up</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,72 @@
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">分享 <b>{{.title}}</b></h4>
|
||||
</div>
|
||||
{{$noteOrNotebookId := .noteOrNotebookId}}
|
||||
|
||||
<div class="modal-body">
|
||||
<button class="btn btn-default" id="addShareNotebookBtn">添加分享</button>
|
||||
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
||||
<table class="table table-hover" id="shareNotebookTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>好友邮箱</th>
|
||||
<th>权限</th>
|
||||
<th>删除分享</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="tr1">
|
||||
<td>#</td>
|
||||
<td>
|
||||
<input id="friendsEmail" type="text" class="form-control" style="width: 200px" placeholder="好友邮箱">
|
||||
</td>
|
||||
<td>
|
||||
<label for="readPerm1"><input type="radio" name="perm1" checked="checked" value="0" id="readPerm1"> 只读</label>
|
||||
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> 可编辑</label>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-success" onclick="addShareNoteOrNotebook(1)">分享</button>
|
||||
<button class="btn btn-warning" onclick="deleteShareNoteOrNotebook(1)">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{range $i, $v := .noteOrNotebookShareUserInfos}}
|
||||
{{$toUserId := $v.ToUserId.Hex}}
|
||||
<tr>
|
||||
<td>{{add $i}}</td>
|
||||
<td>{{$v.Email}}</td>
|
||||
<td>
|
||||
{{if eq $v.Perm 0}}
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">只读</a>
|
||||
{{else}}
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">可编辑</a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
Share.dialogIsNote = {{.isNote}};
|
||||
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
||||
$(function() {
|
||||
setTimeout(function() {
|
||||
$("#tr1 #friendsEmail").focus();
|
||||
}, 500);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,84 @@
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="modalTitle">{{.note.Title}} 的分享状态</h4>
|
||||
</div>
|
||||
{{$noteId := .note.NoteId.Hex}}
|
||||
|
||||
<div class="modal-body">
|
||||
{{if .noteShareUserInfos }}
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Email</th>
|
||||
<th>权限</th>
|
||||
<th>删除分享</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $i, $v := .noteShareUserInfos}}
|
||||
{{$toUserId := $v.ToUserId.Hex}}
|
||||
<tr>
|
||||
<td>{{add $i}}</td>
|
||||
<td>{{$v.Email}}</td>
|
||||
<td>
|
||||
{{if eq $v.Perm 0}}
|
||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">只读</a>
|
||||
{{else}}
|
||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">可编辑</a>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" noteId="{{$noteId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
无分享信息
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
$(function() {
|
||||
$(".change-perm").click(function() {
|
||||
var self = this;
|
||||
var perm = $(this).attr("perm");
|
||||
var noteId = $(this).attr("noteId");
|
||||
var toUserId = $(this).attr("toUserId");
|
||||
var toHtml = "可编辑";
|
||||
var toPerm = "1";
|
||||
if(perm == "1") {
|
||||
toHtml = "只读";
|
||||
toPerm = "0";
|
||||
}
|
||||
ajaxGet("/share/UpdateShareNotePerm", {noteId: noteId, perm: toPerm, toUserId: toUserId}, function(ret) {
|
||||
if(ret) {
|
||||
$(self).html(toHtml);
|
||||
$(self).attr("perm", toPerm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(".delete-share").click(function() {
|
||||
var self = this;
|
||||
var noteId = $(this).attr("noteId");
|
||||
var toUserId = $(this).attr("toUserId");
|
||||
ajaxGet("/share/DeleteShareNote", {noteId: noteId, toUserId: toUserId}, function(ret) {
|
||||
if(ret) {
|
||||
$(self).parent().parent().remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,25 @@
|
||||
{{template "header.html" .}}
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<form class="form-inline" id="registerForm" style="width: 400px; margin: auto;">
|
||||
<h1 style="margin-top:10px">
|
||||
验证邮箱 -
|
||||
{{if .ok}}成功{{else}}失败{{end}}
|
||||
</h1>
|
||||
|
||||
您的邮箱 {{.email}} 验证
|
||||
{{if .ok}}成功{{else}}失败{{end}}
|
||||
|
||||
{{if .msg}}<br />{{.msg}}{{end}}
|
||||
|
||||
<br />
|
||||
<a href="/">回到我的笔记</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer.html"}}
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
{{template "header.html" .}}
|
||||
<div id="postsContainer">
|
||||
<div id="posts">
|
||||
<form class="form-inline" id="registerForm" style="width: 400px; margin: auto;">
|
||||
|
||||
<h1 style="margin-top:10px">
|
||||
验证邮箱 -
|
||||
{{if .ok}}成功{{else}}失败{{end}}
|
||||
</h1>
|
||||
|
||||
您的邮箱 {{.email}} 验证
|
||||
{{if .ok}}成功{{else}}失败{{end}}
|
||||
{{if .ok}}
|
||||
<br />
|
||||
您的新登录邮箱为 {{.email}}
|
||||
{{end}}
|
||||
|
||||
{{if .msg}}<br />{{.msg}}{{end}}
|
||||
|
||||
<br />
|
||||
<a href="/">回到我的笔记</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer.html"}}
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,76 @@
|
||||
#------------------------
|
||||
# leanote config
|
||||
#------------------------
|
||||
|
||||
http.port=80
|
||||
|
||||
site.url=http://leanote.com
|
||||
|
||||
# the administrator username
|
||||
adminUsername=admin
|
||||
|
||||
# mongdb
|
||||
db.host=localhost
|
||||
db.port=27017
|
||||
db.dbname=leanote # required
|
||||
db.username=root
|
||||
db.password=root123
|
||||
# or you can set the mongdb url
|
||||
# mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||
db.url=mongodb://root:root123@localhost:27017/leanote
|
||||
|
||||
# email
|
||||
email.host=
|
||||
email.port=25
|
||||
email.username=
|
||||
email.password=
|
||||
|
||||
#--------------------------------
|
||||
# revel config
|
||||
# for dev
|
||||
#--------------------------------
|
||||
|
||||
app.name=leanote
|
||||
app.secret=V85ZzBeTnzpsHyjQX4zukbQ8qqtju9y2aDM55VWxAH9Qop19poekx3xkcDVvrD0y
|
||||
http.addr=
|
||||
http.ssl=false
|
||||
cookie.httponly=false
|
||||
cookie.prefix=LEANOTE
|
||||
cookie.secure=false
|
||||
format.date=01/02/2006
|
||||
format.datetime=01/02/2006 15:04
|
||||
results.chunked=false
|
||||
|
||||
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
|
||||
|
||||
module.static=github.com/revel/revel/modules/static
|
||||
|
||||
[dev]
|
||||
mode.dev=true
|
||||
results.pretty=true
|
||||
watch=true
|
||||
|
||||
module.testrunner = github.com/revel/revel/modules/testrunner
|
||||
|
||||
log.trace.output = stderr
|
||||
log.info.output = stderr
|
||||
log.warn.output = stderr
|
||||
log.error.output = stderr
|
||||
|
||||
[prod]
|
||||
mode.dev=false
|
||||
results.pretty=false
|
||||
watch=false
|
||||
|
||||
module.testrunner =
|
||||
|
||||
log.trace.output = off
|
||||
log.info.output = off
|
||||
log.warn.output = %(app.name)s.log
|
||||
log.error.output = %(app.name)s.log
|
||||
@@ -0,0 +1,55 @@
|
||||
# Routes
|
||||
# This file defines all application routes (Higher priority routes first)
|
||||
# ~~~~
|
||||
|
||||
module:testrunner
|
||||
|
||||
# Home is My Blog
|
||||
Get / Blog.Index
|
||||
GET /note Note.index
|
||||
# leanote home
|
||||
GET /index Index.index
|
||||
|
||||
GET /login Auth.Login
|
||||
POST /doLogin Auth.doLogin
|
||||
GET /logout Auth.Logout
|
||||
Get /demo Auth.Demo
|
||||
|
||||
Get /register Auth.Register
|
||||
POST /doRegister Auth.DoRegister
|
||||
|
||||
GET /findPassword/:token Auth.FindPassword2
|
||||
GET /findPassword Auth.FindPassword
|
||||
POST /doFindPassword Auth.DoFindPassword
|
||||
POST /findPasswordUpdate Auth.FindPasswordUpdate
|
||||
|
||||
# mobile
|
||||
GET /mobile Mobile.Index
|
||||
|
||||
# blog
|
||||
# /blog/view/:noteId必须要放在/blog/:userId...之前
|
||||
GET /blog/searchBlog/:userId Blog.SearchBlog
|
||||
GET /blog/set Blog.Set
|
||||
GET /blog/aboutMe/:userId Blog.AboutMe
|
||||
POST /blog/setUserBlogBase Blog.SetUserBlogBase
|
||||
POST /blog/setUserBlogComment Blog.SetUserBlogComment
|
||||
POST /blog/setUserBlogStyle Blog.SetUserBlogStyle
|
||||
GET /blog/view/:noteId Blog.View
|
||||
GET /blog/:userId Blog.Index
|
||||
GET /blog/:userId/:notebookId Blog.Index
|
||||
GET /blog Blog.Index
|
||||
|
||||
# Map static resources from the /app/public folder to the /public path
|
||||
GET /favicon.ico Static.Serve("public/images/favicon.ico")
|
||||
GET /public/*filepath Static.Serve("public")
|
||||
GET /js/*filepath Static.Serve("public/js")
|
||||
GET /images/*filepath Static.Serve("public/images")
|
||||
GET /img/*filepath Static.Serve("public/img")
|
||||
GET /css/*filepath Static.Serve("public/css")
|
||||
GET /fonts/*filepath Static.Serve("public/fonts")
|
||||
GET /tinymce/*filepath Static.Serve("public/tinymce")
|
||||
#GET /plugins/*filepath Static.Serve("public/tinymce/plugins")
|
||||
GET /upload/*filepath Static.Serve("public/upload")
|
||||
|
||||
# common
|
||||
* /:controller/:action :controller.:action
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
# leanote
|
||||
moto=Not just a note!
|
||||
# 首页
|
||||
forgetPassword = Forget password?
|
||||
or=or
|
||||
try=Try it
|
||||
3th=Third-party accounts
|
||||
usernameOrEmail=Username or email
|
||||
password=Password
|
||||
home=Home
|
||||
aboutLeanote=About leanote
|
||||
suggestions=Suggestions
|
||||
yourSuggestions=Suggestions
|
||||
leanoteBlog=Blog
|
||||
knowledge=Knowledge
|
||||
knowledgeInfo=Use leanote as a note, manage your knowledge in leanote.
|
||||
share=Share
|
||||
shareInfo=Share your knowledge to your friends in leanote.
|
||||
cooperation=Cooperation
|
||||
cooperationInfo=Collaborate with friends to improve your knowledge.
|
||||
blog=Blog
|
||||
blogInfo=You can public your knowledge and leanote is your blog!
|
||||
suggestionsInfo=help us to improve our service.
|
||||
yourContact=Your contact
|
||||
emailOrOthers=Email or other contact way
|
||||
|
||||
hi=Hi
|
||||
welcomeUseLeanote=Welcome!
|
||||
myNote=Enter to my note
|
||||
curUser=Email
|
||||
|
||||
# form
|
||||
submit=submit
|
||||
register=Sign up
|
||||
login=Sign in
|
||||
password2=Confirm your password
|
||||
email=Email
|
||||
inputUsername=Username(email) is required
|
||||
inputEmail=Email is required
|
||||
wrongEmail=Wrong email
|
||||
wrongUsernameOrPassword=Wrong username or password
|
||||
inputPassword=Password is required
|
||||
wrongPassword=Wrong password
|
||||
logining=Sign in
|
||||
loginSuccess=login success
|
||||
ing=processing
|
||||
|
||||
# 注册
|
||||
registerSuccessAndRdirectToNote=register success, now redirect to my note...
|
||||
|
||||
# 找回密码
|
||||
passwordTips=The length is at least 6
|
||||
findPassword=Find password
|
||||
findPasswordSendEmailOver=We have already send the find password link to your email, please check out your email
|
||||
checkEmai=Check email
|
||||
findPasswordTimeout=time out
|
||||
reFindPassword=find password again
|
||||
updatePassword=Update password
|
||||
updatePasswordSuccessRedirectToLogin=update password success and redirect to login page...
|
||||
inputPassword2=Please input your password again
|
||||
confirmPassword=Please confirm your password
|
||||
notGoodPassword=Tt's not a good password, the length is at least 6
|
||||
|
||||
# 笔记主页
|
||||
myBlog=Blog
|
||||
history=Histories
|
||||
save=Save
|
||||
editorTips=Editor Tips
|
||||
editorTipsInfo=<h4>1. Short Cuts</h4>ctrl+shift+c Toggle code <br /> ctrl+shift+i Insert/edit image <h4>2. shift+enter Get out of current block</h4> eg. <img src="/images/outofcode.png" style="width: 90px"/> in this situation you can use shift+enter to get out of current code block.
|
||||
newNote=New Note
|
||||
newMarkdown=New Markdown Note
|
||||
clickAddTag=Click to add Tag
|
||||
notebook=Notebook
|
||||
myNotebook=My Notebook
|
||||
addNotebook=Add Notebook
|
||||
all=Newest
|
||||
trash=Trash
|
||||
unTitled=UnTitled
|
||||
defaultShare=Default sharing
|
||||
leftHidden=Hidden slide bar
|
||||
leftShow=Show slide bar
|
||||
nav=Note Nav
|
||||
|
||||
update=Update
|
||||
create=Create
|
||||
|
||||
demoRegister=您现在使用的是体验帐号, <a href="/register">立即注册?</a>
|
||||
|
||||
close=Close
|
||||
cancel=Cancel
|
||||
send=Send
|
||||
|
||||
# 标签
|
||||
tag=Tag
|
||||
myTag=My Tag
|
||||
red=red
|
||||
yellow=yellow
|
||||
blue=blue
|
||||
green=green
|
||||
|
||||
# 设置
|
||||
accountSetting=Account
|
||||
themeSetting=Theme
|
||||
logout=Logout
|
||||
basicInfo=Basic
|
||||
updateEmail=Update Email
|
||||
usernameSetting=Update Username
|
||||
oldPassword=Old Password
|
||||
newPassword=New Password
|
||||
|
||||
default=Default
|
||||
simple=Simple
|
||||
|
||||
# tinymce
|
||||
uploadImage=Upload Image
|
||||
|
||||
# error
|
||||
notFound=This page cann't found.
|
||||
|
||||
a=a
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
# leanote
|
||||
moto=不一样的笔记!
|
||||
|
||||
# 首页
|
||||
forgetPassword = 忘记密码?
|
||||
or=或
|
||||
try=体验一下
|
||||
3th=第三方登录
|
||||
usernameOrEmail=用户名或Email
|
||||
password=密码
|
||||
home=主页
|
||||
aboutLeanote=关于leanote
|
||||
suggestions=建议
|
||||
yourSuggestions=帮助完善leanote
|
||||
leanoteBlog=官方博客
|
||||
knowledge=知识
|
||||
knowledgeInfo=leanote是一个笔记, 你可以用它来管理自己的知识.
|
||||
share=分享
|
||||
shareInfo=你也可以将知识分享给你的好友.
|
||||
cooperation=协作
|
||||
cooperationInfo=分享给好友的同时也可以让你的好友和你一起来完善它.
|
||||
blog=博客
|
||||
blogInfo=将笔记公开, 让知识传播的更远!
|
||||
suggestionsInfo=帮助我们完善leanote
|
||||
yourContact=您的联系方式
|
||||
emailOrOthers=Email或其它联系方式
|
||||
|
||||
hi=Hi
|
||||
welcomeUseLeanote=欢迎使用leanote
|
||||
myNote=进入我的笔记
|
||||
curUser=当前登录帐户
|
||||
|
||||
# form
|
||||
submit=提交
|
||||
login=登录
|
||||
register=注册
|
||||
password2=确认密码
|
||||
email=Email
|
||||
inputUsername=请输入用户名或Email
|
||||
inputEmail=请输入Email
|
||||
wrongEmail=Email格式有误
|
||||
wrongUsernameOrPassword=用户名或密码有误
|
||||
inputPassword=请输入密码
|
||||
wrongPassword=密码有误
|
||||
logining=正在登录
|
||||
loginSuccess=登录成功, 正在跳转
|
||||
ing=正在处理
|
||||
|
||||
# 注册
|
||||
registerSuccessAndRdirectToNote=注册成功, 正在转至我的笔记...
|
||||
|
||||
# 找回密码
|
||||
passwordTips=密码至少6位
|
||||
findPassword=找回密码
|
||||
findPasswordSendEmailOver=已经将修改密码的链接发送到您的邮箱, 请查收邮件.
|
||||
checkEmai=查收邮箱
|
||||
updatePassword=修改密码
|
||||
findPasswordTimeout=链接已过期
|
||||
reFindPassword=重新找回密码
|
||||
updatePassword=修改密码
|
||||
updatePasswordSuccessRedirectToLogin=修改成功, 正在跳转到登录页
|
||||
inputPassword2=请再次输入密码
|
||||
confirmPassword=两次密码输入不一致
|
||||
notGoodPassword=密码至少6位
|
||||
|
||||
# 笔记主页
|
||||
myBlog=我的博客
|
||||
history=历史记录
|
||||
save=保存
|
||||
editorTips=帮助
|
||||
editorTipsInfo=<h4>1. 快捷键</h4>ctrl+shift+c 代码块切换 <br /> ctrl+shift+i 插入/修改图片<h4>2. shift+enter 跳出当前区域</h4>比如在代码块中<img src="/images/outofcode.png" style="width: 90px"/>按shift+enter可跳出当前代码块.
|
||||
newNote=新建笔记
|
||||
newMarkdown=新建Markdown笔记
|
||||
clickAddTag=点击添加标签
|
||||
notebook=笔记本
|
||||
myNotebook=我的笔记本
|
||||
addNotebook=添加笔记本
|
||||
all=最新
|
||||
trash=废纸篓
|
||||
unTitled=无标题
|
||||
defaultShare=默认共享
|
||||
leftHidden=隐藏左侧
|
||||
leftShow=展开左侧
|
||||
nav=文档导航
|
||||
|
||||
update=更新
|
||||
create=创建
|
||||
|
||||
demoRegister=您现在使用的是体验帐号, <a href="/register">立即注册?</a>
|
||||
|
||||
close=关闭
|
||||
cancel=取消
|
||||
send=发送
|
||||
|
||||
# 标签
|
||||
tag=标签
|
||||
myTag=我的标签
|
||||
red=红色
|
||||
yellow=黄色
|
||||
blue=蓝色
|
||||
green=绿色
|
||||
|
||||
# 设置
|
||||
accountSetting=帐户设置
|
||||
themeSetting=主题设置
|
||||
logout=退出
|
||||
basicInfo=基本信息
|
||||
updateEmail=修改Email
|
||||
usernameSetting=用户名设置
|
||||
oldPassword=旧密码
|
||||
newPassword=新密码
|
||||
|
||||
default=默认
|
||||
simple=简约
|
||||
|
||||
# tinymce
|
||||
uploadImage=上传图片
|
||||
|
||||
# error
|
||||
notFound=该页面不存在
|
||||
|
||||
# 必须要加这个, 奇怪
|
||||
[CN]
|
||||
Loaded 100 of 1085 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user