示例#1
0
func init() {
	blog_config, err := config.ReadJsonFile("blarg_config.json")
	if err != nil {
		panic(err)
	}

	root := config.Stringify(blog_config["blog_root"]) // test for default

	m := pat.New()

	handle_method := func(method string, urlpattern string, handler http.HandlerFunc) {
		m.Add(method, root+urlpattern, handler)
	}

	handle := func(urlpattern string, handler http.HandlerFunc) {
		m.Get(root+urlpattern, handler)
	}

	handle("list/:page/:invalid", http.NotFound)
	handle("list/:page", layout.IndexPageHandler(blog_config, "list"))
	handle("list/", layout.IndexListHandler(blog_config, "list"))
	handle("index/", layout.IndexListHandler(blog_config, "list"))

	handle("article/:name/:invalid", http.NotFound)
	handle("article/:name", layout.GetArticle(blog_config, "article"))
	handle("article/", http.NotFound)

	handle("label/:label/:page/:invalid", http.NotFound)
	handle("label/:label/:page", layout.LabelPage(blog_config, "label"))
	handle("label/:label", layout.LabelList(blog_config, "label"))
	handle("label/", http.NotFound)

	handle("admin/edit/:name/:invalid", http.NotFound)
	handle("admin/edit/:name", layout.EditPost(blog_config))
	handle("admin/edit/", layout.EditPost(blog_config))

	handle("admin/dump/all.json/:invalid", http.NotFound)
	handle("admin/dump/all.json", layout.JSONAllEntries(blog_config))
	handle("admin/dump/:invalid", http.NotFound)

	handle("admin/gettext/:name/:invalid", http.NotFound)
	handle("admin/gettext/:name", layout.GetPostText(blog_config))
	handle_method("POST", "admin/render/:invalid", http.NotFound)
	handle_method("POST", "admin/render/", layout.RenderPost(blog_config))

	// pat seems to interfere with the blobstore's MIME parsing
	http.HandleFunc(root+"admin/post", layout.Save(blog_config))

	handle("sitemap.xml", layout.GetSitemap(blog_config))

	m.Get("/index.rss", http.HandlerFunc(layout.GetRSS(blog_config)))

	// matching on / will match all URLs
	// so you have to catch invalid top-level URLs first

	handle(":invalid/", http.NotFound)
	handle("", layout.IndexListHandler(blog_config, "list"))

	http.Handle(root, m)
}
示例#2
0
func entrybar(blog_config map[string]interface{}, w http.ResponseWriter, req *http.Request) {
	template_dir := "templates/"
	appcontext := appengine.NewContext(req)
	myurl, err := realhostname(req, appcontext)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	scheme := "http://"
	if req.TLS != nil {
		scheme = "https://"
	}

	urlprefix := scheme + myurl + config.Stringify(blog_config["blog_root"])

	postchan := make(chan post.Post, 16)
	errchan := make(chan error)
	go post.ExecuteQuery(appcontext, post.GetAllPosts(), -1, -1, func(post.Post) bool { return true }, postchan, errchan)

	for p := range postchan {
		context := map[string]interface{}{"url": urlprefix + "article/" + p.StickyUrl,
			"lastmod_date": p.Postdate.Format("2006-01-02")}
		total_con := config.Stringify_map(config.Merge(blog_config, context))
		c := mustache.RenderFile(template_dir+"edit_entrybar.html.mustache", total_con)
		io.WriteString(w, c)
	}

	err, ok := <-errchan
	if ok {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
示例#3
0
func labels(tags []string, blog_config map[string]interface{}) string {
	root := config.Stringify(blog_config["blog_root"])
	labels := bytes.NewBufferString("")

	for _, l := range tags {
		if l != "visible" {
			fmt.Fprintf(labels, "<a href=\"%slabel/%s\">%s</a> ", root, l, l)
		}
	}

	return string(labels.Bytes())
}
示例#4
0
func std_layout(blog_config map[string]interface{}, f func(w http.ResponseWriter, req *http.Request)) func(w http.ResponseWriter, req *http.Request) {

	p := func(w http.ResponseWriter, req *http.Request) {
		appcontext := appengine.NewContext(req)
		myurl, err := realhostname(req, appcontext)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		scheme := "http://"
		if req.TLS != nil {
			scheme = "https://"
		}
		context := map[string]interface{}{"app_url": scheme + myurl + config.Stringify(blog_config["blog_root"])}

		bloginfo := config.Stringify_map(config.Merge(blog_config, context))

		start := time.Now()
		template_dir := "templates/"

		h := mustache.RenderFile(template_dir+"header.html.mustache", bloginfo)
		io.WriteString(w, h)

		f(w, req)

		sidebar(w, req, blog_config)

		delta := time.Since(start).Seconds()

		timing := map[string]interface{}{"timing": fmt.Sprintf("%0.2fs", delta)}
		if delta > 0.100 {
			timing["slow_code"] = "true"
		}

		u := user.Current(appcontext)
		if u != nil {
			logout, err := user.LogoutURL(appcontext, "/")
			if err != nil {
				http.Error(w, "error generating logout URL!", http.StatusInternalServerError)
				appcontext.Errorf("user.LogoutURL: %v", err)
				return
			}
			timing["me"] = fmt.Sprintf("%s", u)
			timing["logout"] = logout
		}

		bloginfo = config.Stringify_map(config.Merge(blog_config, timing))
		f := mustache.RenderFile(template_dir+"footer.html.mustache", bloginfo)
		io.WriteString(w, f)
	}

	return p
}
示例#5
0
func getLimit(blog_config map[string]interface{}) (int, error) {
	var limit int
	if limtext, ok := blog_config["post_limit"]; ok {
		_, err := fmt.Sscanf(config.Stringify(limtext), "%d", &limit)
		if err != nil {
			return 0, err
		}
	} else {
		limit = 20
	}

	return limit, nil
}
示例#6
0
func GetSitemap(blog_config map[string]interface{}) func(w http.ResponseWriter, req *http.Request) {
	template_dir := "templates/"
	l := func(w http.ResponseWriter, req *http.Request) {
		appcontext := appengine.NewContext(req)

		myurl, err := realhostname(req, appcontext)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		scheme := "http://"
		if req.TLS != nil {
			scheme = "https://"
		}

		urlprefix := scheme + myurl + config.Stringify(blog_config["blog_root"])

		postchan := make(chan post.Post, 16)
		errchan := make(chan error)
		go post.ExecuteQuery(appcontext, post.GetAllPosts(), -1, -1, post.NullFilter, postchan, errchan)

		entries := bytes.NewBufferString("")

		me_context := map[string]interface{}{"url": urlprefix,
			"lastmod_date": post.GetLatestDate(appcontext).Format("2006-01-02")}
		me_total_con := config.Stringify_map(config.Merge(blog_config, me_context))
		me_c := mustache.RenderFile(template_dir+"sitemap_entry.mustache", me_total_con)
		io.WriteString(entries, me_c)
		for p := range postchan {
			context := map[string]interface{}{"url": urlprefix + "article/" + p.StickyUrl,
				"lastmod_date": p.Postdate.Format("2006-01-02")}
			total_con := config.Stringify_map(config.Merge(blog_config, context))
			c := mustache.RenderFile(template_dir+"sitemap_entry.mustache", total_con)
			io.WriteString(entries, c)
		}

		err, ok := <-errchan
		if ok {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		context := map[string]interface{}{"content": entries}
		total_con := config.Stringify_map(config.Merge(blog_config, context))
		c := mustache.RenderFile(template_dir+"sitemap.mustache", total_con)
		io.WriteString(w, c)
	}
	return l
}
示例#7
0
func list(w http.ResponseWriter, req *http.Request, blog_config map[string]interface{}, url_stem string, offset int, limit int, keygen func(appengine.Context) ([]*datastore.Key, error)) {

	appcontext := appengine.NewContext(req)
	template_dir := "templates/"
	postchan := make(chan post.FullPost, 16)
	errchan := make(chan error)

	keys, err := keygen(appcontext)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	idx := len(keys)

	pages := idx / limit
	if (idx % limit) > 0 {
		pages += 1
	}

	curpage := offset / limit

	if idx < 1 {
		io.WriteString(w, fmt.Sprintf("<div class=\"entry\"><p>no posts found :(</p></div>"))
	} else {
		//go post.ExecuteQuery(appcontext, query, offset, limit, postchan, errchan)
		go post.GetPosts(appcontext, keys, offset, limit, postchan, errchan)

		myurl, err := realhostname(req, appcontext)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		scheme := "http://"
		if req.TLS != nil {
			scheme = "https://"
		}

		urlprefix := scheme + myurl + config.Stringify(blog_config["blog_root"])

		for p := range postchan {
			con := bytes.NewBuffer(blackfriday.MarkdownCommon(bytes.NewBufferString(p.Content).Bytes())).String()
			context := map[string]interface{}{"c": con, "labels": labels(p.Post.Tags, blog_config),
				"link_to_entry": urlprefix + "article/" + p.Post.StickyUrl,
				"post_date":     p.Post.Postdate.Format("Jan 02 2006"),
				"post_title":    p.Post.Title}
			total_con := config.Stringify_map(config.Merge(blog_config, context))
			c := mustache.RenderFile(template_dir+"list_entry.html.mustache", total_con)
			io.WriteString(w, c)
		}

		err, ok := <-errchan
		if ok {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		context := map[string]interface{}{}

		root := config.Stringify(blog_config["blog_root"])

		context["prev_page"] = "&lt;&lt; prev"
		context["next_page"] = "next &gt;&gt;"

		if pages > 1 {
			context["pb"] = "true"
		}
		if curpage > 0 {
			context["prev_page"] = fmt.Sprintf("<a href=\"%v%v/%v\">&lt;&lt; prev</a>", root, url_stem, curpage-1)
		}
		if curpage < (pages - 1) {
			context["next_page"] = fmt.Sprintf("<a href=\"%v%v/%v\">next &gt;&gt;</a>", root, url_stem, curpage+1)
		}

		total_con := config.Stringify_map(config.Merge(blog_config, context))
		c := mustache.RenderFile(template_dir+"list.html.mustache", total_con)
		io.WriteString(w, c)
	}
}
示例#8
0
func GetRSS(blog_config map[string]interface{}) func(w http.ResponseWriter, req *http.Request) {
	template_dir := "templates/"
	l := func(w http.ResponseWriter, req *http.Request) {
		limit, err := getLimit(blog_config)
		if err != nil {
			panic(err)
		}

		appcontext := appengine.NewContext(req)

		myurl, err := realhostname(req, appcontext)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		scheme := "http://"
		if req.TLS != nil {
			scheme = "https://"
		}

		urlprefix := scheme + myurl + config.Stringify(blog_config["blog_root"])

		keys, err := post.GetPostsMatchingTag(appcontext, "visible")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		idx := len(keys)

		offset := 0

		entries := new(bytes.Buffer)
		if idx >= 1 {
			postchan := make(chan post.FullPost, 16)
			errchan := make(chan error)

			go post.GetPosts(appcontext, keys, offset, limit, postchan, errchan)
			for p := range postchan {
				con := bytes.NewBuffer(blackfriday.MarkdownCommon(bytes.NewBufferString(p.Content).Bytes())).String()
				context := map[string]interface{}{"c": con,
					"link_to_entry": urlprefix + "article/" + p.Post.StickyUrl,
					"post_date":     p.Post.Postdate.Format("Jan 02 2006"),
					"post_title":    p.Post.Title}
				total_con := config.Stringify_map(config.Merge(blog_config, context))
				c := mustache.RenderFile(template_dir+"rss_entry.html.mustache", total_con)
				io.WriteString(entries, c)
			}
			err, ok := <-errchan
			if ok {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		}

		context := map[string]interface{}{
			"lastmod_date": post.GetLatestDate(appcontext).Format("2006-01-02"),
			"content":      entries,
		}

		total_con := config.Stringify_map(config.Merge(blog_config, context))
		c := mustache.RenderFile(template_dir+"rss.mustache", total_con)
		io.WriteString(w, c)
	}
	return l
}
示例#9
0
func GetArticle(blog_config map[string]interface{}, url_stem string) func(w http.ResponseWriter, req *http.Request) {
	template_dir := "templates/"
	l := func(w http.ResponseWriter, req *http.Request) {
		appcontext := appengine.NewContext(req)
		query := post.GetPostsMatchingUrl(req.URL.Query().Get(":name"))
		idx, err := post.GetCount(appcontext, query)

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		if idx < 1 {
			http.Error(w, err.Error(), http.StatusNotFound)
			io.WriteString(w, fmt.Sprintf("<div class=\"entry\"><p>no posts found :(</p></div>"))
			return
		} else {

			myurl, err := realhostname(req, appcontext)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			scheme := "http://"
			if req.TLS != nil {
				scheme = "https://"
			}

			urlprefix := scheme + myurl + config.Stringify(blog_config["blog_root"])

			var ps []post.Post
			keys, err := query.GetAll(appcontext, &ps)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			p := ps[0]
			tags, err := post.GetTagSlice(appcontext, keys[0])
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			content, err := post.GetPostContent(appcontext, p)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				appcontext.Errorf("post.GetPostContent: %v", err)
				return
			}
			con := bytes.NewBuffer(blackfriday.MarkdownCommon(bytes.NewBufferString(content).Bytes())).String()
			context := map[string]interface{}{"c": con, "labels": labels(tags, blog_config),
				"link_to_entry":   urlprefix + "article/" + p.StickyUrl,
				"comment_display": "none",
				"post_date":       p.Postdate.Format("Oct 02 2006"),
				"post_title":      p.Title}
			total_con := config.Stringify_map(config.Merge(blog_config, context))
			c := mustache.RenderFile(template_dir+"entry.html.mustache", total_con)
			io.WriteString(w, c)
		}
	}
	return std_layout(blog_config, l)
}