Beispiel #1
0
func RenderHome(ctx *webapp.Context) error {
	vars := make(map[string]interface{})
	data := MakeData(ctx, vars)
	data.Flags.Home = true
	err := ctx.Execute(mainTPL, &data)
	return err
}
Beispiel #2
0
func HandleGuard(c *webapp.Context) {
	var err error
	action := c.Request.FormValue("action")
	if action == "logout" {
		RevokeSessionTokon()
		c.Redirect("/guard", http.StatusFound)
		return
	}
	if c.Request.Method == "POST" {
		cert := c.Request.FormValue("certificate")
		if len(cert) == 0 {
			c.Redirect("/guard", http.StatusFound)
			return
		}
		if SHA256Sum(cert) == GetConfig().Certificate {
			cookie := new(http.Cookie)
			cookie.Name = "token"
			cookie.Path = "/"
			cookie.Value = GenerateSessionToken()
			http.SetCookie(c.Writer, cookie)
			c.Redirect("/writer", http.StatusFound)
		} else {
			err = RenderGuard(c, "Your password is not correct")
			if err != nil {
				c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
			}
		}
	} else if c.Request.Method == "GET" {
		err = RenderGuard(c, "")
		if err != nil {
			c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
		}
	}
}
Beispiel #3
0
func RenderWriterSettings(ctx *webapp.Context, msg string) error {
	vars := make(map[string]interface{})
	vars["Message"] = msg
	data := MakeData(ctx, vars)
	data.Flags.WriterSettings = true
	err := ctx.Execute(writerTPL, &data)
	return err
}
Beispiel #4
0
func RenderWriterEditor(ctx *webapp.Context, article *Article) error {
	vars := make(map[string]interface{})
	vars["Article"] = article
	data := MakeData(ctx, vars)
	data.Flags.WriterEditor = true
	err := ctx.Execute(editorTPL, &data)
	return err
}
Beispiel #5
0
func RenderFeedAtom(ctx *webapp.Context) error {
	vars := make(map[string]interface{})
	vars["Declaration"] = template.HTML("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
	data := MakeData(ctx, vars)
	data.Flags.Feed = true
	ctx.SetHeader("Content-Type", "application/atom+xml")
	err := ctx.Execute(feedTPL, &data)
	return err
}
Beispiel #6
0
func RenderSinglePage(ctx *webapp.Context, name string, lastMeta *CommentMetadata) error {
	vars := make(map[string]interface{})
	vars["Name"] = name
	vars["LastCommentMeta"] = lastMeta
	data := MakeData(ctx, vars)
	data.Flags.Single = true
	err := ctx.Execute(mainTPL, &data)
	return err
}
Beispiel #7
0
func RenderGuard(ctx *webapp.Context, hint string) error {
	vars := make(map[string]interface{})
	vars["Error"] = ""
	if len(hint) != 0 {
		vars["Error"] = hint
	}
	data := MakeData(ctx, vars)
	err := ctx.Execute(guardTPL, &data)
	return err
}
Beispiel #8
0
func HandleComment(c *webapp.Context) {
	if c.Request.Method == "POST" {
		IP := strings.Split(c.Request.RemoteAddr, ":")[0]
		comment := new(Comment)
		comment.Metadata.Name = UUID()
		comment.Metadata.IP = IP
		comment.Metadata.CreatedTime = time.Now().Unix()
		comment.Metadata.Author = strings.Trim(c.Request.FormValue("author"), " ")
		comment.Metadata.ArticleName = strings.Trim(c.Request.FormValue("article_name"), " /")
		comment.Metadata.UAgent = strings.Trim(c.Request.UserAgent(), " ")
		comment.Metadata.Email = strings.Trim(c.Request.FormValue("email"), " ")
		comment.Metadata.URL = strings.Trim(c.Request.FormValue("url"), " ")
		if strings.Index(comment.Metadata.URL, "http://") == -1 && strings.Index(comment.Metadata.URL, "https://") == -1 {
			comment.Metadata.URL = "http://" + comment.Metadata.URL
		}
		comment.Text = template.HTML(strings.Trim(c.Request.FormValue("text"), " "))

		var cookie *http.Cookie

		expires := time.Date(2099, time.November, 10, 23, 0, 0, 0, time.UTC)
		cookie = new(http.Cookie)
		cookie.Path = "/"
		cookie.Expires = expires
		cookie.Name = "author"
		cookie.Value = comment.Metadata.Author
		http.SetCookie(c.Writer, cookie)
		cookie.Name = "email"
		cookie.Value = comment.Metadata.Email
		http.SetCookie(c.Writer, cookie)
		cookie.Name = "url"
		cookie.Value = comment.Metadata.URL
		http.SetCookie(c.Writer, cookie)

		// verify the form data
		if len(comment.Metadata.Author) == 0 || len(comment.Metadata.Email) < 3 || len(comment.Text) < 3 || len(comment.Metadata.Author) > 20 || len(comment.Metadata.Email) > 32 {
			c.Redirect("/"+comment.Metadata.ArticleName+"#respond", http.StatusFound)
			return
		}
		if !webapp.CheckEmailForm(comment.Metadata.Email) || (0 < len(comment.Metadata.URL) && !webapp.CheckURLForm(comment.Metadata.URL)) {
			c.Redirect("/"+comment.Metadata.ArticleName+"#respond", http.StatusFound)
			return
		}
		if !TattooDB.Has(comment.Metadata.ArticleName) {
			c.Redirect("/"+comment.Metadata.ArticleName+"#respond", http.StatusFound)
			return
		}
		comment.Text = template.HTML(webapp.TransformTags(string(comment.Text)))
		comment.Metadata.EmailHash = MD5Sum(comment.Metadata.Email)
		TattooDB.AddComment(comment)
		TattooDB.PrependCommentTimeline(comment)
		c.Redirect("/"+comment.Metadata.ArticleName+"#comment_"+comment.Metadata.Name, http.StatusFound)
	} else {
		c.Redirect("/"+c.Request.FormValue("article_name"), http.StatusFound)
	}
}
Beispiel #9
0
func RenderSinglePage(ctx *webapp.Context, name string, lastMeta *CommentMetadata) error {
	vars := make(map[string]interface{})
	vars["Name"] = name
	vars["LastCommentMeta"] = lastMeta
	data := MakeData(ctx, vars)
	meta, _ := TattooDB.GetMetadata(name)
	if meta.IsPage {
		data.Flags.Page = true
	} else {
		data.Flags.Single = true
	}
	err := ctx.Execute(mainTPL, &data)
	return err
}
Beispiel #10
0
func HandleSingle(c *webapp.Context, pagename string) {
	if TattooDB.Has(pagename) {
		lastMeta := GetLastCommentMetadata(c)
		err := RenderSinglePage(c, pagename, lastMeta)
		if err != nil {
			c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
		}
		meta, err := TattooDB.GetMetadata(pagename)
		if err == nil {
			meta.Hits += 1
			TattooDB.UpdateMetadata(meta)
		}
	} else {
		Render404page(c, NOT_FOUND_MESSAGE)
	}
}
Beispiel #11
0
func Render404page(ctx *webapp.Context, msg string) error {
	if notFoundTPL != nil {
		vars := make(map[string]interface{})
		vars["Message"] = msg
		vars["URL"] = ctx.Request.RequestURI
		vars["Referer"] = ctx.Request.Referer()
		data := MakeData(ctx, vars)
		err := ctx.Execute(notFoundTPL, &data)
		return err
	} else {
		ctx.Error(fmt.Sprintf("%s: %s", webapp.ErrNotFound, msg),
			http.StatusNotFound)
		return nil
	}
	return nil
}
Beispiel #12
0
func HandleTag(c *webapp.Context, tag string) {
	tag = strings.Trim(tag, " ")
	if !TattooDB.HasTag(tag) {
		Render404page(c, NOT_FOUND_MESSAGE)
	}
	pos, _ := strconv.Atoi(c.Request.FormValue("pos"))
	if pos > TattooDB.GetTagArticleCount(tag)-1 {
		c.Redirect("/", http.StatusFound)
		return
	}
	err := RenderTagPage(c, pos, tag)
	if err != nil {
		c.Error(fmt.Sprintf("%s: %s",
			webapp.ErrInternalServerError, err),
			http.StatusInternalServerError)
	}
}
Beispiel #13
0
func RenderWriterComments(ctx *webapp.Context, offset int) error {
	vars := make(map[string]interface{})
	vars["Offset"] = offset

	vars["AtBegin"] = false
	vars["AtEnd"] = false
	vars["Offset"] = offset
	if TattooDB.GetCommentCount()-1-offset < 20 {
		vars["AtEnd"] = true
	}
	if offset < 20 {
		vars["AtBegin"] = true
	}
	data := MakeData(ctx, vars)
	data.Flags.WriterComments = true
	err := ctx.Execute(writerTPL, &data)
	return err
}
Beispiel #14
0
func RenderArticles(ctx *webapp.Context, offset int) error {
	vars := make(map[string]interface{})
	vars["Offset"] = offset

	vars["AtBegin"] = false
	vars["AtEnd"] = false
	vars["Offset"] = offset
	if TattooDB.GetArticleCount()-1-offset < GetConfig().TimelineCount {
		vars["AtEnd"] = true
	}
	if offset < GetConfig().TimelineCount {
		vars["AtBegin"] = true
	}
	data := MakeData(ctx, vars)
	data.Flags.Articles = true
	err := ctx.Execute(mainTPL, &data)
	return err
}
Beispiel #15
0
func HandleUpdateSystemSettings(c *webapp.Context) {
	portStr := strings.Trim(c.Request.FormValue("port"), " ")
	certificate := strings.Trim(c.Request.FormValue("certificate"), " ")
	sitebase := strings.Trim(c.Request.FormValue("sitebase"), " ")
	siteurl := strings.Trim(c.Request.FormValue("siteurl"), " ")
	sitetitle := strings.Trim(c.Request.FormValue("sitetitle"), " ")
	sitesubtitle := strings.Trim(c.Request.FormValue("sitesubtitle"), " ")
	path := strings.Trim(c.Request.FormValue("path"), " ")
	author := strings.Trim(c.Request.FormValue("author"), " ")
	timelinecountStr := strings.Trim(c.Request.FormValue("timelinecount"), " ")
	theme := strings.Trim(c.Request.FormValue("theme"), " ")
	// verify
	port, err := strconv.Atoi(portStr)
	if err != nil {
		RenderWriterSettings(c, "Port should be a positive integer!")
		return
	}
	timelinecount, err := strconv.Atoi(timelinecountStr)
	if err != nil {
		RenderWriterSettings(c, "Timeline Count should be a positive integer!")
		return
	}
	if err := LoadTheme(c.Application, theme); err != nil {
		RenderWriterSettings(c, fmt.Sprintf("Failed to load theme '%v': %v", theme, err))
		return
	}
	var newConfig Config
	newConfig.Port = port
	newConfig.Certificate = certificate
	newConfig.SiteBase = sitebase
	newConfig.SiteURL = siteurl
	newConfig.SiteTitle = sitetitle
	newConfig.SiteSubTitle = sitesubtitle
	newConfig.Path = path
	newConfig.AuthorName = author
	newConfig.TimelineCount = timelinecount
	newConfig.ThemeName = theme
	cfg := GetConfig()
	cfg.Update(&newConfig)
	cfg.Save()
	c.Redirect("/writer/settings", http.StatusFound)
}
Beispiel #16
0
func HandleFeed(c *webapp.Context, pathLevels []string) {
	if len(pathLevels) < 2 {
		c.Redirect("/feed/atom", http.StatusFound)
		return
	}
	if pathLevels[1] == "atom" {
		var meta *ArticleMetadata
		var err error
		if len(TattooDB.ArticleTimeline) != 0 {
			meta, err = TattooDB.GetMetadata(TattooDB.ArticleTimeline[0])
			if err == nil {
				TattooDB.SetVar("LastUpdatedTime", TimeRFC3339(meta.ModifiedTime))
			}
		}
		err = RenderFeedAtom(c)
		if err != nil {
			c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
			return
		}
	}
}
Beispiel #17
0
func RenderTagPage(ctx *webapp.Context, offset int, tag string) error {
	vars := make(map[string]interface{})
	tag = strings.Trim(tag, " ")
	if !TattooDB.HasTag(tag) {
		return errors.New(webapp.ErrNotFound)
	}

	vars["Offset"] = offset
	vars["Tag"] = tag
	vars["AtBegin"] = false
	vars["AtEnd"] = false
	if TattooDB.GetTagArticleCount(tag)-1-offset < GetConfig().TimelineCount {
		vars["AtEnd"] = true
	}
	if offset < GetConfig().TimelineCount {
		vars["AtBegin"] = true
	}
	data := MakeData(ctx, vars)
	data.Flags.Tag = true
	err := ctx.Execute(mainTPL, &data)
	return err
}
Beispiel #18
0
func HandleArticles(c *webapp.Context) {
	pos, _ := strconv.Atoi(c.Request.FormValue("pos"))
	if pos > TattooDB.GetArticleCount()-1 {
		if HasTemplate("HOME") {
			c.Redirect("/post/", http.StatusFound)
		} else {
			c.Redirect("/", http.StatusFound)
		}
		return
	}
	err := RenderArticles(c, pos)
	if err != nil {
		c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
	}
}
Beispiel #19
0
func HandleWriter(c *webapp.Context, pathLevels []string) {
	if ok := isAuthorized(c); !ok {
		c.Redirect("/guard", http.StatusFound)
		return
	}
	if c.Request.Method == "GET" {
		var err error
		if len(pathLevels) < 2 {
			c.Redirect("/writer/overview", http.StatusFound)
			return
		}
		if pathLevels[1] == "overview" {
			pos, _ := strconv.Atoi(c.Request.FormValue("pos"))
			err = RenderWriterOverview(c, pos)
		} else if pathLevels[1] == "pages" {
			pos, _ := strconv.Atoi(c.Request.FormValue("pos"))
			err = RenderWriterPages(c, pos)
		} else if pathLevels[1] == "comments" {
			pos, _ := strconv.Atoi(c.Request.FormValue("pos"))
			if pos > TattooDB.GetCommentCount()-1 {
				c.Redirect("/writer/comments", http.StatusFound)
				return
			}
			err = RenderWriterComments(c, pos)
		} else if pathLevels[1] == "settings" {
			err = RenderWriterSettings(c, "")
		} else if pathLevels[1] == "edit" {
			var article *Article = new(Article)
			var meta *ArticleMetadata = new(ArticleMetadata)
			var source []byte
			if len(pathLevels) >= 3 {
				name := strings.ToLower(url.QueryEscape(pathLevels[2]))
				meta, err = TattooDB.GetMetadata(name)
				if err == nil {
					source, err = TattooDB.GetArticleSource(name)
					if err == nil {
						article.Metadata = *meta
						article.Text = template.HTML(string(source))
					}
				}
			} else {
				article = new(Article)
			}
			err = RenderWriterEditor(c, article)
		} else if pathLevels[1] == "delete" {
			if len(pathLevels) >= 3 {
				name := strings.ToLower(url.QueryEscape(pathLevels[2]))
				if TattooDB.Has(name) {
					TattooDB.DeleteArticleTagIndex(name)
					TattooDB.DeleteArticle(name)
					TattooDB.DeleteMetadata(name)
					TattooDB.DeleteComments(name)
					TattooDB.Dump()
					TattooDB.RebuildTimeline()
					TattooDB.RebuildCommentTimeline()
				}
			}
			c.Redirect("/writer", http.StatusFound)
		} else if pathLevels[1] == "delete_comment" {
			if len(pathLevels) >= 3 {
				name := strings.ToLower(url.QueryEscape(pathLevels[2]))
				if TattooDB.HasComment(name) {
					TattooDB.DeleteComment(name)
					TattooDB.RebuildCommentTimeline()
				}
			}
			c.Redirect("/writer/comments", http.StatusFound)
		} else {
			Render404page(c, NOT_FOUND_MESSAGE)
		}
		if err != nil {
			c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
		}
	} else if c.Request.Method == "POST" {
		if pathLevels[1] == "update" {
			HandleUpdateArticle(c)
		} else if pathLevels[1] == "settings" {
			HandleUpdateSystemSettings(c)
		} else {
			c.Redirect("/writer", http.StatusFound)
			return
		}
	}
}
Beispiel #20
0
func HandleHome(c *webapp.Context) {
	err := RenderHome(c)
	if err != nil {
		c.Error(fmt.Sprintf("%s: %s", webapp.ErrInternalServerError, err), http.StatusInternalServerError)
	}
}
Beispiel #21
0
func HandleUpdateArticle(c *webapp.Context) {
	isNew := false
	isRename := false
	origName := strings.Trim(c.Request.FormValue("orig_name"), " ")
	var err error
	var meta *ArticleMetadata
	article := new(Article)
	article.Metadata.Title = strings.Trim(c.Request.FormValue("title"), " ")
	article.Metadata.Name = strings.ToLower(strings.Trim(c.Request.FormValue("url"), " "))
	article.Metadata.FeaturedPicURL = strings.Trim(c.Request.FormValue("fpic"), " ")
	article.Metadata.Summary = strings.Trim(c.Request.FormValue("sum"), " ")
	article.Metadata.IsPage, err = strconv.ParseBool(c.Request.FormValue("ispage"))
	if err != nil {
		article.Metadata.IsPage = false
	}
	article.Metadata.Author = GetConfig().AuthorName
	article.Metadata.ModifiedTime = time.Now().Unix()
	article.Text = template.HTML(c.Request.FormValue("text"))

	if len(origName) == 0 {
		isNew = true
	} else if origName != article.Metadata.Name {
		isRename = true
	}
	if isNew {
		article.Metadata.CreatedTime = article.Metadata.ModifiedTime
	} else {
		meta, err = TattooDB.GetMetadata(origName)
		if err == nil {
			article.Metadata.CreatedTime = meta.CreatedTime
			article.Metadata.Hits = meta.Hits
		}
	}
	// check if the name is avaliable.
	meta, err = TattooDB.GetMetadata(article.Metadata.Name)
	if isNew && err == nil {
		article.Metadata.Name = ""
		err = RenderWriterEditor(c, article)
		return
	}
	// verify the form data
	if len(article.Metadata.Title) == 0 || len(article.Metadata.Name) == 0 {
		c.Redirect("/writer/edit", http.StatusFound)
		return
	}
	// handle tags
	tags := strings.Split(c.Request.FormValue("tags"), ",")
	tags_tmp := make(map[string]int)
	for _, t := range tags {
		tag := strings.ToLower(strings.Trim(t, " "))
		if len(tag) == 0 {
			continue
		}
		tags_tmp[tag] = 1
	}
	// remove duplication
	article.Metadata.Tags = make([]string, 0)
	for t := range tags_tmp {
		article.Metadata.Tags = append(article.Metadata.Tags, t)
	}
	// update tag index
	TattooDB.DeleteArticleTagIndex(article.Metadata.Name)
	TattooDB.UpdateArticleTagIndex(article.Metadata.Name, article.Metadata.Tags)
	// update metadata
	TattooDB.UpdateMetadata(&article.Metadata)
	TattooDB.UpdateArticle(article.Metadata.Name, []byte(string(article.Text)))
	if isRename {
		TattooDB.DeleteArticleTagIndex(origName)
		TattooDB.DeleteMetadata(origName)
		TattooDB.DeleteArticle(origName)
		TattooDB.RenameComments(origName, article.Metadata.Name)
	}
	TattooDB.Dump()
	if isNew || isRename {
		TattooDB.RebuildTimeline()
	}
	c.Redirect("/writer/overview", http.StatusFound)
	return
}