func NewThread(w http.ResponseWriter, r *http.Request) { db := models.GetDbSession() board_id_str := mux.Vars(r)["id"] board_id, _ := strconv.Atoi(board_id_str) err, board := models.GetBoard(board_id) if err != nil { http.NotFound(w, r) return } current_user := utils.GetCurrentUser(r) if current_user == nil { http.NotFound(w, r) return } if r.Method == "POST" { title := r.FormValue("title") content := r.FormValue("content") post := models.NewPost(current_user, board, title, content) post.LatestReply = time.Now() db.Insert(post) http.Redirect(w, r, fmt.Sprintf("/board/%d/%d", board.Id, post.Id), http.StatusFound) return } utils.RenderTemplate(w, r, "new_thread.html", map[string]interface{}{ "board": board, }) }
func AdminUsers(w http.ResponseWriter, r *http.Request) { current_user := utils.GetCurrentUser(r) if current_user == nil || !current_user.IsAdmin() { http.NotFound(w, r) return } err := "" success := false starts_with := r.FormValue("starts_with") last_seen := r.FormValue("last_seen") db := models.GetDbSession() var users []*models.User if len(starts_with) == 1 { db.Select(&users, "SELECT * FROM users WHERE username LIKE $1", starts_with+"%") } else if last_seen == "1" { db.Select(&users, "SELECT * FROM users ORDER BY last_seen DESC") } else { db.Select(&users, "SELECT * FROM users ORDER BY id DESC") } utils.RenderTemplate(w, r, "admin_users.html", map[string]interface{}{ "error": err, "success": success, "users": users, }, nil) }
func ActionLockThread(w http.ResponseWriter, r *http.Request) { user := utils.GetCurrentUser(r) if !user.CanModerate() { http.NotFound(w, r) return } thread_id_str := r.FormValue("post_id") thread_id, err := strconv.Atoi(thread_id_str) if err != nil { http.NotFound(w, r) return } db := models.GetDbSession() obj, err := db.Get(&models.Post{}, thread_id) thread := obj.(*models.Post) if thread == nil || err != nil { http.NotFound(w, r) return } thread.Locked = !(thread.Locked) db.Update(thread) http.Redirect(w, r, fmt.Sprintf("/board/%d/%d", thread.BoardId, thread.Id), http.StatusFound) }
func GetMigrationInfo() (latest_db_version int64, migrations []*goose.Migration, err error) { goose_conf := generateGooseDbConf() db := models.GetDbSession() latest_db_version, _ = goose.GetMostRecentDBVersion(goose_conf.MigrationsDir) current_db_version, _ := goose.EnsureDBVersion(goose_conf, db.Db) migrations, _ = goose.CollectMigrations(goose_conf.MigrationsDir, current_db_version, latest_db_version) return latest_db_version, migrations, err }
func Index(w http.ResponseWriter, request *http.Request) { db := models.GetDbSession() var boards []models.Board _, err := db.Select(&boards, "SELECT * FROM boards") if err != nil { fmt.Printf("[error] Could not get boards (%s)\n", err.Error()) } utils.RenderTemplate(w, request, "index.html", map[string]interface{}{ "boards": boards, }) }
func ActionMarkAllRead(w http.ResponseWriter, r *http.Request) { user := utils.GetCurrentUser(r) if user == nil { http.NotFound(w, r) return } db := models.GetDbSession() user.LastUnreadAll = pq.NullTime{Time: time.Now(), Valid: true} db.Update(user) http.Redirect(w, r, "/", http.StatusFound) }
func Thread(w http.ResponseWriter, r *http.Request) { page_id_str := r.FormValue("page") page_id, err := strconv.Atoi(page_id_str) if err != nil { page_id = 0 } board_id_str := mux.Vars(r)["board_id"] board_id, _ := strconv.Atoi(board_id_str) err, board := models.GetBoard(board_id) post_id_str := mux.Vars(r)["post_id"] post_id, _ := strconv.Atoi(post_id_str) err, op, posts := models.GetThread(post_id, page_id) if r.Method == "POST" { db := models.GetDbSession() title := r.FormValue("title") content := r.FormValue("content") current_user := utils.GetCurrentUser(r) if current_user == nil { http.NotFound(w, r) return } post := models.NewPost(current_user, board, title, content) post.ParentId = sql.NullInt64{int64(post_id), true} op.LatestReply = time.Now() db.Insert(post) db.Update(op) err, op, posts = models.GetThread(post_id, page_id) } if err != nil { http.NotFound(w, r) return } num_pages := op.GetPagesInThread() utils.RenderTemplate(w, r, "thread.html", map[string]interface{}{ "board": board, "op": op, "posts": posts, "prev_page": (page_id != 0), "next_page": (page_id < num_pages), "page_id": page_id, }) }
func ActionMoveThread(w http.ResponseWriter, r *http.Request) { current_user := utils.GetCurrentUser(r) if current_user == nil || !current_user.CanModerate() { http.NotFound(w, r) return } thread_id_str := r.FormValue("post_id") thread_id, err := strconv.Atoi(thread_id_str) board_id_str := r.FormValue("to") board_id, err := strconv.Atoi(board_id_str) op, err := models.GetPost(thread_id) // boards, _ := models.GetBoardsfor(current_user.GroupId) boards, _ := models.GetBoards() if op == nil || err != nil { http.NotFound(w, r) return } if board_id_str != "" { db := models.GetDbSession() new_board, _ := models.GetBoard(board_id) if new_board == nil { http.NotFound(w, r) return } _, err := db.Exec("UPDATE posts SET board_id=$1 WHERE parent_id=$2", new_board.Id, op.Id) op.BoardId = new_board.Id db.Update(op) if err != nil { http.NotFound(w, r) fmt.Printf("Error moving post: %s\n", err.Error()) return } http.Redirect(w, r, fmt.Sprintf("/board/%d/%d", op.BoardId, op.Id), http.StatusFound) } board, err := models.GetBoard(int(op.BoardId)) utils.RenderTemplate(w, r, "action_move_thread.html", map[string]interface{}{ "board": board, "thread": op, "boards": boards, }, nil) }
func Board(w http.ResponseWriter, r *http.Request) { db := models.GetDbSession() page_id_str := r.FormValue("page") page_id, err := strconv.Atoi(page_id_str) if err != nil { page_id = 0 } board_id_str := mux.Vars(r)["id"] board_id, _ := strconv.Atoi(board_id_str) obj, err := db.Get(&models.Board{}, board_id) if err != nil || obj == nil { http.NotFound(w, r) return } board := obj.(*models.Board) if err != nil { http.NotFound(w, r) return } current_user := utils.GetCurrentUser(r) threads, err := board.GetThreads(page_id, current_user) if err != nil { fmt.Printf("[error] Could not get posts (%s)\n", err.Error()) } num_pages := board.GetPagesInBoard() utils.RenderTemplate(w, r, "board.html", map[string]interface{}{ "board": board, "threads": threads, "page_id": page_id, "prev_page": (page_id != 0), "next_page": (page_id < num_pages), }, map[string]interface{}{ "IsUnread": func(join *models.JoinThreadView) bool { if current_user != nil && !current_user.LastUnreadAll.Time.Before(join.LatestReply) { return false } return !join.ViewedOn.Valid || join.ViewedOn.Time.Before(join.LatestReply) }, }) }
func User(w http.ResponseWriter, r *http.Request) { db := models.GetDbSession() user_id_str := mux.Vars(r)["id"] user_id, err := strconv.Atoi(user_id_str) if err != nil { http.NotFound(w, r) return } user, err := db.Get(&models.User{}, user_id) if err != nil { http.NotFound(w, r) return } utils.RenderTemplate(w, r, "user.html", map[string]interface{}{ "user": user, }, nil) }
func ActionDeleteThread(w http.ResponseWriter, r *http.Request) { user := utils.GetCurrentUser(r) thread_id_str := r.FormValue("post_id") thread_id, err := strconv.Atoi(thread_id_str) if err != nil { http.NotFound(w, r) return } db := models.GetDbSession() obj, err := db.Get(&models.Post{}, thread_id) thread := obj.(*models.Post) if thread == nil || err != nil { http.NotFound(w, r) return } if (thread.AuthorId != user.Id) && !user.CanModerate() { http.NotFound(w, r) return } redirect_board := true if thread.ParentId.Valid { redirect_board = false } thread.DeleteAllChildren() db.Delete(thread) if redirect_board { http.Redirect(w, r, fmt.Sprintf("/board/%d", thread.BoardId), http.StatusFound) } else { http.Redirect(w, r, fmt.Sprintf("/board/%d/%d", thread.BoardId, thread.ParentId.Int64), http.StatusFound) } }
func Register(w http.ResponseWriter, r *http.Request) { if utils.GetCurrentUser(r) != nil { http.Redirect(w, r, "/", http.StatusFound) return } if r.Method == "POST" { username := r.FormValue("username") password := r.FormValue("password") confirm := r.FormValue("password2") var error string if password != confirm { error = "Passwords don't match" } if error != "" { utils.RenderTemplate(w, r, "register.html", map[string]interface{}{ "error": error, }) return } // We're good, let's make it db_map := models.GetDbSession() user := models.NewUser(username, password) err := db_map.Insert(user) if err != nil { fmt.Printf("[error] Could not insert user (%s)\n", err.Error()) } else { http.Redirect(w, r, "/login", http.StatusFound) return } } utils.RenderTemplate(w, r, "register.html", nil) }
func Board(w http.ResponseWriter, r *http.Request) { db := models.GetDbSession() board_id_str := mux.Vars(r)["id"] board_id, _ := strconv.Atoi(board_id_str) board, err := db.Get(models.Board{}, board_id) if err != nil { http.NotFound(w, r) return } var threads []*models.Post _, err = db.Select(&threads, "SELECT * FROM posts WHERE board_id=$1 AND parent_id IS NULL ORDER BY latest_reply DESC", board_id) if err != nil { fmt.Printf("[error] Could not get posts (%s)\n", err.Error()) } utils.RenderTemplate(w, r, "board.html", map[string]interface{}{ "board": board, "threads": threads, }) }
func UserSettings(w http.ResponseWriter, r *http.Request) { user_id_str := mux.Vars(r)["id"] user_id, _ := strconv.Atoi(user_id_str) current_user := utils.GetCurrentUser(r) if int64(user_id) != current_user.Id { http.NotFound(w, r) return } success := false if r.Method == "POST" { db := models.GetDbSession() current_user.Avatar = r.FormValue("avatar_url") db.Update(current_user) success = true } utils.RenderTemplate(w, r, "user_settings.html", map[string]interface{}{ "success": success, }) }
func main() { // Get the config file var config_path string flag.StringVar(&config_path, "config", "gobb.conf", "Specifies the location of a config file") run_migrations := flag.Bool("migrate", false, "Runs database migrations") ign_migrations := flag.Bool("ignore-migrations", false, "Ignores an out of date database and runs the server anyways") serve := flag.Bool("serve", false, "run server") useradd := flag.Bool("add-user", false, "add a user") var name, password string flag.StringVar(&name, "name", "", "username to add") flag.StringVar(&password, "password", "", "password new user") group := flag.Int64("group", 0, "group of new user (<0 is special group, 0 is default, 1 is mod, 2 is admin)") flag.Parse() config.GetConfig(config_path) // Do we need to run migrations? latest_db_version, migrations, err := utils.GetMigrationInfo() if len(migrations) != 0 && *run_migrations { fmt.Println("[notice] Running database migrations:\n") err = utils.RunMigrations(latest_db_version) if err != nil { fmt.Printf("[error] Could not run migrations (%s)\n", err.Error()) return } fmt.Println("\n[notice] Database migration successful!") } else if len(migrations) != 0 && !(*ign_migrations) { fmt.Println("Your database appears to be out of date. Please run migrations with --migrate or ignore this message with --ignore-migrations") return } db := models.GetDbSession() if *useradd { user := models.NewUser(name, password) user.GroupId = *group err = db.Insert(user) } if !*serve { return } // URL Routing! r := mux.NewRouter() r.StrictSlash(true) r.HandleFunc("/", controllers.Index) r.HandleFunc("/register", controllers.Register) r.HandleFunc("/login", controllers.Login) r.HandleFunc("/logout", controllers.Logout) r.HandleFunc("/admin", controllers.Admin) r.HandleFunc("/admin/boards", controllers.AdminBoards) r.HandleFunc("/admin/users/{id:[0-9]+}", controllers.AdminUser) r.HandleFunc("/admin/users", controllers.AdminUsers) r.HandleFunc("/action/stick", controllers.ActionStickThread) r.HandleFunc("/action/lock", controllers.ActionLockThread) r.HandleFunc("/action/delete", controllers.ActionDeleteThread) r.HandleFunc("/action/move", controllers.ActionMoveThread) r.HandleFunc("/action/mark_read", controllers.ActionMarkAllRead) r.HandleFunc("/action/edit", controllers.PostEditor) r.HandleFunc("/board/{id:[0-9]+}", controllers.Board) r.HandleFunc("/board/{board_id:[0-9]+}/new", controllers.PostEditor) r.HandleFunc("/board/{board_id:[0-9]+}/{post_id:[0-9]+}", controllers.Thread) r.HandleFunc("/user/{id:[0-9]+}", controllers.User) r.HandleFunc("/user/{id:[0-9]+}/settings", controllers.UserSettings) // Handle static files selected_template, _ := models.GetStringSetting("template") base_path, _ := config.Config.GetString("gobb", "base_path") if selected_template == "default" { pkg, _ := build.Import("github.com/stevenleeg/gobb/gobb", ".", build.FindOnly) static_path := filepath.Join(pkg.SrcRoot, pkg.ImportPath, "../templates") r.PathPrefix("/static/").Handler(http.FileServer(http.Dir(static_path))) } else { static_path := filepath.Join(base_path, "templates", selected_template) r.PathPrefix("/static/").Handler(http.FileServer(http.Dir(static_path))) } // User provided static files static_path, err := config.Config.GetString("gobb", "base_path") if err == nil { r.PathPrefix("/assets/").Handler(http.FileServer(http.Dir(static_path))) } http.Handle("/", r) port, err := config.Config.GetString("gobb", "port") fmt.Println("[notice] Starting server on port " + port) http.ListenAndServe(":"+port, nil) }
func Register(w http.ResponseWriter, r *http.Request) { if utils.GetCurrentUser(r) != nil { http.Redirect(w, r, "/", http.StatusFound) return } if r.Method == "POST" { username := r.FormValue("username") password := r.FormValue("password") confirm := r.FormValue("password2") var error string if password != confirm { error = "Passwords don't match" } // See if a user with this name already exists db := models.GetDbSession() count, err := db.SelectInt("SELECT COUNT(*) FROM users WHERE username=$1", username) if count > 0 || err != nil { error = "This username is already taken." } if len(username) < 3 { error = "Username must be greater than 3 characters." } if error != "" { utils.RenderTemplate(w, r, "register.html", map[string]interface{}{ "error": error, }, nil) return } // We're good, let's make it user := models.NewUser(username, password) err = db.Insert(user) if err != nil { fmt.Printf("[error] Could not insert user (%s)\n", err.Error()) return; } // Adminify the first user id, err := db.SelectInt("SELECT lastval()") if err == nil && id == 1 { user.GroupId = 2 count, err = db.Update(user) if err != nil { fmt.Printf("[error] Could not adminify user (%s)\n", err.Error()) return; } } http.Redirect(w, r, "/login", http.StatusFound) return } utils.RenderTemplate(w, r, "register.html", nil, nil) }
func UserSettings(w http.ResponseWriter, r *http.Request) { enable_signatures, _ := config.Config.GetBool("gobb", "enable_signatures") user_id_str := mux.Vars(r)["id"] user_id, _ := strconv.Atoi(user_id_str) current_user := utils.GetCurrentUser(r) if current_user == nil || int64(user_id) != current_user.Id { http.NotFound(w, r) return } success := false var form_error string if r.Method == "POST" { db := models.GetDbSession() current_user.Avatar = r.FormValue("avatar_url") current_user.UserTitle = r.FormValue("user_title") current_user.StylesheetUrl = sql.NullString{ Valid: true, String: r.FormValue("stylesheet_url"), } if r.FormValue("signature") == "" { current_user.Signature = sql.NullString{ Valid: false, String: r.FormValue("signature"), } } else { current_user.Signature = sql.NullString{ Valid: true, String: r.FormValue("signature"), } } // Change hiding settings current_user.HideOnline = false if r.FormValue("hide_online") == "1" { current_user.HideOnline = true } // Update password? old_pass := r.FormValue("password_old") new_pass := r.FormValue("password_new") new_pass2 := r.FormValue("password_new2") if old_pass != "" { err, user := models.AuthenticateUser(current_user.Username, old_pass) if user == nil || err != nil { form_error = "Invalid password" } else if len(new_pass) < 5 { form_error = "Password must be greater than 4 characters" } else if new_pass != new_pass2 { form_error = "Passwords didn't match" } else { current_user.SetPassword(new_pass) session, _ := utils.GetCookieStore(r).Get(r, "sirsid") session.Values["password"] = new_pass session.Save(r, w) } } if form_error == "" { db.Update(current_user) success = true } } stylesheet := "" if current_user.StylesheetUrl.Valid { stylesheet = current_user.StylesheetUrl.String } signature := "" if current_user.Signature.Valid { signature = current_user.Signature.String } utils.RenderTemplate(w, r, "user_settings.html", map[string]interface{}{ "error": form_error, "success": success, "user_stylesheet": stylesheet, "user_signature": signature, "enable_signatures": enable_signatures, }, nil) }
func PostEditor(w http.ResponseWriter, r *http.Request) { db := models.GetDbSession() var err error var board *models.Board var post *models.Post // Attempt to get a board board_id_str := mux.Vars(r)["board_id"] if board_id_str != "" { board_id, _ := strconv.Atoi(board_id_str) board, err = models.GetBoard(board_id) } // Otherwise, a post post_id_str := r.FormValue("post_id") if post_id_str != "" { post_id, _ := strconv.Atoi(post_id_str) post_tmp, _ := db.Get(&models.Post{}, post_id) post = post_tmp.(*models.Post) } if err != nil { fmt.Println("something went wrong") http.NotFound(w, r) return } current_user := utils.GetCurrentUser(r) if current_user == nil { http.NotFound(w, r) return } if post != nil && (post.AuthorId != current_user.Id && !current_user.CanModerate()) { http.NotFound(w, r) return } if r.Method == "POST" { title := r.FormValue("title") content := r.FormValue("content") if post == nil { post = models.NewPost(current_user, board, title, content) post.LatestReply = time.Now() err = post.Validate() if err != nil { renderPostEditor(w, r, board, post, err) return } err = db.Insert(post) } else { post.Title = title post.Content = content post.LastEdit = time.Now() post.LatestReply = time.Now() err = post.Validate() if err != nil { renderPostEditor(w, r, board, post, err) return } _, err = db.Update(post) } if err != nil { fmt.Printf("[error] Could not save post (%s)", err.Error()) return } http.Redirect(w, r, post.GetLink(), http.StatusFound) return } renderPostEditor(w, r, board, post, err) }
func AdminBoards(w http.ResponseWriter, r *http.Request) { current_user := utils.GetCurrentUser(r) if current_user == nil || !current_user.IsAdmin() { http.NotFound(w, r) return } db := models.GetDbSession() // Creating a board if r.Method == "POST" && r.FormValue("create_board") != "" { name := r.FormValue("title") desc := r.FormValue("description") form_order := r.FormValue("order") var order int if form_order != "" { if len(form_order) == 0 { order = 1 } else { order, _ = strconv.Atoi(form_order) } } else { order = 1 } board := models.NewBoard(name, desc, order) db.Insert(board) } // Update the boards if r.Method == "POST" && r.FormValue("update_boards") != "" { err := r.ParseForm() // loop through the post data, entries correspond via index in the map for i := 0; i < len(r.Form["board_id"]); i++ { // basically repeat the process for inserting a board form_id, _ := strconv.Atoi(r.Form["board_id"][i]) id := int64(form_id) name := r.Form["name"][i] desc := r.Form["description"][i] form_order := r.Form["order"][i] groupidst := r.Form["groupid"][i] var order int var groupid int64 if form_order != "" { if len(form_order) == 0 { order = 1 } else { order, _ = strconv.Atoi(form_order) } } else { order = 1 } if len(groupidst) < 1 { groupid = 0 } else { groupid, _ = strconv.ParseInt(groupidst, 10, 64) } board := models.UpdateBoard(name, desc, order, id, groupid) db.Update(board) } if err != nil { http.NotFound(w, r) return } } // Delete a board if id := r.FormValue("delete"); id != "" { obj, _ := db.Get(&models.Board{}, id) if obj == nil { http.NotFound(w, r) return } board := obj.(*models.Board) board.Delete() } boards, _ := models.GetBoards() utils.RenderTemplate(w, r, "admin_boards.html", map[string]interface{}{ "boards": boards, }, nil) }
func AdminUser(w http.ResponseWriter, r *http.Request) { current_user := utils.GetCurrentUser(r) if current_user == nil || !current_user.IsAdmin() { http.NotFound(w, r) return } id_str := mux.Vars(r)["id"] id, _ := strconv.Atoi(id_str) user, err := models.GetUser(id) if err != nil || user == nil { http.NotFound(w, r) return } var form_error string success := false if r.Method == "POST" { db := models.GetDbSession() user.Username = r.FormValue("username") user.Avatar = r.FormValue("avatar_url") user.UserTitle = r.FormValue("user_title") user.StylesheetUrl = sql.NullString{ Valid: true, String: r.FormValue("stylesheet_url"), } if r.FormValue("signature") == "" { user.Signature = sql.NullString{ Valid: false, String: r.FormValue("signature"), } } else { user.Signature = sql.NullString{ Valid: true, String: r.FormValue("signature"), } } // Change hiding settings user.HideOnline = false if r.FormValue("hide_online") == "1" { user.HideOnline = true } // Update the username? if len(user.Username) < 3 { form_error = "Username must at least 3 characters" } // Update password? new_pass := r.FormValue("password_new") new_pass2 := r.FormValue("password_new2") if len(new_pass) > 0 { if len(new_pass) < 5 { form_error = "Password must be greater than 4 characters" } else if new_pass != new_pass2 { form_error = "Passwords didn't match" } else { user.SetPassword(new_pass) } } group_id, _ := strconv.Atoi(r.FormValue("group_id")) user.GroupId = int64(group_id) if form_error == "" { db.Update(user) success = true } } utils.RenderTemplate(w, r, "admin_user.html", map[string]interface{}{ "error": form_error, "success": success, "user": user, }, nil) }
func Thread(w http.ResponseWriter, r *http.Request) { page_id_str := r.FormValue("page") page_id, err := strconv.Atoi(page_id_str) if err != nil { page_id = 0 } board_id_str := mux.Vars(r)["board_id"] board_id, _ := strconv.Atoi(board_id_str) board, err := models.GetBoard(board_id) post_id_str := mux.Vars(r)["post_id"] post_id, _ := strconv.Atoi(post_id_str) err, op, posts := models.GetThread(post_id, page_id) var posting_error error current_user := utils.GetCurrentUser(r) if r.Method == "POST" { db := models.GetDbSession() title := r.FormValue("title") content := r.FormValue("content") if current_user == nil { http.NotFound(w, r) return } if op.Locked && !current_user.CanModerate() { http.NotFound(w, r) return } post := models.NewPost(current_user, board, title, content) post.ParentId = sql.NullInt64{int64(post_id), true} op.LatestReply = time.Now() posting_error = post.Validate() if posting_error == nil { db.Insert(post) db.Update(op) if page := post.GetPageInThread(); page != page_id { http.Redirect(w, r, fmt.Sprintf("/board/%d/%d?page=%d#post_%d", post.BoardId, op.Id, page, post.Id), http.StatusFound) } err, op, posts = models.GetThread(post_id, page_id) } } if err != nil { http.NotFound(w, r) fmt.Printf("[error] Something went wrong in posts (%s)\n", err.Error()) return } num_pages := op.GetPagesInThread() if page_id > num_pages { http.NotFound(w, r) return } var previous_text string if posting_error != nil { previous_text = r.FormValue("content") } // Mark the thread as read if current_user != nil { models.AddView(current_user, op) } utils.RenderTemplate(w, r, "thread.html", map[string]interface{}{ "board": board, "op": op, "posts": posts, "first_page": (page_id > 0), "prev_page": (page_id > 1), "next_page": (page_id < num_pages-1), "last_page": (page_id < num_pages), "page_id": page_id, "posting_error": posting_error, "previous_text": previous_text, }, map[string]interface{}{ "CurrentUserCanModerateThread": func(thread *models.Post) bool { current_user := utils.GetCurrentUser(r) if current_user == nil { return false } return (current_user.CanModerate() && thread.ParentId.Valid == false) }, "CurrentUserCanDeletePost": func(thread *models.Post) bool { current_user := utils.GetCurrentUser(r) if current_user == nil { return false } return (current_user.Id == thread.AuthorId) || current_user.CanModerate() }, "CurrentUserCanEditPost": func(post *models.Post) bool { current_user := utils.GetCurrentUser(r) if current_user == nil { return false } return (current_user.Id == post.AuthorId || current_user.CanModerate()) }, "CurrentUserCanModerate": func() bool { current_user := utils.GetCurrentUser(r) if current_user == nil { return false } return current_user.CanModerate() }, "SignaturesEnabled": func() bool { enable_signatures, _ := config.Config.GetBool("gobb", "enable_signatures") return enable_signatures }, "ShowReplyBox": func(post *models.Post) bool { current_user := utils.GetCurrentUser(r) if current_user != nil && (!post.Locked || current_user.CanModerate()) { return true } return false }, }) }