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

More abstraction to make SQL queries simpler, initialsetupdb.sql is now called on every startup

This commit is contained in:
Joshua Merrell 2018-05-23 12:15:46 -07:00
parent 6a4443dbc6
commit 9597760442
13 changed files with 313 additions and 322 deletions

View file

@ -1,5 +1,4 @@
-- Initial setup file for Gochan
-- Deleted after setup is finished
-- Turn off warnings in case tables are already there.
SET sql_notes=0;
@ -200,11 +199,11 @@ CREATE TABLE IF NOT EXISTS `DBPREFIXstaff` (
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
# create a temp table with the same columns as the posts table to be stored in memory
# This is currently not used, and commented out.
#CREATE TABLE IF NOT EXISTS `DBPREFIXtempposts` SELECT * FROM DBPREFIXposts;
#ALTER TABLE `DBPREFIXtempposts` CHANGE `message` `message` VARCHAR(1024);
#ALTER TABLE `DBPREFIXtempposts` ENGINE=MEMORY;
-- create a temp table with the same columns as the posts table to be stored in memory
-- This is currently not used, and commented out.
-- CREATE TABLE IF NOT EXISTS `DBPREFIXtempposts` SELECT * FROM DBPREFIXposts;
-- ALTER TABLE `DBPREFIXtempposts` CHANGE `message` `message` VARCHAR(1024);
-- ALTER TABLE `DBPREFIXtempposts` ENGINE=MEMORY;
CREATE TABLE IF NOT EXISTS `DBPREFIXwordfilters` (
`id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,

View file

@ -1,2 +0,0 @@
This file is in here to keep the log directory around, as gochan expects the log
directory to exist before it runs.

View file

@ -16,7 +16,11 @@ var verbosityString string
var buildtimeString string // set in Makefile, format: YRMMDD.HHMM
func main() {
defer db.Close()
defer func() {
if db != nil {
_ = db.Close()
}
}()
initConfig()
config.Verbosity, _ = strconv.Atoi(verbosityString)
config.Version = version
@ -26,7 +30,7 @@ func main() {
println(0, "Loading and parsing templates...")
if err := initTemplates(); err != nil {
println(0, err.Error())
handleError(0, customError(err))
os.Exit(2)
}
@ -34,7 +38,8 @@ func main() {
if db != nil {
_, err := db.Exec("USE `" + config.DBname + "`")
if err != nil {
println(0, customError(err))
handleError(0, customError(err))
os.Exit(2)
}
}
initServer()

View file

@ -87,19 +87,24 @@ func getCurrentStaff() (string, error) {
}
key = sessionCookie.Value
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 {
if err := queryRowSQL(
"SELECT `data` FROM `"+config.DBprefix+"sessions` WHERE `key` = ?",
[]interface{}{key},
[]interface{}{&current_session.Data},
); err != nil {
return "", err
}
return current_session.Data, nil
}
func getStaff(name string) (*StaffTable, error) {
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)
err := queryRowSQL(
"SELECT * FROM `"+config.DBprefix+"staff` WHERE `username` = ?",
[]interface{}{name},
[]interface{}{&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
}
@ -124,7 +129,7 @@ func getStaffRank() int {
func createSession(key string, username string, password string, request *http.Request, writer *http.ResponseWriter) int {
//returns 0 for successful, 1 for password mismatch, and 2 for other
domain := request.Host
var err error
chopPortNumRegex := regexp.MustCompile("(.+|\\w+):(\\d+)$")
domain = chopPortNumRegex.Split(domain, -1)[0]
@ -146,13 +151,17 @@ func createSession(key string, username string, password string, request *http.R
// successful login, add cookie that expires in one month
cookie := &http.Cookie{Name: "sessiondata", Value: key, Path: "/", Domain: domain, Expires: time.Now().Add(time.Duration(time.Hour * 730))}
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 {
if _, err = execSQL(
"INSERT INTO `"+config.DBprefix+"sessions` (`key`, `data`, `expires`) VALUES(?,?,?)",
key, username, getSpecificSQLDateTime(time.Now().Add(time.Duration(time.Hour*730))),
); err != nil {
handleError(1, customError(err))
return 2
}
_, err = db.Exec("UPDATE `"+config.DBprefix+"staff` SET `last_active` = ? WHERE `username` = ?", getSQLDateTime(), username)
if err != nil {
if _, err = execSQL(
"UPDATE `"+config.DBprefix+"staff` SET `last_active` = ? WHERE `username` = ?", getSQLDateTime(), username,
); err != nil {
handleError(1, customError(err))
}
return 0
@ -165,10 +174,12 @@ var manage_functions = map[string]ManageFunction{
Permissions: 3,
Callback: func() (html string) {
html = "<h2>Cleanup</h2><br />"
var err error
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` = '" + nilTimestamp + "'")
if err != nil {
if _, err = execSQL(
"DELETE FROM `"+config.DBprefix+"posts` WHERE `deleted_timestamp` = ?", nilTimestamp,
); err != nil {
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
}
@ -176,7 +187,8 @@ var manage_functions = map[string]ManageFunction{
// TODO: remove orphaned uploads
html += "Optimizing all tables in database.<hr />"
tableRows, tablesErr := db.Query("SHOW TABLES")
tableRows, tablesErr := querySQL("SHOW TABLES")
defer closeRows(tableRows)
if tablesErr != nil {
html += "<tr><td>" + tablesErr.Error() + "</td></tr></table>"
return
@ -185,8 +197,7 @@ var manage_functions = map[string]ManageFunction{
for tableRows.Next() {
var table string
tableRows.Scan(&table)
_, err = db.Exec("OPTIMIZE TABLE " + table)
if err != nil {
if _, err := execSQL("OPTIMIZE TABLE `" + table + "`"); err != nil {
html += handleError(1, err.Error()) + "<br />"
return
}
@ -230,7 +241,8 @@ var manage_functions = map[string]ManageFunction{
Permissions: 3,
Callback: func() (html string) {
html = "<img src=\"/css/purge.jpg\" />"
rows, err := db.Query("SELECT `dir` FROM `" + config.DBprefix + "boards`")
rows, err := querySQL("SELECT `dir` FROM `" + config.DBprefix + "boards`")
defer closeRows(rows)
if err != nil {
html += err.Error()
handleError(1, customError(err))
@ -264,16 +276,20 @@ var manage_functions = map[string]ManageFunction{
return
}
}
if _, err = db.Exec("TRUNCATE `" + config.DBprefix + "posts`"); err != nil {
if _, err = execSQL("TRUNCATE `" + config.DBprefix + "posts`"); err != nil {
html += err.Error() + "<br />"
handleError(1, customError(err))
return
}
if _, err = execSQL("ALTER TABLE `" + config.DBprefix + "posts` AUTO_INCREMENT = 1"); err != nil {
html += err.Error() + "<br />"
handleError(1, customError(err))
return
}
db.Exec("ALTER TABLE `" + config.DBprefix + "posts` AUTO_INCREMENT = 1")
html += "<br />Everything purged, rebuilding all<br />" +
buildBoards(true, 0) + "<hr />\n" +
buildFrontPage()
return
}},
"executesql": {
@ -283,8 +299,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 />"
_, sqlerr := db.Exec(statement)
if sqlerr != nil {
if _, sqlerr := execSQL(statement); sqlerr != nil {
html += handleError(1, sqlerr.Error())
} else {
html += "Statement esecuted successfully."
@ -349,7 +364,8 @@ 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 := querySQL("SELECT `subject`,`message`,`poster`,`timestamp` FROM `" + config.DBprefix + "announcements` ORDER BY `id` DESC")
defer closeRows(rows)
if err != nil {
html += handleError(1, err.Error())
return
@ -399,7 +415,8 @@ 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 := querySQL("SELECT `dir` FROM `" + config.DBprefix + "boards`")
defer closeRows(rows)
if err != nil {
html += "<hr />" + handleError(1, err.Error())
return
@ -451,7 +468,7 @@ var manage_functions = map[string]ManageFunction{
"<input type=\"submit\" name=\"ban-both-button\" value=\"Ban both\" /></form>\n</br />" +
"<h2>Banned IPs</h2>\n"
rows, err = db.Query("SELECT * FROM `" + config.DBprefix + "banlist`")
rows, err = querySQL("SELECT * FROM `" + config.DBprefix + "banlist`")
if err != nil {
html += "</table><br />" + handleError(1, err.Error())
return
@ -502,9 +519,11 @@ var manage_functions = map[string]ManageFunction{
html = "nobody;0;"
return
}
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 {
if err := queryRowSQL("SELECT `rank`,`boards` FROM `"+config.DBprefix+"staff` WHERE `username` = ?",
[]interface{}{current_staff},
[]interface{}{&staff.Rank, &staff.Boards},
); err != nil {
html += handleError(1, "Error getting staff list: "+err.Error())
return
}
@ -619,33 +638,26 @@ var manage_functions = map[string]ManageFunction{
board_creation_status = handleError(1, "ERROR: directory /"+config.DocumentRoot+"/"+board.Dir+"/src/ already exists!")
break
}
stmt, err := db.Prepare(
"INSERT INTO `" + config.DBprefix + "boards` (`order`,`dir`,`type`,`upload_type`,`title`,`subtitle`," +
"`description`,`section`,`max_image_size`,`max_pages`,`locale`,`default_style`,`locked`,`created_on`," +
"`anonymous`,`forced_anon`,`max_age`,`autosage_after`,`no_images_after`,`max_message_length`,`embeds_allowed`," +
"`redirect_to_thread`,`require_file`,`enable_catalog`) " +
"VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
if err != nil {
do = ""
board_creation_status = handleError(1, err.Error())
break
}
defer closeStatement(stmt)
boardCreationTimestamp := getSpecificSQLDateTime(board.CreatedOn)
if _, err = stmt.Exec(
&board.Order, &board.Dir, &board.Type, &board.UploadType,
&board.Title, &board.Subtitle, &board.Description, &board.Section,
&board.MaxImageSize, &board.MaxPages, &board.Locale, &board.DefaultStyle,
&board.Locked, &boardCreationTimestamp, &board.Anonymous,
&board.ForcedAnon, &board.MaxAge, &board.AutosageAfter,
&board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed,
&board.RedirectToThread, &board.RequireFile, &board.EnableCatalog,
if _, err := execSQL(
"INSERT INTO `"+config.DBprefix+"boards` (`order`,`dir`,`type`,`upload_type`,`title`,`subtitle`,"+
"`description`,`section`,`max_image_size`,`max_pages`,`locale`,`default_style`,`locked`,`created_on`,"+
"`anonymous`,`forced_anon`,`max_age`,`autosage_after`,`no_images_after`,`max_message_length`,`embeds_allowed`,"+
"`redirect_to_thread`,`require_file`,`enable_catalog`) "+
"VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[]interface{}{
&board.Order, &board.Dir, &board.Type, &board.UploadType,
&board.Title, &board.Subtitle, &board.Description, &board.Section,
&board.MaxImageSize, &board.MaxPages, &board.Locale, &board.DefaultStyle,
&board.Locked, &boardCreationTimestamp, &board.Anonymous,
&board.ForcedAnon, &board.MaxAge, &board.AutosageAfter,
&board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed,
&board.RedirectToThread, &board.RequireFile, &board.EnableCatalog,
},
); err != nil {
do = ""
board_creation_status = customError(err)
handleError(1, "Error creating board: "+board_creation_status)
board_creation_status = handleError(1, "Error creating board: "+customError(err))
break
} else {
board_creation_status = "Board created successfully"
println(2, board_creation_status)
@ -661,7 +673,7 @@ var manage_functions = map[string]ManageFunction{
// resetBoardSectionArrays()
default:
// put the default column values in the text boxes
rows, err = db.Query("SELECT `column_name`,`columnDefault` FROM `information_schema`.`columns` WHERE `table_name` = '" + config.DBprefix + "boards'")
rows, err = querySQL("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
@ -726,12 +738,12 @@ var manage_functions = map[string]ManageFunction{
}
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 = querySQL("SELECT `dir` FROM `" + config.DBprefix + "boards`")
defer closeRows(rows)
if err != nil {
html += handleError(1, err.Error())
return
}
defer closeRows(rows)
for rows.Next() {
var boardDir string
@ -745,7 +757,7 @@ var manage_functions = map[string]ManageFunction{
manageBoardsBuffer := bytes.NewBufferString("")
allSections, _ = getSectionArr("")
if len(allSections) == 0 {
db.Exec("INSERT INTO `" + config.DBprefix + "sections` (`hidden`,`name`,`abbreviation`) VALUES(0,'Main','main')")
execSQL("INSERT INTO `" + config.DBprefix + "sections` (`hidden`,`name`,`abbreviation`) VALUES(0,'Main','main')")
}
allSections, _ = getSectionArr("")
@ -824,14 +836,13 @@ var manage_functions = map[string]ManageFunction{
}
for _, post := range posts {
stmt, err := db.Prepare("UPDATE `" + config.DBprefix + "posts` SET `message` = ? WHERE `id` = ? AND `boardid` = ?")
_, err = execSQL("UPDATE `"+config.DBprefix+"posts` SET `message` = ? WHERE `id` = ? AND `boardid` = ?",
formatMessage(post.MessageText), post.ID, post.BoardID,
)
if err != nil {
html += handleError(1, err.Error()) + "<br />"
return
}
defer closeStatement(stmt)
stmt.Exec(formatMessage(post.MessageText), post.ID, post.BoardID)
}
html += "Done reparsing HTML<hr />" +
buildFrontPage() + "<hr />\n" +
@ -847,27 +858,30 @@ 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`, " +
"`" + config.DBprefix + "posts`.`boardid` AS boardid, " +
"`" + config.DBprefix + "posts`.`id` AS id, " +
"`" + config.DBprefix + "posts`. " +
"`parentid` AS parentid, " +
"`" + config.DBprefix + "posts`. " +
"`message` AS message, " +
"`" + config.DBprefix + "posts`. " +
"`ip` AS ip, " +
"`" + config.DBprefix + "posts`. " +
"`timestamp` AS timestamp " +
"FROM `" + config.DBprefix + "posts`, `" + config.DBprefix + "boards` " +
"WHERE `reviewed` = 0 " +
"AND `" + config.DBprefix + "posts`.`deleted_timestamp` = \"" + nilTimestamp + "\" " +
"AND `boardid` = `" + config.DBprefix + "boards`.`id` " +
"ORDER BY `timestamp` DESC LIMIT " + limit + "")
rows, err := querySQL(
"SELECT `"+config.DBprefix+"boards`.`dir` AS `boardname`, "+
"`"+config.DBprefix+"posts`.`boardid` AS boardid, "+
"`"+config.DBprefix+"posts`.`id` AS id, "+
"`"+config.DBprefix+"posts`. "+
"`parentid` AS parentid, "+
"`"+config.DBprefix+"posts`. "+
"`message` AS message, "+
"`"+config.DBprefix+"posts`. "+
"`ip` AS ip, "+
"`"+config.DBprefix+"posts`. "+
"`timestamp` AS timestamp "+
"FROM `"+config.DBprefix+"posts`, `"+config.DBprefix+"boards` "+
"WHERE `reviewed` = 0 "+
"AND `"+config.DBprefix+"posts`.`deleted_timestamp` = ? "+
"AND `boardid` = `"+config.DBprefix+"boards`.`id` "+
"ORDER BY `timestamp` DESC LIMIT ?",
nilTimestamp, limit,
)
defer closeRows(rows)
if err != nil {
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
}
defer closeRows(rows)
for rows.Next() {
recentpost := new(RecentPost)
@ -891,16 +905,16 @@ var manage_functions = map[string]ManageFunction{
"staff": {
Permissions: 3,
Callback: func() (html string) {
//do := request.FormValue("do")
do := request.FormValue("do")
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 := querySQL("SELECT `username`,`rank`,`boards`,`added_on` FROM `" + config.DBprefix + "staff`")
defer closeRows(rows)
if err != nil {
html += "<tr><td>" + handleError(1, err.Error()) + "</td></tr></table>"
return
}
defer closeRows(rows)
iter := 1
for rows.Next() {
@ -910,28 +924,21 @@ var manage_functions = map[string]ManageFunction{
return err.Error()
}
if request.FormValue("do") == "add" {
if do == "add" {
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 {
if _, err := execSQL("INSERT INTO `"+config.DBprefix+"staff` (`username`, `password_checksum`, `rank`) VALUES(?,?,?)",
&newUsername, bcryptSum(newPassword), &newRank,
); err != nil {
serveErrorPage(writer, handleError(1, err.Error()))
}
defer closeStatement(stmt)
if _, err = stmt.Exec(&newUsername, bcryptSum(newPassword), &newRank); err != nil {
} else if do == "del" && request.FormValue("username") != "" {
if _, err = execSQL("DELETE FROM `"+config.DBprefix+"staff` WHERE `username` = ?",
request.FormValue("username"),
); err != nil {
serveErrorPage(writer, handleError(1, err.Error()))
}
} else if request.FormValue("do") == "del" && request.FormValue("username") != "" {
stmt, err := db.Prepare("DELETE FROM `" + config.DBprefix + "staff` WHERE `username` = ?")
if err != nil {
serveErrorPage(writer, handleError(1, err.Error()))
}
defer closeStatement(stmt)
_, err = stmt.Exec(request.FormValue("username"))
}
var rank string

View file

@ -115,22 +115,18 @@ func buildBoardPages(board *BoardsTable) (html string) {
thread.IName = "thread"
// Get the number of replies to this thread.
stmt, err := db.Prepare("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = ? AND `parentid` = ? AND `deleted_timestamp` = ?")
if err != nil {
html += err.Error() + "<br />\n"
}
defer closeStatement(stmt)
if err = stmt.QueryRow(board.ID, op.ID, nilTimestamp).Scan(&thread.NumReplies); err != nil {
if err = queryRowSQL("SELECT COUNT(*) FROM `"+config.DBprefix+"posts` WHERE `boardid` = ? AND `parentid` = ? AND `deleted_timestamp` = ?",
[]interface{}{board.ID, op.ID, nilTimestamp},
[]interface{}{&thread.NumReplies},
); err != nil {
html += err.Error() + "<br />\n"
}
// Get the number of image replies in this thread
stmt, err = db.Prepare("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = ? AND `parentid` = ? AND `deleted_timestamp` = ? AND `filesize` <> 0")
if err != nil {
html += err.Error() + "<br />\n"
}
if err = stmt.QueryRow(board.ID, op.ID, nilTimestamp).Scan(&thread.NumImages); err != nil {
if err = queryRowSQL("SELECT COUNT(*) FROM `"+config.DBprefix+"posts` WHERE `boardid` = ? AND `parentid` = ? AND `deleted_timestamp` = ? AND `filesize` <> 0",
[]interface{}{board.ID, op.ID, nilTimestamp},
[]interface{}{&thread.NumImages},
); err != nil {
html += err.Error() + "<br />\n"
}
@ -225,11 +221,12 @@ func buildBoardPages(board *BoardsTable) (html string) {
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, 0600)
defer closeFile(catalog_json_file)
if err != nil {
html += handleError(1, "Failed opening /"+board.Dir+"/catalog.json: "+err.Error())
return
}
defer closeFile(catalog_json_file)
currentBoardPage := board.CurrentPage
for _, page_threads := range thread_pages {
board.CurrentPage++
@ -237,11 +234,11 @@ func buildBoardPages(board *BoardsTable) (html 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, 0600)
defer closeFile(current_page_file)
if err != nil {
html += handleError(1, "Failed opening board page: "+err.Error()) + "<br />"
continue
}
defer closeFile(current_page_file)
// Render the boardpage template, don't forget config
if err = img_boardpage_tmpl.Execute(current_page_file, map[string]interface{}{
@ -396,11 +393,11 @@ 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, 0600)
defer closeFile(threadJSONFile)
if err != nil {
html += handleError(1, "Failed opening /%s/res/%d.json: %s", board.Dir, op.ID, err.Error())
return
}
defer closeFile(threadJSONFile)
// Create the wrapper object
thread_json_wrapper := new(ThreadJSONWrapper)
@ -464,17 +461,17 @@ func buildFrontPage() (html string) {
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, 0600)
defer closeFile(front_file)
if err != nil {
return handleError(1, "Failed opening front page for writing: "+err.Error()) + "<br />\n"
}
defer closeFile(front_file)
// get front pages
rows, err := db.Query("SELECT * FROM `" + config.DBprefix + "frontpage`")
rows, err := querySQL("SELECT * FROM `" + config.DBprefix + "frontpage`")
defer closeRows(rows)
if err != nil {
return handleError(1, "Failed getting front page rows: "+err.Error())
}
defer closeRows(rows)
for rows.Next() {
frontpage := new(FrontTable)
@ -487,25 +484,23 @@ func buildFrontPage() (html string) {
}
// get recent posts
stmt, err := db.Prepare(
"SELECT `" + config.DBprefix + "posts`.`id`, " +
"`" + config.DBprefix + "posts`.`parentid`, " +
"`" + config.DBprefix + "boards`.`dir` AS boardname, " +
"`" + config.DBprefix + "posts`.`boardid` AS boardid, " +
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` " +
"FROM `" + config.DBprefix + "posts`, `" + config.DBprefix + "boards` " +
"WHERE `" + config.DBprefix + "posts`.`deleted_timestamp` = ? " +
"AND `boardid` = `" + config.DBprefix + "boards`.`id` " +
"ORDER BY `timestamp` DESC LIMIT ?")
rows, err = querySQL(
"SELECT `"+config.DBprefix+"posts`.`id`, "+
"`"+config.DBprefix+"posts`.`parentid`, "+
"`"+config.DBprefix+"boards`.`dir` AS boardname, "+
"`"+config.DBprefix+"posts`.`boardid` AS boardid, "+
"`name`, `tripcode`, `message`, `filename`, `thumb_w`, `thumb_h` "+
"FROM `"+config.DBprefix+"posts`, `"+config.DBprefix+"boards` "+
"WHERE `"+config.DBprefix+"posts`.`deleted_timestamp` = ? "+
"AND `boardid` = `"+config.DBprefix+"boards`.`id` "+
"ORDER BY `timestamp` DESC LIMIT ?",
nilTimestamp, config.MaxRecentPosts,
)
defer closeRows(rows)
if err != nil {
return handleError(1, err.Error())
}
defer closeStatement(stmt)
rows, err = stmt.Query(nilTimestamp, config.MaxRecentPosts)
if err != nil {
return handleError(1, "Failed getting list of recent posts for front page: "+err.Error())
}
for rows.Next() {
recent_post := new(RecentPost)
err = rows.Scan(&recent_post.PostID, &recent_post.ParentID, &recent_post.BoardName, &recent_post.BoardID, &recent_post.Name, &recent_post.Tripcode, &recent_post.Message, &recent_post.Filename, &recent_post.ThumbW, &recent_post.ThumbH)
@ -529,10 +524,10 @@ 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, 0600)
defer closeFile(board_list_file)
if err != nil {
return handleError(1, "Failed opening board.json for writing: "+err.Error()) + "<br />\n"
}
defer closeFile(board_list_file)
board_list_wrapper := new(BoardJSONWrapper)
@ -563,13 +558,10 @@ func buildBoardListJSON() (html string) {
// bumps the given thread on the given board and returns true if there were no errors
func bumpThread(postID, boardID int) error {
stmt, err := db.Prepare("UPDATE `" + config.DBprefix + "posts` SET `bumped` = ? WHERE `id` = ? AND `boardid` = ?")
if err != nil {
return err
}
defer closeStatement(stmt)
_, err := execSQL("UPDATE `"+config.DBprefix+"posts` SET `bumped` = ? WHERE `id` = ? AND `boardid` = ?",
[]interface{}{time.Now(), postID, boardID},
)
_, err = stmt.Exec(time.Now(), postID, boardID)
return err
}
@ -581,51 +573,44 @@ func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interfac
var interfaces []interface{}
// var count int
// var search string
stmt, err := db.Prepare("SELECT `ip`, `name`, `tripcode`, `message`, `boards`, `timestamp`, `expires`, `appeal_at` FROM `" + config.DBprefix + "banlist` WHERE `ip` = ?")
if err != nil {
err := queryRowSQL("SELECT `ip`, `name`, `tripcode`, `message`, `boards`, `timestamp`, `expires`, `appeal_at` FROM `"+config.DBprefix+"banlist` WHERE `ip` = ?",
[]interface{}{&post.IP},
[]interface{}{&ban_entry.IP, &ban_entry.Name, &ban_entry.Tripcode, &ban_entry.Message, &ban_entry.Boards, &ban_entry.Timestamp, &ban_entry.Expires, &ban_entry.AppealAt},
)
if err == sql.ErrNoRows {
// the user isn't banned
// We don't need to return err because it isn't necessary
return interfaces, nil
} else if err != nil {
handleError(1, "Error checking banned status: "+err.Error())
return interfaces, err
}
defer closeStatement(stmt)
err = stmt.QueryRow(&post.IP).Scan(&ban_entry.IP, &ban_entry.Name, &ban_entry.Tripcode, &ban_entry.Message, &ban_entry.Boards, &ban_entry.Timestamp, &ban_entry.Expires, &ban_entry.AppealAt)
if err != nil {
if err == sql.ErrNoRows {
// the user isn't banned
// We don't need to return err because it isn't necessary
return interfaces, nil
}
return interfaces, err // something went wrong
} else {
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()) {
// for some funky reason, Go's MySQL driver seems to not like getting a supposedly nil timestamp as an ACTUAL nil timestamp
// so we're just going to wing it and cheat. Of course if they change that, we're kind of hosed.
var interfaces []interface{}
interfaces = append(interfaces, config)
interfaces = append(interfaces, ban_entry)
return interfaces, nil
}
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()) {
// for some funky reason, Go's MySQL driver seems to not like getting a supposedly nil timestamp as an ACTUAL nil timestamp
// so we're just going to wing it and cheat. Of course if they change that, we're kind of hosed.
return []interface{}{config, ban_entry}, nil
}
return interfaces, nil
}
func sinceLastPost(post *PostTable) int {
var lastPostTime time.Time
if err := db.QueryRow("SELECT `timestamp` FROM `" + config.DBprefix + "posts` WHERE `ip` = '" + post.IP + "' ORDER BY `timestamp` DESC LIMIT 1").Scan(&lastPostTime); err == sql.ErrNoRows {
if err := queryRowSQL("SELECT `timestamp` FROM `"+config.DBprefix+"posts` WHERE `ip` = '?' ORDER BY `timestamp` DESC LIMIT 1",
[]interface{}{post.IP},
[]interface{}{&lastPostTime},
); err == sql.ErrNoRows {
// no posts by that IP.
return -1
} else {
return int(time.Since(lastPostTime).Seconds())
}
return -1
return int(time.Since(lastPostTime).Seconds())
}
func createImageThumbnail(image_obj image.Image, size string) image.Image {
@ -738,13 +723,7 @@ func insertPost(post PostTable, bump bool) (sql.Result, error) {
}
insertValues += " ? )"
stmt, err := db.Prepare(insertString + insertValues)
if err != nil {
return nil, err
}
defer closeStatement(stmt)
result, err = stmt.Exec(
result, err := execSQL(insertString+insertValues,
post.BoardID, post.ParentID, post.Name, post.Tripcode,
post.Email, post.Subject, post.MessageHTML, post.MessageText,
post.Password, post.Filename, post.FilenameOriginal,
@ -753,6 +732,7 @@ func insertPost(post PostTable, bump bool) (sql.Result, error) {
post.Autosage, post.PosterAuthority, post.DeletedTimestamp,
post.Bumped, post.Stickied, post.Locked, post.Reviewed, post.Sillytag,
)
if err != nil {
return result, err
}
@ -821,16 +801,11 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
post.Subject = request.FormValue("postsubject")
post.MessageText = strings.Trim(request.FormValue("postmsg"), "\r\n")
stmt, err := db.Prepare("SELECT `max_message_length` from `" + config.DBprefix + "boards` WHERE `id` = ?")
if err != nil {
serveErrorPage(w, "Error getting board info.")
errorLog.Print("Error getting board info: " + err.Error())
return
}
defer closeStatement(stmt)
if err = stmt.QueryRow(post.BoardID).Scan(&maxMessageLength); err != nil {
serveErrorPage(w, handleError(1, "Requested board does not exist."))
if err := queryRowSQL("SELECT `max_message_length` from `"+config.DBprefix+"boards` WHERE `id` = ?",
[]interface{}{post.BoardID},
[]interface{}{&maxMessageLength},
); err != nil {
serveErrorPage(w, handleError(0, "Error getting board info: "+err.Error()))
return
}
@ -921,14 +896,10 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
post.FileChecksum = fmt.Sprintf("%x", md5.Sum(data))
var allowsVids bool
vidStmt, err := db.Prepare("SELECT `embeds_allowed` FROM `" + config.DBprefix + "boards` WHERE `id` = ? LIMIT 1")
if err != nil {
serveErrorPage(w, handleError(1, "Couldn't get board info: "+err.Error()))
return
}
defer closeStatement(vidStmt)
if err = vidStmt.QueryRow(post.BoardID).Scan(&allowsVids); err != nil {
if err = queryRowSQL("SELECT `embeds_allowed` FROM `"+config.DBprefix+"boards` WHERE `id` = ? LIMIT 1",
[]interface{}{post.BoardID},
[]interface{}{&allowsVids},
); err != nil {
serveErrorPage(w, handleError(1, "Couldn't get board info: "+err.Error()))
return
}
@ -1142,9 +1113,13 @@ func formatMessage(message string) string {
// the link is in fact, a valid int
var boardDir string
var linkParent int
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)
if err = queryRowSQL("SELECT `dir`,`parentid` FROM "+config.DBprefix+"posts,"+config.DBprefix+"boards WHERE "+config.DBprefix+"posts.id = ?",
[]interface{}{word[8:]},
[]interface{}{&boardDir, &linkParent},
); err != nil {
handleError(1, customError(err))
}
// get post board dir
if boardDir == "" {

View file

@ -94,10 +94,9 @@ func serveNotFound(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(404)
errorPage, err := ioutil.ReadFile(config.DocumentRoot + "/error/404.html")
if err != nil {
writer.Write([]byte("Requested page not found, and 404 error page not found"))
_, _ = writer.Write([]byte("Requested page not found, and 404 error page not found"))
} else {
writer.Write(errorPage)
_, _ = writer.Write(errorPage)
}
errorLog.Print("Error: 404 Not Found from " + getRealIP(request) + " @ " + request.RequestURI)
}
@ -121,7 +120,7 @@ func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Reques
serveNotFound(writer, request)
return
}
writer.Write(fb)
_, _ = writer.Write(fb)
}
func initServer() {
@ -143,7 +142,7 @@ func initServer() {
testfunc := func(writer http.ResponseWriter, response *http.Request, data interface{}) {
if writer != nil {
writer.Write([]byte("hahahaha"))
_, _ = writer.Write([]byte("hahahaha"))
}
}
server.AddNamespace("example", testfunc)
@ -254,29 +253,29 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
var fileType string
var thumbType string
var post PostTable
var err error
post.ID, _ = strconv.Atoi(checkedPostID)
post.BoardID, _ = strconv.Atoi(boardid)
stmt, err := db.Prepare("SELECT `parentid`, `filename`, `password` FROM `" + config.DBprefix + "posts` WHERE `id` = ? AND `boardid` = ? AND `deleted_timestamp` = ?")
if err != nil {
serveErrorPage(writer, handleError(1, err.Error()+"\n"))
}
defer closeStatement(stmt)
err = stmt.QueryRow(&post.ID, &post.BoardID, nilTimestamp).Scan(&post.ParentID, &post.Filename, &post.Password)
if err == sql.ErrNoRows {
if err = queryRowSQL(
"SELECT `parentid`, `filename`, `password` FROM `"+config.DBprefix+"posts` WHERE `id` = ? AND `boardid` = ? AND `deleted_timestamp` = ?",
[]interface{}{&post.ID, &post.BoardID, nilTimestamp},
[]interface{}{&post.ParentID, &post.Filename, &post.Password},
); err == sql.ErrNoRows {
//the post has already been deleted
writer.Header().Add("refresh", "4;url="+request.Referer())
fmt.Fprintf(writer, "%d has already been deleted or is a post in a deleted thread.\n<br />", post.ID)
continue
}
if err != nil {
serveErrorPage(writer, err.Error())
} else if err != nil {
serveErrorPage(writer, handleError(1, err.Error()+"\n"))
return
}
err = db.QueryRow("SELECT `id` FROM `" + config.DBprefix + "boards` WHERE `dir` = '" + board + "'").Scan(&post.BoardID)
if err != nil {
if err = queryRowSQL(
"SELECT `id` FROM `"+config.DBprefix+"boards` WHERE `dir` = ?",
[]interface{}{board},
[]interface{}{&post.BoardID},
); err != nil {
serveErrorPage(writer, err.Error())
return
}
@ -299,8 +298,10 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/"+fileName+"t."+thumbType))
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/"+fileName+"c."+thumbType))
_, err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `filename` = 'deleted' WHERE `id` = " + strconv.Itoa(post.ID) + " AND `boardid` = " + strconv.Itoa(post.BoardID))
if err != nil {
if _, err = execSQL(
"UPDATE `"+config.DBprefix+"posts` SET `filename` = 'deleted' WHERE `id` = ? AND `boardid` = ?",
post.ID, post.BoardID,
); err != nil {
serveErrorPage(writer, err.Error())
return
}
@ -309,14 +310,18 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
buildBoardPages(&_board[0])
_post, _ := getPostArr(map[string]interface{}{"id": post.ID, "boardid": post.BoardID}, "")
postBoard := _post[0]
// postBoard := _post[0].(PostTable)
buildThreadPages(&postBoard)
writer.Header().Add("refresh", "4;url="+request.Referer())
fmt.Fprintf(writer, "Attached image from %d deleted successfully<br />\n<meta http-equiv=\"refresh\" content=\"1;url=/"+board+"/\">", post.ID)
} else {
// delete the post
_, err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `id` = " + strconv.Itoa(post.ID))
if _, err = execSQL(
"UPDATE `"+config.DBprefix+"posts` SET `deleted_timestamp` = ? WHERE `id` = ?",
getSQLDateTime(), post.ID,
); err != nil {
serveErrorPage(writer, err.Error())
}
if post.ParentID == 0 {
os.Remove(path.Join(config.DocumentRoot, board, "/res/"+strconv.Itoa(post.ID)+".html"))
} else {
@ -325,23 +330,30 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
}
// if the deleted post is actually a thread, delete its posts
_, err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `parentID` = " + strconv.Itoa(post.ID))
if err != nil {
if _, err = execSQL("UPDATE `"+config.DBprefix+"posts` SET `deleted_timestamp` = ? WHERE `parentID` = ?",
getSQLDateTime(), post.ID,
); err != nil {
serveErrorPage(writer, err.Error())
return
}
// delete the file
var deletedFilename string
err = db.QueryRow("SELECT `filename` FROM `" + config.DBprefix + "posts` WHERE `id` = " + strconv.Itoa(post.ID) + " AND `filename` != ''").Scan(&deletedFilename)
if err == nil {
if err = queryRowSQL(
"SELECT `filename` FROM `"+config.DBprefix+"posts` WHERE `id` = ? AND `filename` != ''",
[]interface{}{post.ID},
[]interface{}{&deletedFilename},
); err == nil {
os.Remove(path.Join(config.DocumentRoot, board, "/src/", deletedFilename))
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deletedFilename, ".", "t.", -1)))
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deletedFilename, ".", "c.", -1)))
}
err = db.QueryRow("SELECT `filename` FROM `" + config.DBprefix + "posts` WHERE `parentID` = " + strconv.Itoa(post.ID) + " AND `filename` != ''").Scan(&deletedFilename)
if err == nil {
if err = queryRowSQL(
"SELECT `filename` FROM `"+config.DBprefix+"posts` WHERE `parentID` = ? AND `filename` != ''",
[]interface{}{post.ID},
[]interface{}{&deletedFilename},
); err == nil {
os.Remove(path.Join(config.DocumentRoot, board, "/src/", deletedFilename))
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deletedFilename, ".", "t.", -1)))
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deletedFilename, ".", "c.", -1)))

View file

@ -17,8 +17,7 @@ const (
)
var (
db *sql.DB
dbConnected = false
db *sql.DB
)
func connectToSQLServer() {
@ -31,45 +30,25 @@ func connectToSQLServer() {
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 numRows int
err = db.QueryRow("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = ?", config.DBname).Scan(&numRows)
if err == sql.ErrNoRows {
numRows = 0
} else if err != nil {
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 numRows >= 16 {
// the initial setup has already been run
needsInitialSetup = false
dbConnected = true
println(0, "complete.")
return
}
// 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")
handleError(0, "Initial setup file (initialsetupdb.sql) missing. Please reinstall gochan")
os.Exit(2)
}
// read the initial setup sql file into a string
initialSQLBytes, err := ioutil.ReadFile("initialsetupdb.sql")
if err != nil {
printf(0, "failed: ")
print(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);"
print(0, "Starting initial setup...")
initialSQLStr += "\nINSERT INTO `DBNAME`.`DBPREFIXstaff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '" + bcryptSum("password") + "', 'abc', 3);"
initialSQLStr = strings.NewReplacer("DBNAME", config.DBname, "DBPREFIX", config.DBprefix).Replace(initialSQLStr)
initialSQLArr := strings.Split(initialSQLStr, ";")
for _, statement := range initialSQLArr {
@ -82,9 +61,34 @@ func connectToSQLServer() {
}
}
println(0, "complete.")
needsInitialSetup = false
dbConnected = true
}
func execSQL(query string, values ...interface{}) (sql.Result, error) {
stmt, err := db.Prepare(query)
defer closeStatement(stmt)
if err != nil {
return nil, err
}
return stmt.Exec(values...)
}
func queryRowSQL(query string, values []interface{}, out []interface{}) error {
stmt, err := db.Prepare(query)
defer closeStatement(stmt)
if err != nil {
return err
}
err = stmt.QueryRow(values...).Scan(out...)
return err
}
func querySQL(query string, a ...interface{}) (*sql.Rows, error) {
stmt, err := db.Prepare(query)
defer closeStatement(stmt)
if err != nil {
return nil, err
}
return stmt.Query(a...)
}
func getSQLDateTime() string {

View file

@ -1,6 +1,7 @@
package main
import (
"errors"
"fmt"
"html"
"net/http"
@ -189,7 +190,7 @@ var (
func loadTemplate(files ...string) (*template.Template, error) {
if len(files) == 0 {
return nil, fmt.Errorf("ERROR: no files named in call to loadTemplate")
return nil, errors.New("ERROR: no files named in call to loadTemplate")
}
var templates []string
for i, file := range files {
@ -200,7 +201,7 @@ func loadTemplate(files ...string) (*template.Template, error) {
}
func templateError(name string, err error) error {
return fmt.Errorf("Failed loading template \"" + config.TemplateDir + "/" + name + ": \"" + err.Error())
return errors.New("Failed loading template \"" + config.TemplateDir + "/" + name + ": \"" + err.Error())
}
func initTemplates() error {
@ -260,7 +261,7 @@ func getStyleLinks(w http.ResponseWriter, stylesheet string) {
}
if err := manage_header_tmpl.Execute(w, config); err != nil {
println(0, err.Error())
handleError(0, customError(err))
os.Exit(2)
}
}

View file

@ -12,13 +12,12 @@ import (
)
var (
needsInitialSetup = true
config GochanConfig
accessLog *log.Logger
errorLog *log.Logger
modLog *log.Logger
readBannedIPs []string
bbcompiler bbcode.Compiler
config GochanConfig
accessLog *log.Logger
errorLog *log.Logger
modLog *log.Logger
readBannedIPs []string
bbcompiler bbcode.Compiler
)
type RecentPost struct {

View file

@ -185,14 +185,13 @@ func getBoardArr(parameterList map[string]interface{}, extra string) (boards []B
queryString += fmt.Sprintf(" %s ORDER BY `order`", extra)
printf(2, "queryString@getBoardArr: %s\n", queryString)
stmt, err := db.Prepare(queryString)
rows, err := querySQL(queryString, parameterValues...)
defer closeRows(rows)
if err != nil {
errorLog.Print(err.Error())
handleError(0, "error getting board list: %s", customError(err))
return
}
defer closeStatement(stmt)
rows, err := stmt.Query(parameterValues...)
// For each row in the results from the database, populate a new BoardsTable instance,
// then append it to the boards array we are going to return
for rows.Next() {
@ -225,8 +224,7 @@ func getBoardArr(parameterList map[string]interface{}, extra string) (boards []B
&board.RequireFile,
&board.EnableCatalog,
); err != nil {
errorLog.Print(err.Error())
println(0, err.Error())
handleError(0, customError(err))
return
}
boards = append(boards, *board)
@ -236,27 +234,24 @@ func getBoardArr(parameterList map[string]interface{}, extra string) (boards []B
func getBoardFromID(id int) (*BoardsTable, error) {
board := new(BoardsTable)
stmt, err := db.Prepare("SELECT `order`,`dir`,`type`,`upload_type`,`title`,`subtitle`,`description`,`section`," +
"`max_image_size`,`max_pages`,`locale`,`default_style`,`locked`,`created_on`,`anonymous`,`forced_anon`,`max_age`," +
"`autosage_after`,`no_images_after`,`max_message_length`,`embeds_allowed`,`redirect_to_thread`,`require_file`," +
"`enable_catalog` FROM `" + config.DBprefix + "boards` WHERE `id` = ?")
if err != nil {
return nil, err
}
defer closeStatement(stmt)
err := queryRowSQL(
"SELECT `order`,`dir`,`type`,`upload_type`,`title`,`subtitle`,`description`,`section`,"+
"`max_image_size`,`max_pages`,`locale`,`default_style`,`locked`,`created_on`,`anonymous`,`forced_anon`,`max_age`,"+
"`autosage_after`,`no_images_after`,`max_message_length`,`embeds_allowed`,`redirect_to_thread`,`require_file`,"+
"`enable_catalog` FROM `"+config.DBprefix+"boards` WHERE `id` = ?",
[]interface{}{id},
[]interface{}{
&board.Order, &board.Dir, &board.Type, &board.UploadType, &board.Title,
&board.Subtitle, &board.Description, &board.Section, &board.MaxImageSize,
&board.MaxPages, &board.Locale, &board.DefaultStyle, &board.Locked, &board.CreatedOn,
&board.Anonymous, &board.ForcedAnon, &board.MaxAge, &board.AutosageAfter,
&board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed,
&board.RedirectToThread, &board.RequireFile, &board.EnableCatalog,
},
)
board.ID = id
if err = stmt.QueryRow(id).Scan(
&board.Order, &board.Dir, &board.Type, &board.UploadType, &board.Title,
&board.Subtitle, &board.Description, &board.Section, &board.MaxImageSize,
&board.MaxPages, &board.Locale, &board.DefaultStyle, &board.Locked, &board.CreatedOn,
&board.Anonymous, &board.ForcedAnon, &board.MaxAge, &board.AutosageAfter,
&board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed,
&board.RedirectToThread, &board.RequireFile, &board.EnableCatalog,
); err != nil {
return nil, err
}
return board, nil
return board, err
}
// if parameterList is nil, ignore it and treat extra like a whole SQL query
@ -281,19 +276,12 @@ func getPostArr(parameterList map[string]interface{}, extra string) (posts []Pos
queryString += " " + extra // " ORDER BY `order`"
printf(2, "queryString@getPostArr queryString: %s\n", queryString)
stmt, err := db.Prepare(queryString)
if err != nil {
errorLog.Print(err.Error())
return
}
defer closeStatement(stmt)
rows, err := stmt.Query(parameterValues...)
if err != nil {
handleError(1, "Error in getPostArr: "+err.Error())
return
}
rows, err := querySQL(queryString, parameterValues...)
defer closeRows(rows)
if err != nil {
handleError(1, customError(err))
return
}
// For each row in the results from the database, populate a new PostTable instance,
// then append it to the posts array we are going to return
@ -307,8 +295,7 @@ func getPostArr(parameterList map[string]interface{}, extra string) (posts []Pos
&post.Autosage, &post.PosterAuthority, &post.DeletedTimestamp, &post.Bumped,
&post.Stickied, &post.Locked, &post.Reviewed, &post.Sillytag,
); err != nil {
errorLog.Print(err.Error())
println(0, err.Error())
handleError(0, customError(err))
return
}
posts = append(posts, post)
@ -316,23 +303,24 @@ func getPostArr(parameterList map[string]interface{}, extra string) (posts []Pos
return
}
// TODO: replace where with a map[string]interface{} like getBoardsArr()
func getSectionArr(where string) (sections []interface{}, err error) {
if where == "" {
where = "1"
}
rows, err := db.Query("SELECT * FROM `" + config.DBprefix + "sections` WHERE " + where + " ORDER BY `order`;")
rows, err := querySQL("SELECT * FROM `" + config.DBprefix + "sections` WHERE " + where + " ORDER BY `order`")
defer closeRows(rows)
if err != nil {
errorLog.Print(err.Error())
return
}
defer closeRows(rows)
for rows.Next() {
section := new(BoardSectionsTable)
section.IName = "section"
if err = rows.Scan(&section.ID, &section.Order, &section.Hidden, &section.Name, &section.Abbreviation); err != nil {
errorLog.Print(err.Error())
handleError(1, customError(err))
return
}
sections = append(sections, section)
@ -370,7 +358,7 @@ func generateSalt() string {
}
func getFileExtension(filename string) (extension string) {
if strings.Index(filename, ".") == -1 {
if !strings.Contains(filename, ".") {
extension = ""
} else {
extension = filename[strings.LastIndex(filename, ".")+1:]
@ -544,7 +532,11 @@ func checkPostForSpam(userIP string, userAgent string, referrer string,
handleError(1, err.Error())
return "other_failure"
}
defer resp.Body.Close()
defer func() {
if resp != nil && resp.Body != nil {
resp.Body.Close()
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
handleError(1, err.Error())

View file

@ -1,5 +1,5 @@
<div id="footer">
<a href="{{.SiteWebfolder}}">Home</a> | <a href="{{.SiteWebfolder}}#boards">Boards</a> | <a href="{{.SiteWebfolder}}#rules">Rules</a> | <a href="{{.SiteWebfolder}}#faq">FAQ</a><br />
<a href="{{$.config.SiteWebfolder}}">Home</a> | <a href="{{$.config.SiteWebfolder}}#boards">Boards</a> | <a href="{{$.config.SiteWebfolder}}#rules">Rules</a> | <a href="{{$.config.SiteWebfolder}}#faq">FAQ</a><br />
Powered by <a href="http://github.com/eggbertx/gochan/">Gochan {{.config.Version}}</a><br />
</div>
</body>

View file

@ -13,7 +13,7 @@
{{if ne $op.Filename ""}}
{{if ne $op.Filename "deleted"}}
<div class="file-info">File: <a href="src/{{$op.Filename}}" target="_blank">{{$op.Filename}}</a> - ({{formatFilesize $op.Filesize}} , {{$op.ImageW}}x{{$op.ImageH}}, {{$op.FilenameOriginal}})</div>
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$op.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{imageToThumbnailPath $op.Filename}}" width="{{$op.ThumbW}}" height="{{$op.ThumbH}}" class="upload" /></a>
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$op.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{imageToThumbnailPath $op.Filename}}" width="{{$op.ThumbW}}" height="{{$op.ThumbH}}" class="upload" alt="" /></a>
{{else}}
<div class="file-deleted-box" style="text-align:center;">File removed</div>
{{end}}
@ -32,7 +32,7 @@
{{if ne $reply.Filename ""}}
{{if ne $reply.Filename "deleted"}}
<span class="file-info">File: <a href="src/{{$reply.Filename}}" target="_blank">{{$reply.Filename}}</a> - ({{formatFilesize $reply.Filesize}} , {{$reply.ImageW}}x{{$reply.ImageH}}, {{$reply.FilenameOriginal}})</span><br />
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$reply.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{imageToThumbnailPath $reply.Filename}}" width="{{$reply.ThumbW}}" height="{{$reply.ThumbH}}" class="upload" /></a>
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$reply.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{imageToThumbnailPath $reply.Filename}}" width="{{$reply.ThumbW}}" height="{{$reply.ThumbH}}" class="upload" alt=""/></a>
{{else}}
<div class="file-deleted-box" style="text-align:center;">File removed</div>
{{end}}{{end}}

View file

@ -10,7 +10,6 @@
<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
{{end}}
{{else}}<title>/{{.board.Dir}}/ - {{.board.Title}}</title>{{end}}
<title>/{{.board.Dir}}/ - {{.board.Title}}</title>
<script type="text/javascript" src="/javascript/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
var styles = [{{range $ii, $style := $.config.Styles_img}}{{if gt $ii 0}}, {{end}}"{{$style}}"{{end}}];