1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-16 07:56:24 -07:00

Add various changes suggested by gometalinter, 359 more to go!

This commit is contained in:
Joshua Merrell 2018-05-04 17:41:46 -07:00
parent f1df7aefce
commit 6a4443dbc6
7 changed files with 234 additions and 238 deletions

View file

@ -12,15 +12,15 @@ var version string
// verbose = 1 for non-critical warnings and important info
// verbose = 2 for all debugging/benchmarks/warnings
// set in Makefile via -ldflags
var verbosity_str string
var buildtime_str string // set in build.sh, format: YRMMDD.HHMM
var verbosityString string
var buildtimeString string // set in Makefile, format: YRMMDD.HHMM
func main() {
defer db.Close()
initConfig()
config.Verbosity, _ = strconv.Atoi(verbosity_str)
config.Verbosity, _ = strconv.Atoi(verbosityString)
config.Version = version
printf(0, "Starting gochan v%s.%s, using verbosity level %d\n", config.Version, buildtime_str, config.Verbosity)
printf(0, "Starting gochan v%s.%s, using verbosity level %d\n", config.Version, buildtimeString, config.Verbosity)
printf(0, "Config file loaded. Connecting to database...")
connectToSQLServer()
@ -32,7 +32,10 @@ func main() {
println(0, "Initializing server...")
if db != nil {
db.Exec("USE `" + config.DBname + "`;")
_, err := db.Exec("USE `" + config.DBname + "`")
if err != nil {
println(0, customError(err))
}
}
initServer()
}

View file

@ -14,6 +14,8 @@ import (
"golang.org/x/crypto/bcrypt"
)
// ManageFunction represents the functions accessed by staff members at /manage?action=<functionname>.
// Eventually a plugin system might allow you to add more
type ManageFunction struct {
Permissions int // 0 -> non-staff, 1 => janitor, 2 => moderator, 3 => administrator
Callback func() string //return string of html output
@ -23,12 +25,17 @@ func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}
request = *r
writer = w
cookies = r.Cookies()
request.ParseForm()
err := request.ParseForm()
if err != nil {
serveErrorPage(writer, err.Error())
errorLog.Println(customError(err))
}
action := request.FormValue("action")
staffRank := getStaffRank()
var managePageBuffer bytes.Buffer
mangePageHTML := ""
var err error
if action == "" {
action = "announcements"
@ -36,12 +43,13 @@ func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}
if action != "getstaffjquery" {
if err = global_header_tmpl.Execute(&managePageBuffer, config); err != nil {
handleError(0, customError(err))
fmt.Fprintf(writer, mangePageHTML+err.Error()+"\n</body>\n</html>")
return
}
if err = manage_header_tmpl.Execute(&managePageBuffer, config); err != nil {
println(0, mangePageHTML)
handleError(0, customError(err))
fmt.Fprintf(writer, mangePageHTML+err.Error()+"\n</body>\n</html>")
return
}
@ -64,23 +72,22 @@ func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}
managePageBuffer.Write([]byte("\n</body>\n</html>"))
}
extension := getFileExtension(request.URL.Path)
/* extension := getFileExtension(request.URL.Path)
if extension == "" {
//writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
}
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
} */
fmt.Fprintf(writer, managePageBuffer.String())
}
func getCurrentStaff() (string, error) {
session_cookie := getCookie("sessiondata")
sessionCookie := getCookie("sessiondata")
var key string
if session_cookie == nil {
if sessionCookie == nil {
return "", nil
} else {
key = session_cookie.Value
}
key = sessionCookie.Value
row := db.QueryRow("SELECT `data` FROM `" + config.DBprefix + "sessions` WHERE `key` = '" + key + "'")
row := db.QueryRow("SELECT `data` FROM `"+config.DBprefix+"sessions` WHERE `key` = ?", key)
current_session := new(SessionsTable)
if err := row.Scan(&current_session.Data); err != nil {
@ -90,7 +97,7 @@ func getCurrentStaff() (string, error) {
}
func getStaff(name string) (*StaffTable, error) {
row := db.QueryRow("SELECT * FROM `" + config.DBprefix + "staff` WHERE `username` = '" + name + "';")
row := db.QueryRow("SELECT * FROM `"+config.DBprefix+"staff` WHERE `username` = ?", name)
staff_obj := new(StaffTable)
err := row.Scan(&staff_obj.ID, &staff_obj.Username, &staff_obj.PasswordChecksum, &staff_obj.Salt, &staff_obj.Rank, &staff_obj.Boards, &staff_obj.AddedOn, &staff_obj.LastActive)
return staff_obj, err
@ -98,6 +105,7 @@ func getStaff(name string) (*StaffTable, error) {
func getStaffRank() int {
staffname, err := getCurrentStaff()
println(1, customError(err))
if staffname == "" {
return 0
}
@ -107,7 +115,7 @@ func getStaffRank() int {
staff, err := getStaff(staffname)
if err != nil {
handleError(1, err.Error())
handleError(1, customError(err))
return 0
}
return staff.Rank
@ -126,7 +134,7 @@ func createSession(key string, username string, password string, request *http.R
}
staff, err := getStaff(username)
if err != nil {
handleError(1, err.Error())
handleError(1, customError(err))
return 1
} else {
success := bcrypt.CompareHashAndPassword([]byte(staff.PasswordChecksum), []byte(password))
@ -140,12 +148,12 @@ func createSession(key string, username string, password string, request *http.R
http.SetCookie(*writer, cookie)
_, err := db.Exec("INSERT INTO `" + config.DBprefix + "sessions` (`key`, `data`, `expires`) VALUES('" + key + "','" + username + "', '" + getSpecificSQLDateTime(time.Now().Add(time.Duration(time.Hour*730))) + "')")
if err != nil {
handleError(1, err.Error())
handleError(1, customError(err))
return 2
}
_, err = db.Exec("UPDATE `" + config.DBprefix + "staff` SET `last_active` ='" + getSQLDateTime() + "' WHERE `username` = '" + username + "';")
_, err = db.Exec("UPDATE `"+config.DBprefix+"staff` SET `last_active` = ? WHERE `username` = ?", getSQLDateTime(), username)
if err != nil {
handleError(1, err.Error())
handleError(1, customError(err))
}
return 0
}
@ -159,9 +167,9 @@ var manage_functions = map[string]ManageFunction{
html = "<h2>Cleanup</h2><br />"
if request.FormValue("run") == "Run Cleanup" {
html += "Removing deleted posts from the database.<hr />"
_, err := db.Exec("DELETE FROM `" + config.DBprefix + "posts` WHERE `deleted_timestamp` = '" + nil_timestamp + "'")
_, err := db.Exec("DELETE FROM `" + config.DBprefix + "posts` WHERE `deleted_timestamp` = '" + nilTimestamp + "'")
if err != nil {
html += "<tr><td>" + err.Error() + "</td></tr></table>"
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
}
// TODO: remove orphaned replies
@ -203,7 +211,7 @@ var manage_functions = map[string]ManageFunction{
// return
// }
// err = ioutil.WriteFile("gochan.json", configJSON, 0777)
// err = ioutil.WriteFile("gochan.json", configJSON, 0666)
// if err != nil {
// html += "Error writing \"gochan.json\": %s\n" + err.Error()
// return
@ -224,34 +232,41 @@ var manage_functions = map[string]ManageFunction{
html = "<img src=\"/css/purge.jpg\" />"
rows, err := db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`")
if err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
var board string
for rows.Next() {
if err = rows.Scan(&board); err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
if _, err = deleteMatchingFiles(path.Join(config.DocumentRoot, board), ".html"); err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
if _, err = deleteMatchingFiles(path.Join(config.DocumentRoot, board, "res"), ".*"); err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
if _, err = deleteMatchingFiles(path.Join(config.DocumentRoot, board, "src"), ".*"); err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
if _, err = deleteMatchingFiles(path.Join(config.DocumentRoot, board, "thumb"), ".*"); err != nil {
html += handleError(1, err.Error())
html += err.Error()
handleError(1, customError(err))
return
}
}
if _, err = db.Exec("TRUNCATE `" + config.DBprefix + "posts`"); err != nil {
html += handleError(1, err.Error()) + "<br />"
html += err.Error() + "<br />"
handleError(1, customError(err))
return
}
db.Exec("ALTER TABLE `" + config.DBprefix + "posts` AUTO_INCREMENT = 1")
@ -268,9 +283,7 @@ var manage_functions = map[string]ManageFunction{
html = "<h1>Execute SQL statement(s)</h1><form method = \"POST\" action=\"/manage?action=executesql\">\n<textarea name=\"sql\" id=\"sql-statement\">" + statement + "</textarea>\n<input type=\"submit\" />\n</form>"
if statement != "" {
html += "<hr />"
result, sqlerr := db.Exec(statement)
println(1, &result)
_, sqlerr := db.Exec(statement)
if sqlerr != nil {
html += handleError(1, sqlerr.Error())
} else {
@ -336,7 +349,7 @@ var manage_functions = map[string]ManageFunction{
Callback: func() (html string) {
html = "<h1>Announcements</h1><br />"
rows, err := db.Query("SELECT `subject`,`message`,`poster`,`timestamp` FROM `" + config.DBprefix + "announcements` ORDER BY `id` DESC;")
rows, err := db.Query("SELECT `subject`,`message`,`poster`,`timestamp` FROM `" + config.DBprefix + "announcements` ORDER BY `id` DESC")
if err != nil {
html += handleError(1, err.Error())
return
@ -386,7 +399,7 @@ var manage_functions = map[string]ManageFunction{
boards_list_html := " <span style=\"font-weight: bold;\">Boards: </span><br />\n" +
" <label>All boards <input type=\"checkbox\" id=\"allboards\" /></label> overrides individual board selection<br />\n"
rows, err := db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`;")
rows, err := db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`")
if err != nil {
html += "<hr />" + handleError(1, err.Error())
return
@ -489,7 +502,7 @@ var manage_functions = map[string]ManageFunction{
html = "nobody;0;"
return
}
row := db.QueryRow("SELECT `rank`,`boards` FROM `" + config.DBprefix + "staff` WHERE `username` = '" + current_staff + "'")
row := db.QueryRow("SELECT `rank`,`boards` FROM `"+config.DBprefix+"staff` WHERE `username` = ?", current_staff)
staff := new(StaffTable)
if err = row.Scan(&staff.Rank, &staff.Boards); err != nil {
html += handleError(1, "Error getting staff list: "+err.Error())
@ -583,25 +596,25 @@ var manage_functions = map[string]ManageFunction{
board.EnableCatalog = (request.FormValue("enablecatalog") == "on")
//actually start generating stuff
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir), 0777); err != nil {
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir), 0666); err != nil {
do = ""
board_creation_status = handleError(1, "ERROR: directory /"+config.DocumentRoot+"/"+board.Dir+"/ already exists!")
break
}
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "res"), 0777); err != nil {
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "res"), 0666); err != nil {
do = ""
board_creation_status = handleError(1, "ERROR: directory /"+config.DocumentRoot+"/"+board.Dir+"/res/ already exists!")
break
}
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "thumb"), 0777); err != nil {
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "thumb"), 0666); err != nil {
do = ""
board_creation_status = handleError(1, "ERROR: directory /"+config.DocumentRoot+"/"+board.Dir+"/thumb/ already exists!")
break
}
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "src"), 0777); err != nil {
if err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir, "src"), 0666); err != nil {
do = ""
board_creation_status = handleError(1, "ERROR: directory /"+config.DocumentRoot+"/"+board.Dir+"/src/ already exists!")
break
@ -631,9 +644,8 @@ var manage_functions = map[string]ManageFunction{
&board.RedirectToThread, &board.RequireFile, &board.EnableCatalog,
); err != nil {
do = ""
board_creation_status = err.Error()
board_creation_status = customError(err)
handleError(1, "Error creating board: "+board_creation_status)
break
} else {
board_creation_status = "Board created successfully"
println(2, board_creation_status)
@ -641,81 +653,80 @@ var manage_functions = map[string]ManageFunction{
resetBoardSectionArrays()
println(2, "Boards rebuilt successfully")
done = true
break
}
break
case do == "del":
// resetBoardSectionArrays()
case do == "edit":
// resetBoardSectionArrays()
default:
// put the default column values in the text boxes
rows, err = db.Query("SELECT `column_name`,`column_default` FROM `information_schema`.`columns` WHERE `table_name` = '" + config.DBprefix + "boards'")
rows, err = db.Query("SELECT `column_name`,`columnDefault` FROM `information_schema`.`columns` WHERE `table_name` = '" + config.DBprefix + "boards'")
if err != nil {
html += handleError(1, "Error getting column names from boards table:"+err.Error())
return
}
for rows.Next() {
var column_name string
var column_default string
rows.Scan(&column_name, &column_default)
column_default_int, _ := strconv.Atoi(column_default)
column_default_bool := (column_default_int == 1)
switch column_name {
var columnName string
var columnDefault string
rows.Scan(&columnName, &columnDefault)
columnDefaultInt, _ := strconv.Atoi(columnDefault)
columnDefaultBool := (columnDefaultInt == 1)
switch columnName {
case "id":
board.ID = column_default_int
board.ID = columnDefaultInt
case "order":
board.Order = column_default_int
board.Order = columnDefaultInt
case "dir":
board.Dir = column_default
board.Dir = columnDefault
case "type":
board.Type = column_default_int
board.Type = columnDefaultInt
case "upload_type":
board.UploadType = column_default_int
board.UploadType = columnDefaultInt
case "title":
board.Title = column_default
board.Title = columnDefault
case "subtitle":
board.Subtitle = column_default
board.Subtitle = columnDefault
case "description":
board.Description = column_default
board.Description = columnDefault
case "section":
board.Section = column_default_int
board.Section = columnDefaultInt
case "max_image_size":
board.MaxImageSize = column_default_int
board.MaxImageSize = columnDefaultInt
case "max_pages":
board.MaxPages = column_default_int
board.MaxPages = columnDefaultInt
case "locale":
board.Locale = column_default
board.Locale = columnDefault
case "default_style":
board.DefaultStyle = column_default
board.DefaultStyle = columnDefault
case "locked":
board.Locked = column_default_bool
board.Locked = columnDefaultBool
case "anonymous":
board.Anonymous = column_default
board.Anonymous = columnDefault
case "forced_anon":
board.ForcedAnon = column_default_bool
board.ForcedAnon = columnDefaultBool
case "max_age":
board.MaxAge = column_default_int
board.MaxAge = columnDefaultInt
case "autosage_after":
board.AutosageAfter = column_default_int
board.AutosageAfter = columnDefaultInt
case "no_images_after":
board.NoImagesAfter = column_default_int
board.NoImagesAfter = columnDefaultInt
case "max_message_length":
board.MaxMessageLength = column_default_int
board.MaxMessageLength = columnDefaultInt
case "embeds_allowed":
board.EmbedsAllowed = column_default_bool
board.EmbedsAllowed = columnDefaultBool
case "redirect_to_thread":
board.RedirectToThread = column_default_bool
board.RedirectToThread = columnDefaultBool
case "require_file":
board.RequireFile = column_default_bool
board.RequireFile = columnDefaultBool
case "enable_catalog":
board.EnableCatalog = column_default_bool
board.EnableCatalog = columnDefaultBool
}
}
}
html = "<h1>Manage boards</h1>\n<form action=\"/manage?action=boards\" method=\"POST\">\n<input type=\"hidden\" name=\"do\" value=\"existing\" /><select name=\"boardselect\">\n<option>Select board...</option>\n"
rows, err = db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`;")
rows, err = db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`")
if err != nil {
html += handleError(1, err.Error())
return
@ -723,24 +734,24 @@ var manage_functions = map[string]ManageFunction{
defer closeRows(rows)
for rows.Next() {
var board_dir string
rows.Scan(&board_dir)
html += "<option>" + board_dir + "</option>\n"
var boardDir string
rows.Scan(&boardDir)
html += "<option>" + boardDir + "</option>\n"
}
html += "</select> <input type=\"submit\" value=\"Edit\" /> <input type=\"submit\" value=\"Delete\" /></form><hr />" +
"<h2>Create new board</h2>\n<span id=\"board-creation-message\">" + board_creation_status + "</span><br />"
manageBoardsBuffer := bytes.NewBufferString("")
all_sections, _ = getSectionArr("")
if len(all_sections) == 0 {
allSections, _ = getSectionArr("")
if len(allSections) == 0 {
db.Exec("INSERT INTO `" + config.DBprefix + "sections` (`hidden`,`name`,`abbreviation`) VALUES(0,'Main','main')")
}
all_sections, _ = getSectionArr("")
allSections, _ = getSectionArr("")
if err := manage_boards_tmpl.Execute(manageBoardsBuffer, map[string]interface{}{
"board": board,
"section_arr": all_sections,
"section_arr": allSections,
}); err != nil {
html += handleError(1, err.Error())
return
@ -805,7 +816,7 @@ var manage_functions = map[string]ManageFunction{
Permissions: 3,
Callback: func() (html string) {
posts, err := getPostArr(map[string]interface{}{
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, "")
if err != nil {
html += err.Error() + "<br />"
@ -836,7 +847,7 @@ var manage_functions = map[string]ManageFunction{
limit = "50"
}
html = "<h1>Recent posts</h1>\nLimit by: <select id=\"limit\"><option>25</option><option>50</option><option>100</option><option>200</option></select>\n<br />\n<table width=\"100%%d\" border=\"1\">\n<colgroup><col width=\"25%%\" /><col width=\"50%%\" /><col width=\"17%%\" /></colgroup><tr><th></th><th>Message</th><th>Time</th></tr>"
rows, err := db.Query("SELECT `" + config.DBprefix + "boards`.`dir` AS `boardname`, " +
rows, err := db.Query("SELECT `" + config.DBprefix + "boards`.`dir` AS `boardname`, " +
"`" + config.DBprefix + "posts`.`boardid` AS boardid, " +
"`" + config.DBprefix + "posts`.`id` AS id, " +
"`" + config.DBprefix + "posts`. " +
@ -849,9 +860,9 @@ var manage_functions = map[string]ManageFunction{
"`timestamp` AS timestamp " +
"FROM `" + config.DBprefix + "posts`, `" + config.DBprefix + "boards` " +
"WHERE `reviewed` = 0 " +
"AND `" + config.DBprefix + "posts`.`deleted_timestamp` = \"" + nil_timestamp + "\" " +
"AND `" + config.DBprefix + "posts`.`deleted_timestamp` = \"" + nilTimestamp + "\" " +
"AND `boardid` = `" + config.DBprefix + "boards`.`id` " +
"ORDER BY `timestamp` DESC LIMIT " + limit + ";")
"ORDER BY `timestamp` DESC LIMIT " + limit + "")
if err != nil {
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
@ -884,7 +895,7 @@ var manage_functions = map[string]ManageFunction{
html = "<h1>Staff</h1><br />\n" +
"<table id=\"stafftable\" border=\"1\">\n" +
"<tr><td><b>Username</b></td><td><b>Rank</b></td><td><b>Boards</b></td><td><b>Added on</b></td><td><b>Action</b></td></tr>\n"
rows, err := db.Query("SELECT `username`,`rank`,`boards`,`added_on` FROM `" + config.DBprefix + "staff`;")
rows, err := db.Query("SELECT `username`,`rank`,`boards`,`added_on` FROM `" + config.DBprefix + "staff`")
if err != nil {
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
@ -900,16 +911,16 @@ var manage_functions = map[string]ManageFunction{
}
if request.FormValue("do") == "add" {
new_username := request.FormValue("username")
new_password := request.FormValue("password")
new_rank := request.FormValue("rank")
newUsername := request.FormValue("username")
newPassword := request.FormValue("password")
newRank := request.FormValue("rank")
stmt, err := db.Prepare("INSERT INTO `" + config.DBprefix + "staff` (`username`, `password_checksum`, `rank`) VALUES(?,?,?)")
if err != nil {
serveErrorPage(writer, handleError(1, err.Error()))
}
defer closeStatement(stmt)
if _, err = stmt.Exec(&new_username, bcryptSum(new_password), &new_rank); err != nil {
if _, err = stmt.Exec(&newUsername, bcryptSum(newPassword), &newRank); err != nil {
serveErrorPage(writer, handleError(1, err.Error()))
}

View file

@ -35,9 +35,9 @@ const (
)
var (
last_post PostTable
all_sections []interface{}
all_boards []interface{}
lastPost PostTable
allSections []interface{}
allBoards []interface{}
)
// buildBoards builds one or all boards. If all == true, all boards will have their pages built.
@ -85,7 +85,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
results, err := os.Stat(path.Join(config.DocumentRoot, board.Dir))
if err != nil {
// Try creating the board's configured directory if it doesn't exist
err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir), 0777)
err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir), 0600)
if err != nil {
html += handleError(1, "Failed creating /"+board.Dir+"/: "+err.Error())
return
@ -100,7 +100,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
op_posts, err := getPostArr(map[string]interface{}{
"boardid": board.ID,
"parentid": 0,
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, " ORDER BY `bumped` DESC")
if err != nil {
html += handleError(1, err.Error()) + "<br />"
@ -121,7 +121,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
}
defer closeStatement(stmt)
if err = stmt.QueryRow(board.ID, op.ID, nil_timestamp).Scan(&thread.NumReplies); err != nil {
if err = stmt.QueryRow(board.ID, op.ID, nilTimestamp).Scan(&thread.NumReplies); err != nil {
html += err.Error() + "<br />\n"
}
@ -130,7 +130,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
if err != nil {
html += err.Error() + "<br />\n"
}
if err = stmt.QueryRow(board.ID, op.ID, nil_timestamp).Scan(&thread.NumImages); err != nil {
if err = stmt.QueryRow(board.ID, op.ID, nilTimestamp).Scan(&thread.NumImages); err != nil {
html += err.Error() + "<br />\n"
}
@ -150,7 +150,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
posts_in_thread, err = getPostArr(map[string]interface{}{
"boardid": board.ID,
"parentid": op.ID,
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, fmt.Sprintf(" ORDER BY `id` DESC LIMIT %d", numRepliesOnBoardPage))
if err != nil {
html += err.Error() + "<br />"
@ -194,7 +194,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
if len(threads) == 0 {
board.CurrentPage = 1
// Open board.html for writing to the first page.
board_page_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
board_page_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening /"+board.Dir+"/board.html: "+err.Error()) + "<br />"
return
@ -204,8 +204,8 @@ func buildBoardPages(board *BoardsTable) (html string) {
// packaging the board/section list, threads, and board info
if err = img_boardpage_tmpl.Execute(board_page_file, map[string]interface{}{
"config": config,
"boards": all_boards,
"sections": all_sections,
"boards": allBoards,
"sections": allSections,
"threads": threads,
"board": board,
}); err != nil {
@ -224,7 +224,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
// Create array of page wrapper objects, and open the file.
var pages_obj []BoardPageJSON
catalog_json_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
catalog_json_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening /"+board.Dir+"/catalog.json: "+err.Error())
return
@ -236,7 +236,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
var current_page_filepath string
pageFilename := strconv.Itoa(board.CurrentPage) + ".html"
current_page_filepath = path.Join(config.DocumentRoot, board.Dir, pageFilename)
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening board page: "+err.Error()) + "<br />"
continue
@ -246,8 +246,8 @@ func buildBoardPages(board *BoardsTable) (html string) {
// Render the boardpage template, don't forget config
if err = img_boardpage_tmpl.Execute(current_page_file, map[string]interface{}{
"config": config,
"boards": all_boards,
"sections": all_sections,
"boards": allBoards,
"sections": allSections,
"threads": page_threads,
"board": board,
"posts": []interface{}{
@ -322,7 +322,7 @@ func buildThreads(all bool, boardid, threadid int) (html string) {
"boardid": boardid,
"id": threadid,
"parentid": 0,
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, "")
thread := threads[0]
html += buildThreadPages(&thread) + "<br />\n"
@ -332,7 +332,7 @@ func buildThreads(all bool, boardid, threadid int) (html string) {
threads, _ := getPostArr(map[string]interface{}{
"boardid": boardid,
"parentid": 0,
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, "")
if len(threads) == 0 {
return
@ -356,7 +356,7 @@ func buildThreadPages(op *PostTable) (html string) {
replies, err = getPostArr(map[string]interface{}{
"boardid": op.BoardID,
"parentid": op.ID,
"deleted_timestamp": nil_timestamp,
"deleted_timestamp": nilTimestamp,
}, "ORDER BY `id` ASC")
if err != nil {
html += handleError(1, "Error building thread "+strconv.Itoa(op.ID)+":"+err.Error())
@ -376,7 +376,7 @@ func buildThreadPages(op *PostTable) (html string) {
op.NumPages = len(thread_pages)
current_page_filepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening "+current_page_filepath+": "+err.Error())
return
@ -384,9 +384,9 @@ func buildThreadPages(op *PostTable) (html string) {
// render main page
if err = img_threadpage_tmpl.Execute(current_page_file, map[string]interface{}{
"config": config,
"boards": all_boards,
"boards": allBoards,
"board": board,
"sections": all_sections,
"sections": allSections,
"posts": replies,
"op": op,
}); err != nil {
@ -395,7 +395,7 @@ func buildThreadPages(op *PostTable) (html string) {
}
// Put together the thread JSON
threadJSONFile, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
threadJSONFile, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening /%s/res/%d.json: %s", board.Dir, op.ID, err.Error())
return
@ -432,7 +432,7 @@ func buildThreadPages(op *PostTable) (html string) {
for page_num, page_posts := range thread_pages {
op.CurrentPage = page_num + 1
current_page_filepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+"p"+strconv.Itoa(op.CurrentPage)+".html")
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
html += handleError(1, "Failed opening "+current_page_filepath+": "+err.Error()) + "<br />\n"
return
@ -440,9 +440,9 @@ func buildThreadPages(op *PostTable) (html string) {
if err = img_threadpage_tmpl.Execute(current_page_file, map[string]interface{}{
"config": config,
"boards": all_boards,
"boards": allBoards,
"board": board,
"sections": all_sections,
"sections": allSections,
"posts": page_posts,
"op": op,
}); err != nil {
@ -463,7 +463,7 @@ func buildFrontPage() (html string) {
var recent_posts_arr []interface{}
os.Remove(path.Join(config.DocumentRoot, "index.html"))
front_file, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
front_file, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
return handleError(1, "Failed opening front page for writing: "+err.Error()) + "<br />\n"
}
@ -502,7 +502,7 @@ func buildFrontPage() (html string) {
}
defer closeStatement(stmt)
rows, err = stmt.Query(nil_timestamp, config.MaxRecentPosts)
rows, err = stmt.Query(nilTimestamp, config.MaxRecentPosts)
if err != nil {
return handleError(1, "Failed getting list of recent posts for front page: "+err.Error())
}
@ -518,8 +518,8 @@ func buildFrontPage() (html string) {
if err = front_page_tmpl.Execute(front_file, map[string]interface{}{
"config": config,
"fronts": front_arr,
"boards": all_boards,
"sections": all_sections,
"boards": allBoards,
"sections": allSections,
"recent_posts": recent_posts_arr,
}); err != nil {
return handleError(1, "Failed executing front page template: "+err.Error())
@ -528,7 +528,7 @@ func buildFrontPage() (html string) {
}
func buildBoardListJSON() (html string) {
board_list_file, err := os.OpenFile(path.Join(config.DocumentRoot, "boards.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
board_list_file, err := os.OpenFile(path.Join(config.DocumentRoot, "boards.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
return handleError(1, "Failed opening board.json for writing: "+err.Error()) + "<br />\n"
}
@ -539,7 +539,7 @@ func buildBoardListJSON() (html string) {
// Our cooldowns are site-wide currently.
cooldowns_obj := BoardCooldowns{NewThread: config.NewThreadDelay, Reply: config.ReplyDelay, ImageReply: config.ReplyDelay}
for _, board_int := range all_boards {
for _, board_int := range allBoards {
board := board_int.(BoardsTable)
board_obj := BoardJSON{BoardName: board.Dir, Title: board.Title, WorkSafeBoard: 1,
ThreadsPerPage: config.ThreadsPerPage_img, Pages: board.MaxPages, MaxFilesize: board.MaxImageSize,
@ -576,7 +576,7 @@ func bumpThread(postID, boardID int) error {
// Checks check poster's name/tripcode/file checksum (from PostTable post) for banned status
// returns true if the user is banned
func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interface{}, error) {
var is_expired bool
var isExpired bool
var ban_entry BanlistTable
var interfaces []interface{}
// var count int
@ -594,18 +594,14 @@ func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interfac
// the user isn't banned
// We don't need to return err because it isn't necessary
return interfaces, nil
} else {
// something went wrong
return interfaces, err
}
return interfaces, err // something went wrong
} else {
is_expired = ban_entry.Expires.After(time.Now()) == false
if is_expired {
isExpired = ban_entry.Expires.After(time.Now()) == false
if isExpired {
// if it is expired, send a message saying that it's expired, but still post
println(1, "expired")
return interfaces, nil
}
// the user's IP is in the banlist. Check if the ban has expired
if getSpecificSQLDateTime(ban_entry.Expires) == "0001-01-01 00:00:00" || ban_entry.Expires.After(time.Now()) {
@ -619,7 +615,6 @@ func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interfac
}
return interfaces, nil
}
return interfaces, nil
}
func sinceLastPost(post *PostTable) int {
@ -673,7 +668,8 @@ func createVideoThumbnail(video, thumb string, size int) error {
}
func getVideoInfo(path string) (map[string]int, error) {
var vidInfo map[string]int
vidInfo := make(map[string]int)
outputBytes, err := exec.Command("ffprobe", "-v quiet", "-show_format", "-show_streams", path).CombinedOutput()
if err == nil && outputBytes != nil {
outputStringArr := strings.Split(string(outputBytes), "\n")
@ -915,7 +911,7 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
thumbPath := path.Join(config.DocumentRoot, "/"+boardDir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "t."+thumbFiletype, -1))
catalogThumbPath := path.Join(config.DocumentRoot, "/"+boardDir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "c."+thumbFiletype, -1))
if err := ioutil.WriteFile(filePath, data, 0777); err != nil {
if err := ioutil.WriteFile(filePath, data, 0600); err != nil {
handleError(0, "Couldn't write file \""+post.Filename+"\""+err.Error())
serveErrorPage(w, "Couldn't write file \""+post.FilenameOriginal+"\"")
return
@ -1146,10 +1142,11 @@ func formatMessage(message string) string {
// the link is in fact, a valid int
var boardDir string
var linkParent int
stmt, _ := db.Prepare("SELECT `dir`,`parentid` FROM " + config.DBprefix + "posts," + config.DBprefix + "boards WHERE " + config.DBprefix + "posts.id = ?")
stmt, err := db.Prepare("SELECT `dir`,`parentid` FROM " + config.DBprefix + "posts," + config.DBprefix + "boards WHERE " + config.DBprefix + "posts.id = ?")
handleError(1, customError(err))
stmt.QueryRow(word[8:]).Scan(&boardDir, &linkParent)
// get post board dir
// get post board dir
if boardDir == "" {
lineWords[w] = "<a href=\"javascript:;\"><strike>" + word + "</strike></a>"
} else if linkParent == 0 {

View file

@ -23,8 +23,8 @@ var (
)
type GochanServer struct {
writer http.ResponseWriter
request http.Request
/* writer http.ResponseWriter
request http.Request */
namespaces map[string]func(http.ResponseWriter, *http.Request, interface{})
}
@ -105,7 +105,7 @@ func serveNotFound(writer http.ResponseWriter, request *http.Request) {
func serveErrorPage(writer http.ResponseWriter, err string) {
errorPageBytes, _ := ioutil.ReadFile("templates/error.html")
errorPage := strings.Replace(string(errorPageBytes), "{ERRORTEXT}", err, -1)
writer.Write([]byte(errorPage))
_, _ = writer.Write([]byte(errorPage))
}
func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
@ -127,8 +127,8 @@ func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Reques
func initServer() {
listener, err := net.Listen("tcp", config.ListenIP+":"+strconv.Itoa(config.Port))
if err != nil {
printf(0, "Failed listening on %s:%d, see log for details", config.ListenIP, config.Port)
errorLog.Fatal(err.Error())
handleError(0, "Failed listening on %s:%d: %s", config.ListenIP, config.Port, customError(err))
os.Exit(2)
}
server = new(GochanServer)
server.namespaces = make(map[string]func(http.ResponseWriter, *http.Request, interface{}))
@ -151,10 +151,16 @@ func initServer() {
server.AddNamespace("post", makePost)
server.AddNamespace("util", utilHandler)
// eventually plugins will be able to register new namespaces. Or they will be restricted to something like /plugin
if config.UseFastCGI {
fcgi.Serve(listener, server)
err = fcgi.Serve(listener, server)
} else {
http.Serve(listener, server)
err = http.Serve(listener, server)
}
if err != nil {
handleError(0, customError(err))
os.Exit(2)
}
}
@ -257,7 +263,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
}
defer closeStatement(stmt)
err = stmt.QueryRow(&post.ID, &post.BoardID, nil_timestamp).Scan(&post.ParentID, &post.Filename, &post.Password)
err = stmt.QueryRow(&post.ID, &post.BoardID, nilTimestamp).Scan(&post.ParentID, &post.Filename, &post.Password)
if err == sql.ErrNoRows {
//the post has already been deleted
writer.Header().Add("refresh", "4;url="+request.Referer())

View file

@ -2,7 +2,6 @@ package main
import (
"database/sql"
"fmt"
"io/ioutil"
"os"
"strings"
@ -13,8 +12,8 @@ import (
)
const (
nil_timestamp = "0000-00-00 00:00:00"
mysql_datetime_format = "2006-01-02 15:04:05"
nilTimestamp = "0000-00-00 00:00:00"
mysqlDatetimeFormat = "2006-01-02 15:04:05"
)
var (
@ -27,88 +26,71 @@ func connectToSQLServer() {
db, err = sql.Open("mysql", config.DBusername+":"+config.DBpassword+"@"+config.DBhost+"/"+config.DBname+"?parseTime=true&collation=utf8mb4_unicode_ci")
if err != nil {
println(0, "Failed to connect to the database, see log for details.")
errorLog.Fatal(err.Error())
printf(0, "Failed to connect to the database: ")
handleError(0, customError(err))
os.Exit(2)
}
// get the number of tables in the database. If the number > 1, we can assume that initial setup has already been run
var num_rows int
err = db.QueryRow("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '" + config.DBname + "'").Scan(&num_rows)
var numRows int
err = db.QueryRow("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = ?", config.DBname).Scan(&numRows)
if err == sql.ErrNoRows {
num_rows = 0
numRows = 0
} else if err != nil {
println(0, "Failed retrieving list of tables in database.")
errorLog.Fatal(err.Error())
printf(0, "Failed retrieving list of tables in database: ")
handleError(0, customError(err))
os.Exit(2)
}
// Detect that there are at least the number of tables that we are setting up.
// If there are fewer than that, then we either half-way set up, or there's other tables in our database.
if num_rows >= 16 {
if numRows >= 16 {
// the initial setup has already been run
needsInitialSetup = false
dbConnected = true
println(0, "complete.")
return
} else {
// check if initialsetupdb.sql still exists
if _, err := os.Stat("initialsetupdb.sql"); err != nil {
println(0, "Initial setup file (initialsetupdb.sql) missing. Please reinstall gochan")
errorLog.Fatal("Initial setup file (initialsetupdb.sql) missing. Please reinstall gochan")
}
}
// read the initial setup sql file into a string
initial_sql_bytes, err := ioutil.ReadFile("initialsetupdb.sql")
if err != nil {
println(0, "failed, see log for details.")
errorLog.Fatal("Error reading initialsetupdb.sql: " + err.Error())
}
initial_sql_str := string(initial_sql_bytes)
initial_sql_bytes = nil
printf(0, "Starting initial setup...")
initial_sql_str = strings.Replace(initial_sql_str, "DBNAME", config.DBname, -1)
initial_sql_str = strings.Replace(initial_sql_str, "DBPREFIX", config.DBprefix, -1)
initial_sql_str += "\nINSERT INTO `" + config.DBname + "`.`" + config.DBprefix + "staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '" + bcryptSum("password") + "', 'abc', 3);"
initial_sql_arr := strings.Split(initial_sql_str, ";")
initial_sql_str = ""
// check if initialsetupdb.sql still exists
if _, err = os.Stat("initialsetupdb.sql"); err != nil {
println(0, "Initial setup file (initialsetupdb.sql) missing. Please reinstall gochan")
errorLog.Fatal("Initial setup file (initialsetupdb.sql) missing. Please reinstall gochan")
}
for _, statement := range initial_sql_arr {
if statement != "" {
if _, err := db.Exec(statement); err != nil {
println(0, "failed, see log for details.")
errorLog.Fatal("Error executing initialsetupdb.sql: " + err.Error())
return
}
// read the initial setup sql file into a string
initialSQLBytes, err := ioutil.ReadFile("initialsetupdb.sql")
if err != nil {
printf(0, "failed: ")
handleError(0, customError(err))
os.Exit(2)
}
initialSQLStr := string(initialSQLBytes)
printf(0, "Starting initial setup...")
initialSQLStr = strings.Replace(initialSQLStr, "DBNAME", config.DBname, -1)
initialSQLStr = strings.Replace(initialSQLStr, "DBPREFIX", config.DBprefix, -1)
initialSQLStr += "\nINSERT INTO `" + config.DBname + "`.`" + config.DBprefix + "staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '" + bcryptSum("password") + "', 'abc', 3);"
initialSQLArr := strings.Split(initialSQLStr, ";")
for _, statement := range initialSQLArr {
if statement != "" {
if _, err := db.Exec(statement); err != nil {
println(0, "failed, see log for details.")
errorLog.Fatal("Error executing initialsetupdb.sql: " + customError(err))
return
}
}
println(0, "complete.")
needsInitialSetup = false
dbConnected = true
}
println(0, "complete.")
needsInitialSetup = false
dbConnected = true
}
func getSQLDateTime() string {
now := time.Now()
return now.Format(mysql_datetime_format)
return time.Now().Format(mysqlDatetimeFormat)
}
func getSpecificSQLDateTime(t time.Time) string {
return t.Format(mysql_datetime_format)
}
func makeInsertString(table string, columns []string) string {
columnString := ""
valuePlaceholders := ""
for i, column := range columns {
columnString += "`" + column + "`"
if i < len(columns)-1 {
columnString += ", "
}
//valuePlaceholders += fmt.Sprintf("$%d", i+1)
valuePlaceholders += "?"
if i < len(columns)-1 {
valuePlaceholders += ", "
}
}
return fmt.Sprintf("INSERT INTO %s%s (%s) VALUES (%s)",
config.DBprefix, table, columnString, valuePlaceholders)
return t.Format(mysqlDatetimeFormat)
}

View file

@ -108,7 +108,7 @@ type BoardsTable struct {
MaxMessageLength int
EmbedsAllowed bool
RedirectToThread bool
ShowId bool
ShowID bool
RequireFile bool
EnableCatalog bool
EnableSpoileredImages bool
@ -126,6 +126,8 @@ type BoardSectionsTable struct {
Abbreviation string
}
// EmbedsTable represents the embedable media on different sites.
// It's held over from Kusaba X and may be removed in the future
type EmbedsTable struct {
ID uint8
Filetype string
@ -136,6 +138,8 @@ type EmbedsTable struct {
EmbedCode string
}
// FiletypesTable represents the allowed filetypes
// It's held over from Kusaba X and may be removed in the future
type FiletypesTable struct {
ID uint8
Filetype string
@ -145,6 +149,7 @@ type FiletypesTable struct {
ImageH uint
}
// FrontTable represents the information (News, rules, etc) on the front page
type FrontTable struct {
IName string
ID int
@ -157,6 +162,7 @@ type FrontTable struct {
Email string
}
// FrontLinksTable is used for linking to sites that the admin linkes
type FrontLinksTable struct {
ID uint8
Title string
@ -177,6 +183,7 @@ type ModLogTable struct {
Timestamp time.Time
}
// PollResultsTable may or may not be used in the future for polls (duh)
type PollResultsTable struct {
ID uint
IP string
@ -184,6 +191,7 @@ type PollResultsTable struct {
Timestamp time.Time
}
// PostTable represents each post in the database
type PostTable struct {
IName string
ID int
@ -236,6 +244,7 @@ type SessionsTable struct {
Expires string
}
// StaffTable represents a single staff member's info stored in the database
type StaffTable struct {
ID int
Username string
@ -320,8 +329,7 @@ type ThreadJSON struct {
Locked int `json:"locked"`
}
// Global variables, most initialized by config.cfg
// GochanConfig stores crucial info and is read from/written to gochan.json
type GochanConfig struct {
IName string //used by our template parser
ListenIP string
@ -469,7 +477,7 @@ func initConfig() {
os.Exit(2)
}
accessLogFile, err := os.OpenFile(path.Join(config.LogDir, "access.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
accessLogFile, err := os.OpenFile(path.Join(config.LogDir, "access.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
println(0, "Couldn't open access log. Returned error: "+err.Error())
os.Exit(1)
@ -478,7 +486,7 @@ func initConfig() {
}
errorLogFile, err := os.OpenFile(path.Join(config.LogDir, "error.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
errorLogFile, err := os.OpenFile(path.Join(config.LogDir, "error.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
println(0, "Couldn't open error log. Returned error: "+err.Error())
os.Exit(1)
@ -486,7 +494,7 @@ func initConfig() {
errorLog = log.New(errorLogFile, "", log.Ltime|log.Ldate)
}
modLogFile, err := os.OpenFile(path.Join(config.LogDir, "mod.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
modLogFile, err := os.OpenFile(path.Join(config.LogDir, "mod.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
println(0, "Couldn't open mod log. Returned error: "+err.Error())
} else {

View file

@ -78,19 +78,19 @@ func byteByByteReplace(input, from, to string) string {
// for easier defer cleaning
func closeFile(file *os.File) {
if file != nil {
file.Close()
_ = file.Close()
}
}
func closeRows(rows *sql.Rows) {
if rows != nil {
rows.Close()
_ = rows.Close()
}
}
func closeStatement(stmt *sql.Stmt) {
if stmt != nil {
stmt.Close()
_ = stmt.Close()
}
}
@ -397,15 +397,12 @@ func getMetaInfo(stackOffset int) (string, int, string) {
return file, line, runtime.FuncForPC(pc).Name()
}
func customError(v int, err error) (errored bool) {
func customError(err error) string {
if err != nil {
if config.Verbosity >= v {
file, line, _ := getMetaInfo(1)
printf(v, "[ERROR] %s:%d: %s\n", file, line, err.Error())
}
return true
file, line, _ := getMetaInfo(2)
return fmt.Sprintf("[ERROR] %s:%d: %s\n", file, line, err.Error())
}
return false
return ""
}
func handleError(verbosity int, format string, a ...interface{}) string {
@ -459,24 +456,16 @@ func println(v int, a ...interface{}) {
func resetBoardSectionArrays() {
// run when the board list needs to be changed (board/section is added, deleted, etc)
all_boards = nil
all_sections = nil
allBoards = nil
allSections = nil
allBoardsArr, _ := getBoardArr(nil, "")
for _, b := range allBoardsArr {
all_boards = append(all_boards, b)
allBoards = append(allBoards, b)
}
allSectionsArr, _ := getSectionArr("")
for _, b := range allSectionsArr {
all_sections = append(all_sections, b)
}
}
func reverse(arr []interface{}) (reversed []interface{}) {
for i := len(arr); i > 0; i-- {
reversed = append(reversed, arr[i-1])
}
return
allSectionsArr, _ := getSectionArr("")
allSections = append(allSections, allSectionsArr...)
}
// sanitize/escape HTML strings in a post. This should be run immediately before