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:
parent
f1df7aefce
commit
6a4443dbc6
7 changed files with 234 additions and 238 deletions
|
@ -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()
|
||||
}
|
||||
|
|
189
src/manage.go
189
src/manage.go
|
@ -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(¤t_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()))
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
108
src/sql.go
108
src/sql.go
|
@ -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)
|
||||
}
|
||||
|
|
20
src/types.go
20
src/types.go
|
@ -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 {
|
||||
|
|
35
src/util.go
35
src/util.go
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue