mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-20 09:26:23 -07:00
Add post editing, fix log not showing IP/path
This commit is contained in:
parent
53553b8ac4
commit
7e1110214d
13 changed files with 315 additions and 230 deletions
2
AUTHORS
2
AUTHORS
|
@ -1,2 +0,0 @@
|
|||
Joshua Merrell <joshuamerrell@gmail.com>
|
||||
Darren VanBuren <onekopaka@theoks.net>
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2013-2018, Joshua Merrell
|
||||
Copyright (c) 2013-2018, Eggbertx
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ GOCHAN_DEBUG=1
|
|||
GOCHAN_VERBOSE=2
|
||||
GOCHAN_VERBOSITY=0 # This is set by "make release/debug/verbose"
|
||||
|
||||
GOCHAN_VERSION=1.9.3
|
||||
GOCHAN_VERSION=1.10.0
|
||||
GOCHAN_BUILDTIME=$(shell date +%y%m%d.%H%M)
|
||||
ifeq ($(GOOS), windows)
|
||||
GOCHAN_BIN=gochan.exe
|
||||
|
|
2
dist.sh
2
dist.sh
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=1.9.3
|
||||
VERSION=1.10.0
|
||||
GOOS_ORIG=$GOOS
|
||||
|
||||
function copyStuff {
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
<h1>404: File not found</h1>
|
||||
<img src="/error/lol 404.gif" border="0" alt="">
|
||||
<p>The requested file could not be found on this server. Are you just typing random stuff in the address bar? If you followed a link from this site here, then post <a href="/site">here</a></p>
|
||||
<hr><address>http://gochan.org powered by Gochan v1.9.3</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v1.10.0</address>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
<h1>500: Internal Server error</h1>
|
||||
<img src="/error/derpy server.gif" border="0" alt="">
|
||||
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon has he/she/it can.</p>
|
||||
<hr><address>http://gochan.org powered by Gochan v1.9.3</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v1.10.0</address>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -17,23 +17,19 @@ import (
|
|||
// 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
|
||||
Permissions int // 0 -> non-staff, 1 => janitor, 2 => moderator, 3 => administrator
|
||||
Callback func(writer http.ResponseWriter, request *http.Request) string //return string of html output
|
||||
}
|
||||
|
||||
func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||
request = *r
|
||||
writer = w
|
||||
cookies = r.Cookies()
|
||||
|
||||
err := request.ParseForm()
|
||||
if err != nil {
|
||||
func callManageFunction(writer http.ResponseWriter, request *http.Request) {
|
||||
var err error
|
||||
if err = request.ParseForm(); err != nil {
|
||||
serveErrorPage(writer, err.Error())
|
||||
errorLog.Println(customError(err))
|
||||
}
|
||||
|
||||
action := request.FormValue("action")
|
||||
staffRank := getStaffRank()
|
||||
staffRank := getStaffRank(request)
|
||||
var managePageBuffer bytes.Buffer
|
||||
mangePageHTML := ""
|
||||
|
||||
|
@ -57,11 +53,11 @@ func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}
|
|||
|
||||
if _, ok := manage_functions[action]; ok {
|
||||
if staffRank >= manage_functions[action].Permissions {
|
||||
managePageBuffer.Write([]byte(manage_functions[action].Callback()))
|
||||
managePageBuffer.Write([]byte(manage_functions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 && manage_functions[action].Permissions == 0 {
|
||||
managePageBuffer.Write([]byte(manage_functions[action].Callback()))
|
||||
managePageBuffer.Write([]byte(manage_functions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 {
|
||||
managePageBuffer.Write([]byte(manage_functions["login"].Callback()))
|
||||
managePageBuffer.Write([]byte(manage_functions["login"].Callback(writer, request)))
|
||||
} else {
|
||||
managePageBuffer.Write([]byte(action + " is undefined."))
|
||||
}
|
||||
|
@ -79,14 +75,12 @@ func callManageFunction(w http.ResponseWriter, r *http.Request, data interface{}
|
|||
fmt.Fprintf(writer, managePageBuffer.String())
|
||||
}
|
||||
|
||||
func getCurrentStaff() (string, error) {
|
||||
sessionCookie := getCookie("sessiondata")
|
||||
var key string
|
||||
if sessionCookie == nil {
|
||||
func getCurrentStaff(request *http.Request) (string, error) {
|
||||
sessionCookie, err := request.Cookie("sessiondata")
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
key = sessionCookie.Value
|
||||
|
||||
key := sessionCookie.Value
|
||||
current_session := new(SessionsTable)
|
||||
if err := queryRowSQL(
|
||||
"SELECT `data` FROM `"+config.DBprefix+"sessions` WHERE `key` = ?",
|
||||
|
@ -108,13 +102,13 @@ func getStaff(name string) (*StaffTable, error) {
|
|||
return staff_obj, err
|
||||
}
|
||||
|
||||
func getStaffRank() int {
|
||||
staffname, err := getCurrentStaff()
|
||||
println(1, customError(err))
|
||||
func getStaffRank(request *http.Request) int {
|
||||
staffname, err := getCurrentStaff(request)
|
||||
if staffname == "" {
|
||||
return 0
|
||||
}
|
||||
if err != nil {
|
||||
handleError(1, customError(err))
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -126,14 +120,14 @@ func getStaffRank() int {
|
|||
return staff.Rank
|
||||
}
|
||||
|
||||
func createSession(key string, username string, password string, request *http.Request, writer *http.ResponseWriter) 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]
|
||||
|
||||
if !validReferrer(*request) {
|
||||
if !validReferrer(request) {
|
||||
modLog.Print("Rejected login from possible spambot @ : " + request.RemoteAddr)
|
||||
return 2
|
||||
}
|
||||
|
@ -150,7 +144,7 @@ func createSession(key string, username string, password string, request *http.R
|
|||
} else {
|
||||
// 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)
|
||||
http.SetCookie(writer, cookie)
|
||||
if _, err = execSQL(
|
||||
"INSERT INTO `"+config.DBprefix+"sessions` (`key`, `data`, `expires`) VALUES(?,?,?)",
|
||||
key, username, getSpecificSQLDateTime(time.Now().Add(time.Duration(time.Hour*730))),
|
||||
|
@ -172,7 +166,7 @@ func createSession(key string, username string, password string, request *http.R
|
|||
var manage_functions = map[string]ManageFunction{
|
||||
"cleanup": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = "<h2>Cleanup</h2><br />"
|
||||
var err error
|
||||
if request.FormValue("run") == "Run Cleanup" {
|
||||
|
@ -213,7 +207,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"config": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
do := request.FormValue("do")
|
||||
if do == "save" {
|
||||
// configJSON, err := json.Marshal(config)
|
||||
|
@ -239,7 +233,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"purgeeverything": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = "<img src=\"/css/purge.jpg\" />"
|
||||
rows, err := querySQL("SELECT `dir` FROM `" + config.DBprefix + "boards`")
|
||||
defer closeRows(rows)
|
||||
|
@ -294,7 +288,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"executesql": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
statement := request.FormValue("sql")
|
||||
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 != "" {
|
||||
|
@ -309,9 +303,9 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"login": {
|
||||
Permissions: 0,
|
||||
Callback: func() (html string) {
|
||||
if getStaffRank() > 0 {
|
||||
http.Redirect(writer, &request, path.Join(config.SiteWebfolder, "manage"), http.StatusFound)
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
if getStaffRank(request) > 0 {
|
||||
http.Redirect(writer, request, path.Join(config.SiteWebfolder, "manage"), http.StatusFound)
|
||||
}
|
||||
username := request.FormValue("username")
|
||||
password := request.FormValue("password")
|
||||
|
@ -329,15 +323,18 @@ var manage_functions = map[string]ManageFunction{
|
|||
"\t</form>"
|
||||
} else {
|
||||
key := md5Sum(request.RemoteAddr + username + password + config.RandomSeed + generateSalt())[0:10]
|
||||
createSession(key, username, password, &request, &writer)
|
||||
http.Redirect(writer, &request, path.Join(config.SiteWebfolder, "/manage?action="+request.FormValue("redirect")), http.StatusFound)
|
||||
createSession(key, username, password, request, writer)
|
||||
http.Redirect(writer, request, path.Join(config.SiteWebfolder, "/manage?action="+request.FormValue("redirect")), http.StatusFound)
|
||||
}
|
||||
return
|
||||
}},
|
||||
"logout": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
cookie := getCookie("sessiondata")
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
cookie, err := request.Cookie("sessiondata")
|
||||
if err != nil {
|
||||
serveErrorPage(writer, err.Error())
|
||||
}
|
||||
var key string
|
||||
if cookie != nil {
|
||||
key = cookie.Value
|
||||
|
@ -361,7 +358,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"announcements": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = "<h1>Announcements</h1><br />"
|
||||
|
||||
rows, err := querySQL("SELECT `subject`,`message`,`poster`,`timestamp` FROM `" + config.DBprefix + "announcements` ORDER BY `id` DESC")
|
||||
|
@ -391,7 +388,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"bans": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
var ban_which string // user, image, or both
|
||||
|
||||
if request.PostFormValue("ban-user-button") == "Ban user" {
|
||||
|
@ -508,13 +505,13 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"getstaffjquery": {
|
||||
Permissions: 0,
|
||||
Callback: func() (html string) {
|
||||
current_staff, err := getCurrentStaff()
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
current_staff, err := getCurrentStaff(request)
|
||||
if err != nil {
|
||||
html = "nobody;0;"
|
||||
return
|
||||
}
|
||||
staff_rank := getStaffRank()
|
||||
staff_rank := getStaffRank(request)
|
||||
if staff_rank == 0 {
|
||||
html = "nobody;0;"
|
||||
return
|
||||
|
@ -532,7 +529,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"boards": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
do := request.FormValue("do")
|
||||
var done bool
|
||||
board := new(BoardsTable)
|
||||
|
@ -774,8 +771,8 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"staffmenu": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
rank := getStaffRank()
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
rank := getStaffRank(request)
|
||||
|
||||
html = "<a href=\"javascript:void(0)\" id=\"logout\" class=\"staffmenu-item\">Log out</a><br />\n" +
|
||||
"<a href=\"javascript:void(0)\" id=\"announcements\" class=\"staffmenu-item\">Announcements</a><br />\n"
|
||||
|
@ -804,13 +801,13 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"rebuildfront": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
initTemplates()
|
||||
return buildFrontPage()
|
||||
}},
|
||||
"rebuildall": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
initTemplates()
|
||||
return buildFrontPage() + "<hr />\n" +
|
||||
buildBoardListJSON() + "<hr />\n" +
|
||||
|
@ -818,13 +815,13 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"rebuildboards": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
initTemplates()
|
||||
return buildBoards(true, 0)
|
||||
}},
|
||||
"reparsehtml": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
posts, err := getPostArr(map[string]interface{}{
|
||||
"deleted_timestamp": nilTimestamp,
|
||||
}, "")
|
||||
|
@ -850,7 +847,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"recentposts": {
|
||||
Permissions: 1,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
limit := request.FormValue("limit")
|
||||
if limit == "" {
|
||||
limit = "50"
|
||||
|
@ -896,13 +893,13 @@ var manage_functions = map[string]ManageFunction{
|
|||
}},
|
||||
"killserver": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
os.Exit(0)
|
||||
return
|
||||
}},
|
||||
"staff": {
|
||||
Permissions: 3,
|
||||
Callback: func() (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
do := request.FormValue("do")
|
||||
html = "<h1>Staff</h1><br />\n" +
|
||||
"<table id=\"stafftable\" border=\"1\">\n" +
|
||||
|
|
113
src/posting.go
113
src/posting.go
|
@ -67,7 +67,7 @@ func buildBoards(all bool, which int) (html string) {
|
|||
// buildBoardPages builds the pages for the board archive. board is a BoardsTable object representing the board to
|
||||
// build archive pages for. The return value is a string of HTML with debug information from the build process.
|
||||
func buildBoardPages(board *BoardsTable) (html string) {
|
||||
// start_time := benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), time.Now(), true)
|
||||
start_time := benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), time.Now(), true)
|
||||
var current_page_file *os.File
|
||||
var threads []interface{}
|
||||
var thread_pages [][]interface{}
|
||||
|
@ -210,7 +210,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
|
|||
}
|
||||
|
||||
html += "/" + board.Dir + "/ built successfully, no threads to build.\n"
|
||||
//benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
return
|
||||
} else {
|
||||
// Create the archive pages.
|
||||
|
@ -306,7 +306,7 @@ func buildBoardPages(board *BoardsTable) (html string) {
|
|||
}
|
||||
html += "/" + board.Dir + "/ built successfully.\n"
|
||||
}
|
||||
//benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -567,7 +567,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) {
|
||||
func checkBannedStatus(post *PostTable, writer http.ResponseWriter) ([]interface{}, error) {
|
||||
var isExpired bool
|
||||
var ban_entry BanlistTable
|
||||
var interfaces []interface{}
|
||||
|
@ -711,6 +711,21 @@ func getThumbnailSize(w int, h int, size string) (new_w int, new_h int) {
|
|||
return
|
||||
}
|
||||
|
||||
func parseName(name string) map[string]string {
|
||||
parsed := make(map[string]string)
|
||||
if !strings.Contains(name, "#") {
|
||||
parsed["name"] = name
|
||||
parsed["tripcode"] = ""
|
||||
} else if strings.Index(name, "#") == 0 {
|
||||
parsed["tripcode"] = tripcode.Tripcode(name[1:])
|
||||
} else if strings.Index(name, "#") > 0 {
|
||||
postNameArr := strings.SplitN(name, "#", 2)
|
||||
parsed["name"] = postNameArr[0]
|
||||
parsed["tripcode"] = tripcode.Tripcode(postNameArr[1])
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// inserts prepared post object into the SQL table so that it can be rendered
|
||||
func insertPost(post PostTable, bump bool) (sql.Result, error) {
|
||||
var result sql.Result
|
||||
|
@ -748,13 +763,11 @@ func insertPost(post PostTable, bump bool) (sql.Result, error) {
|
|||
}
|
||||
|
||||
// called when a user accesses /post. Parse form data, then insert and build
|
||||
func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||
func makePost(writer http.ResponseWriter, request *http.Request) {
|
||||
startTime := benchmarkTimer("makePost", time.Now(), true)
|
||||
request = *r
|
||||
writer = w
|
||||
var maxMessageLength int
|
||||
var post PostTable
|
||||
domain := r.Host
|
||||
domain := request.Host
|
||||
var formName string
|
||||
var nameCookie string
|
||||
var formEmail string
|
||||
|
@ -769,25 +782,15 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
|
||||
var emailCommand string
|
||||
formName = request.FormValue("postname")
|
||||
|
||||
if strings.Index(formName, "#") == -1 {
|
||||
post.Name = formName
|
||||
} else if strings.Index(formName, "#") == 0 {
|
||||
post.Tripcode = tripcode.Tripcode(formName[1:])
|
||||
} else if strings.Index(formName, "#") > 0 {
|
||||
postNameArr := strings.SplitN(formName, "#", 2)
|
||||
post.Name = postNameArr[0]
|
||||
post.Tripcode = tripcode.Tripcode(postNameArr[1])
|
||||
}
|
||||
if strings.Index(post.Tripcode, "PipesTtB.A") > -1 {
|
||||
http.Redirect(writer, r, "https://i.imgur.com/caMm6N8.jpg", 302)
|
||||
}
|
||||
parsedName := parseName(formName)
|
||||
post.Name = parsedName["name"]
|
||||
post.Tripcode = parsedName["tripcode"]
|
||||
|
||||
nameCookie = post.Name + post.Tripcode
|
||||
formEmail = request.FormValue("postemail")
|
||||
http.SetCookie(writer, &http.Cookie{Name: "email", Value: formEmail, Path: "/", Domain: domain, RawExpires: getSpecificSQLDateTime(time.Now().Add(time.Duration(yearInSeconds))), MaxAge: yearInSeconds})
|
||||
|
||||
if strings.Index(formEmail, "noko") == -1 && strings.Index(formEmail, "sage") == -1 {
|
||||
if !strings.Contains(formEmail, "noko") && !strings.Contains(formEmail, "sage") {
|
||||
post.Email = formEmail
|
||||
} else if strings.Index(formEmail, "#") > 1 {
|
||||
formEmailArr := strings.SplitN(formEmail, "#", 2)
|
||||
|
@ -805,16 +808,15 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
[]interface{}{post.BoardID},
|
||||
[]interface{}{&maxMessageLength},
|
||||
); err != nil {
|
||||
serveErrorPage(w, handleError(0, "Error getting board info: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(0, "Error getting board info: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(post.MessageText) > maxMessageLength {
|
||||
serveErrorPage(w, "Post body is too long")
|
||||
serveErrorPage(writer, "Post body is too long")
|
||||
return
|
||||
}
|
||||
post.MessageHTML = formatMessage(post.MessageText)
|
||||
|
||||
post.Password = md5Sum(request.FormValue("postpassword"))
|
||||
|
||||
// Reverse escapes
|
||||
|
@ -826,9 +828,9 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
http.SetCookie(writer, &http.Cookie{Name: "name", Value: nameCookie, Path: "/", Domain: domain, RawExpires: getSpecificSQLDateTime(time.Now().Add(time.Duration(yearInSeconds))), MaxAge: yearInSeconds})
|
||||
http.SetCookie(writer, &http.Cookie{Name: "password", Value: request.FormValue("postpassword"), Path: "/", Domain: domain, RawExpires: getSpecificSQLDateTime(time.Now().Add(time.Duration(yearInSeconds))), MaxAge: yearInSeconds})
|
||||
|
||||
post.IP = getRealIP(&request)
|
||||
post.IP = getRealIP(request)
|
||||
post.Timestamp = time.Now()
|
||||
post.PosterAuthority = getStaffRank()
|
||||
post.PosterAuthority = getStaffRank(request)
|
||||
post.Bumped = time.Now()
|
||||
post.Stickied = request.FormValue("modstickied") == "on"
|
||||
post.Locked = request.FormValue("modlocked") == "on"
|
||||
|
@ -844,11 +846,11 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
switch checkPostForSpam(post.IP, request.Header["User-Agent"][0], request.Referer(),
|
||||
post.Name, post.Email, post.MessageText) {
|
||||
case "discard":
|
||||
serveErrorPage(w, "Your post looks like spam.")
|
||||
serveErrorPage(writer, "Your post looks like spam.")
|
||||
accessLog.Print("Akismet recommended discarding post from: " + post.IP)
|
||||
return
|
||||
case "spam":
|
||||
serveErrorPage(w, "Your post looks like spam.")
|
||||
serveErrorPage(writer, "Your post looks like spam.")
|
||||
accessLog.Print("Akismet suggested post is spam from " + post.IP)
|
||||
return
|
||||
default:
|
||||
|
@ -867,7 +869,7 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
} else {
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, "Couldn't read file: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Couldn't read file: "+err.Error()))
|
||||
} else {
|
||||
post.FilenameOriginal = html.EscapeString(handler.Filename)
|
||||
filetype := getFileExtension(post.FilenameOriginal)
|
||||
|
@ -879,7 +881,7 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
post.Filename = getNewFilename() + "." + getFileExtension(post.FilenameOriginal)
|
||||
boardArr, _ := getBoardArr(map[string]interface{}{"id": request.FormValue("boardid")}, "")
|
||||
if len(boardArr) == 0 {
|
||||
serveErrorPage(w, "No boards have been created yet")
|
||||
serveErrorPage(writer, "No boards have been created yet")
|
||||
return
|
||||
}
|
||||
_boardDir, _ := getBoardArr(map[string]interface{}{"id": request.FormValue("boardid")}, "")
|
||||
|
@ -890,7 +892,7 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
|
||||
if err := ioutil.WriteFile(filePath, data, 0777); err != nil {
|
||||
handleError(0, "Couldn't write file \""+post.Filename+"\""+err.Error())
|
||||
serveErrorPage(w, "Couldn't write file \""+post.FilenameOriginal+"\"")
|
||||
serveErrorPage(writer, "Couldn't write file \""+post.FilenameOriginal+"\"")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -902,13 +904,13 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
[]interface{}{post.BoardID},
|
||||
[]interface{}{&allowsVids},
|
||||
); err != nil {
|
||||
serveErrorPage(w, handleError(1, "Couldn't get board info: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Couldn't get board info: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if filetype == "webm" {
|
||||
if !allowsVids || !config.AllowVideoUploads {
|
||||
serveErrorPage(w, "Video uploading is not currently enabled for this board.")
|
||||
serveErrorPage(writer, "Video uploading is not currently enabled for this board.")
|
||||
os.Remove(filePath)
|
||||
return
|
||||
}
|
||||
|
@ -917,25 +919,25 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
if post.ParentID == 0 {
|
||||
err := createVideoThumbnail(filePath, thumbPath, config.ThumbWidth)
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, err.Error()))
|
||||
serveErrorPage(writer, handleError(1, err.Error()))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := createVideoThumbnail(filePath, thumbPath, config.ThumbWidth_reply)
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, err.Error()))
|
||||
serveErrorPage(writer, handleError(1, err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := createVideoThumbnail(filePath, catalogThumbPath, config.ThumbWidth_catalog); err != nil {
|
||||
serveErrorPage(w, handleError(1, err.Error()))
|
||||
serveErrorPage(writer, handleError(1, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
outputBytes, err := exec.Command("ffprobe", "-v", "quiet", "-show_format", "-show_streams", filePath).CombinedOutput()
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, "Error getting video info: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Error getting video info: "+err.Error()))
|
||||
return
|
||||
}
|
||||
if err == nil && outputBytes != nil {
|
||||
|
@ -968,13 +970,13 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
if err != nil {
|
||||
os.Remove(filePath)
|
||||
handleError(1, "Couldn't open uploaded file \""+post.Filename+"\""+err.Error())
|
||||
serveErrorPage(w, "Upload filetype not supported")
|
||||
serveErrorPage(writer, "Upload filetype not supported")
|
||||
return
|
||||
} else {
|
||||
// Get image filesize
|
||||
stat, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, "Couldn't get image filesize: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Couldn't get image filesize: "+err.Error()))
|
||||
return
|
||||
} else {
|
||||
post.Filesize = int(stat.Size())
|
||||
|
@ -994,12 +996,12 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
if request.FormValue("spoiler") == "on" {
|
||||
// If spoiler is enabled, symlink thumbnail to spoiler image
|
||||
if _, err := os.Stat(path.Join(config.DocumentRoot, "spoiler.png")); err != nil {
|
||||
serveErrorPage(w, "missing /spoiler.png")
|
||||
serveErrorPage(writer, "missing /spoiler.png")
|
||||
return
|
||||
} else {
|
||||
err = syscall.Symlink(path.Join(config.DocumentRoot, "spoiler.png"), thumbPath)
|
||||
if err != nil {
|
||||
serveErrorPage(w, err.Error())
|
||||
serveErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -1008,7 +1010,7 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
post.ThumbW = img.Bounds().Max.X
|
||||
post.ThumbH = img.Bounds().Max.Y
|
||||
if err := syscall.Symlink(filePath, thumbPath); err != nil {
|
||||
serveErrorPage(w, err.Error())
|
||||
serveErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
@ -1019,14 +1021,14 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
thumbnail = createImageThumbnail(img, "op")
|
||||
catalogThumbnail = createImageThumbnail(img, "catalog")
|
||||
if err = imaging.Save(catalogThumbnail, catalogThumbPath); err != nil {
|
||||
serveErrorPage(w, handleError(1, "Couldn't generate catalog thumbnail: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Couldn't generate catalog thumbnail: "+err.Error()))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
thumbnail = createImageThumbnail(img, "reply")
|
||||
}
|
||||
if err = imaging.Save(thumbnail, thumbPath); err != nil {
|
||||
serveErrorPage(w, handleError(1, "Couldn't save thumbnail: "+err.Error()))
|
||||
serveErrorPage(writer, handleError(1, "Couldn't save thumbnail: "+err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -1036,25 +1038,25 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
}
|
||||
|
||||
if strings.TrimSpace(post.MessageText) == "" && post.Filename == "" {
|
||||
serveErrorPage(w, "Post must contain a message if no image is uploaded.")
|
||||
serveErrorPage(writer, "Post must contain a message if no image is uploaded.")
|
||||
return
|
||||
}
|
||||
|
||||
postDelay := sinceLastPost(&post)
|
||||
if postDelay > -1 {
|
||||
if post.ParentID == 0 && postDelay < config.NewThreadDelay {
|
||||
serveErrorPage(w, "Please wait before making a new thread.")
|
||||
serveErrorPage(writer, "Please wait before making a new thread.")
|
||||
return
|
||||
} else if post.ParentID > 0 && postDelay < config.ReplyDelay {
|
||||
serveErrorPage(w, "Please wait before making a reply.")
|
||||
serveErrorPage(writer, "Please wait before making a reply.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
isBanned, err := checkBannedStatus(&post, &w)
|
||||
isBanned, err := checkBannedStatus(&post, writer)
|
||||
if err != nil {
|
||||
handleError(1, "Error in checkBannedStatus: "+err.Error())
|
||||
serveErrorPage(w, err.Error())
|
||||
serveErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1068,14 +1070,14 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
fmt.Fprintf(writer, banpage_html+handleError(1, err.Error())+"\n</body>\n</html>")
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, banpage_buffer.String())
|
||||
fmt.Fprintf(writer, banpage_buffer.String())
|
||||
return
|
||||
}
|
||||
|
||||
sanitizePost(&post)
|
||||
result, err := insertPost(post, emailCommand != "sage")
|
||||
if err != nil {
|
||||
serveErrorPage(w, handleError(1, err.Error()))
|
||||
serveErrorPage(writer, handleError(1, err.Error()))
|
||||
return
|
||||
}
|
||||
postid, _ := result.LastInsertId()
|
||||
|
@ -1084,17 +1086,16 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
boards, _ := getBoardArr(nil, "")
|
||||
// rebuild the board page
|
||||
buildBoards(false, post.BoardID)
|
||||
|
||||
buildFrontPage()
|
||||
|
||||
if emailCommand == "noko" {
|
||||
if post.ParentID == 0 {
|
||||
http.Redirect(writer, &request, "/"+boards[post.BoardID-1].Dir+"/res/"+strconv.Itoa(post.ID)+".html", http.StatusFound)
|
||||
http.Redirect(writer, request, "/"+boards[post.BoardID-1].Dir+"/res/"+strconv.Itoa(post.ID)+".html", http.StatusFound)
|
||||
} else {
|
||||
http.Redirect(writer, &request, "/"+boards[post.BoardID-1].Dir+"/res/"+strconv.Itoa(post.ParentID)+".html#"+strconv.Itoa(post.ID), http.StatusFound)
|
||||
http.Redirect(writer, request, "/"+boards[post.BoardID-1].Dir+"/res/"+strconv.Itoa(post.ParentID)+".html#"+strconv.Itoa(post.ID), http.StatusFound)
|
||||
}
|
||||
} else {
|
||||
http.Redirect(writer, &request, "/"+boards[post.BoardID-1].Dir+"/", http.StatusFound)
|
||||
http.Redirect(writer, request, "/"+boards[post.BoardID-1].Dir+"/", http.StatusFound)
|
||||
}
|
||||
benchmarkTimer("makePost", startTime, false)
|
||||
}
|
||||
|
|
188
src/server.go
188
src/server.go
|
@ -15,29 +15,27 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
cookies []*http.Cookie
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
server *GochanServer
|
||||
referrerRegex *regexp.Regexp
|
||||
)
|
||||
|
||||
type GochanServer struct {
|
||||
/* writer http.ResponseWriter
|
||||
request http.Request */
|
||||
namespaces map[string]func(http.ResponseWriter, *http.Request, interface{})
|
||||
namespaces map[string]func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func (s GochanServer) AddNamespace(basePath string, namespaceFunction func(http.ResponseWriter, *http.Request, interface{})) {
|
||||
func (s GochanServer) AddNamespace(basePath string, namespaceFunction func(http.ResponseWriter, *http.Request)) {
|
||||
s.namespaces[basePath] = namespaceFunction
|
||||
}
|
||||
|
||||
func (s GochanServer) getFileData(writer http.ResponseWriter, url string) (fileBytes []byte) {
|
||||
filePath := path.Join(config.DocumentRoot, url)
|
||||
func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Request) {
|
||||
filePath := path.Join(config.DocumentRoot, request.URL.Path)
|
||||
var fileBytes []byte
|
||||
results, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
// the requested path isn't a file or directory, 404
|
||||
fileBytes = nil
|
||||
writer.WriteHeader(404)
|
||||
serveNotFound(writer, request)
|
||||
return
|
||||
} else {
|
||||
//the file exists, or there is a folder here
|
||||
if results.IsDir() {
|
||||
|
@ -46,16 +44,13 @@ func (s GochanServer) getFileData(writer http.ResponseWriter, url string) (fileB
|
|||
newPath := path.Join(filePath, value)
|
||||
_, err := os.Stat(newPath)
|
||||
if err == nil {
|
||||
// serve the index page
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
fileBytes, _ := ioutil.ReadFile(newPath)
|
||||
return fileBytes
|
||||
filePath = newPath
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//the file exists, and is not a folder
|
||||
fileBytes, _ = ioutil.ReadFile(filePath)
|
||||
extension := getFileExtension(url)
|
||||
extension := getFileExtension(request.URL.Path)
|
||||
switch extension {
|
||||
case "png":
|
||||
writer.Header().Add("Content-Type", "image/png")
|
||||
|
@ -83,10 +78,14 @@ func (s GochanServer) getFileData(writer http.ResponseWriter, url string) (fileB
|
|||
writer.Header().Add("Content-Type", "text/html")
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
}
|
||||
accessLog.Print("Success: 200 from " + getRealIP(&request) + " @ " + request.RequestURI)
|
||||
accessLog.Print("Success: 200 from " + getRealIP(request) + " @ " + request.URL.Path)
|
||||
}
|
||||
}
|
||||
return
|
||||
// serve the index page
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
fileBytes, _ = ioutil.ReadFile(filePath)
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
_, _ = writer.Write(fileBytes)
|
||||
}
|
||||
|
||||
func serveNotFound(writer http.ResponseWriter, request *http.Request) {
|
||||
|
@ -98,29 +97,28 @@ func serveNotFound(writer http.ResponseWriter, request *http.Request) {
|
|||
} else {
|
||||
_, _ = writer.Write(errorPage)
|
||||
}
|
||||
errorLog.Print("Error: 404 Not Found from " + getRealIP(request) + " @ " + request.RequestURI)
|
||||
errorLog.Print("Error: 404 Not Found from " + getRealIP(request) + " @ " + request.URL.Path)
|
||||
}
|
||||
|
||||
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))
|
||||
errorpage_tmpl.Execute(writer, map[string]interface{}{
|
||||
"config": config,
|
||||
"ErrorTitle": "Error :c",
|
||||
"ErrorImage": "/error/lol 404.gif",
|
||||
"ErrorHeader": "Error",
|
||||
"ErrorText": err,
|
||||
})
|
||||
}
|
||||
|
||||
func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
for name, namespaceFunction := range s.namespaces {
|
||||
if request.URL.Path == "/"+name {
|
||||
namespaceFunction(writer, request, nil)
|
||||
// writer.WriteHeader(200)
|
||||
namespaceFunction(writer, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
fb := s.getFileData(writer, request.URL.Path)
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
if fb == nil {
|
||||
serveNotFound(writer, request)
|
||||
return
|
||||
}
|
||||
_, _ = writer.Write(fb)
|
||||
s.serveFile(writer, request)
|
||||
}
|
||||
|
||||
func initServer() {
|
||||
|
@ -130,7 +128,7 @@ func initServer() {
|
|||
os.Exit(2)
|
||||
}
|
||||
server = new(GochanServer)
|
||||
server.namespaces = make(map[string]func(http.ResponseWriter, *http.Request, interface{}))
|
||||
server.namespaces = make(map[string]func(http.ResponseWriter, *http.Request))
|
||||
|
||||
// Check if Akismet API key is usable at startup.
|
||||
if config.AkismetAPIKey != "" {
|
||||
|
@ -140,11 +138,12 @@ func initServer() {
|
|||
// Compile regex for checking referrers.
|
||||
referrerRegex = regexp.MustCompile(config.DomainRegex)
|
||||
|
||||
testfunc := func(writer http.ResponseWriter, response *http.Request, data interface{}) {
|
||||
testfunc := func(writer http.ResponseWriter, request *http.Request) {
|
||||
if writer != nil {
|
||||
_, _ = writer.Write([]byte("hahahaha"))
|
||||
}
|
||||
}
|
||||
|
||||
server.AddNamespace("example", testfunc)
|
||||
server.AddNamespace("manage", callManageFunction)
|
||||
server.AddNamespace("post", makePost)
|
||||
|
@ -163,23 +162,23 @@ func initServer() {
|
|||
}
|
||||
}
|
||||
|
||||
func getRealIP(r *http.Request) string {
|
||||
func getRealIP(request *http.Request) string {
|
||||
// HTTP_CF_CONNECTING_IP > X-Forwarded-For > RemoteAddr
|
||||
if r.Header.Get("HTTP_CF_CONNECTING_IP") != "" {
|
||||
return r.Header.Get("HTTP_CF_CONNECTING_IP")
|
||||
if request.Header.Get("HTTP_CF_CONNECTING_IP") != "" {
|
||||
return request.Header.Get("HTTP_CF_CONNECTING_IP")
|
||||
}
|
||||
if r.Header.Get("X-Forwarded-For") != "" {
|
||||
return r.Header.Get("X-Forwarded-For")
|
||||
if request.Header.Get("X-Forwarded-For") != "" {
|
||||
return request.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
return r.RemoteAddr
|
||||
return request.RemoteAddr
|
||||
}
|
||||
|
||||
func validReferrer(request http.Request) bool {
|
||||
func validReferrer(request *http.Request) bool {
|
||||
return referrerRegex.MatchString(request.Referer())
|
||||
}
|
||||
|
||||
// register /util handler
|
||||
func utilHandler(writer http.ResponseWriter, request *http.Request, data interface{}) {
|
||||
func utilHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
//writer.Header().Add("Content-Type", "text/css")
|
||||
action := request.FormValue("action")
|
||||
password := request.FormValue("password")
|
||||
|
@ -189,8 +188,9 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
deleteBtn := request.PostFormValue("delete_btn")
|
||||
reportBtn := request.PostFormValue("report_btn")
|
||||
editBtn := request.PostFormValue("edit_btn")
|
||||
doEdit := request.PostFormValue("doedit")
|
||||
|
||||
if action == "" && deleteBtn != "Delete" && reportBtn != "Report" && editBtn != "Edit" {
|
||||
if action == "" && deleteBtn != "Delete" && reportBtn != "Report" && editBtn != "Edit" && doEdit != "1" {
|
||||
http.Redirect(writer, request, path.Join(config.SiteWebfolder, "/"), http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
@ -202,6 +202,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
}
|
||||
|
||||
if editBtn == "Edit" {
|
||||
var err error
|
||||
if len(postsArr) == 0 {
|
||||
serveErrorPage(writer, "You need to select one post to edit.")
|
||||
return
|
||||
|
@ -209,40 +210,99 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
serveErrorPage(writer, "You can only edit one post at a time.")
|
||||
return
|
||||
} else {
|
||||
passwordMD5 := md5Sum(password)
|
||||
rank := getStaffRank()
|
||||
if passwordMD5 == "" && rank == 0 {
|
||||
rank := getStaffRank(request)
|
||||
if password == "" && rank == 0 {
|
||||
serveErrorPage(writer, "Password required for post editing")
|
||||
return
|
||||
}
|
||||
passwordMD5 := md5Sum(password)
|
||||
|
||||
var post PostTable
|
||||
post.ID, _ = strconv.Atoi(postsArr[0])
|
||||
post.BoardID, _ = strconv.Atoi(boardid)
|
||||
stmt, err := db.Prepare("SELECT `parentid`,` password`,`message_raw` FROM `" + config.DBprefix + "posts` WHERE `id` = ? AND `deleted_timestamp` = ?")
|
||||
if err != nil {
|
||||
serveErrorPage(writer, handleError(1, err.Error()+"\n"))
|
||||
}
|
||||
defer closeStatement(stmt)
|
||||
/* var post_edit_buffer bytes.Buffer
|
||||
if err = renderTemplate(post_edit_tmpl, "post_edit", post_edit_buffer,
|
||||
&Wrapper{IName: "boards_", Data: all_boards},
|
||||
&Wrapper{IName: "sections_w", Data: all_sections},
|
||||
&Wrapper{IName: "posts_w", Data: []interface{}{
|
||||
PostTable{BoardID: board.ID},
|
||||
}},
|
||||
&Wrapper{IName: "op", Data: []interface{}{PostTable{}}},
|
||||
&Wrapper{IName: "board", Data: []interface{}{board}},
|
||||
if err = queryRowSQL("SELECT `parentid`,`name`,`tripcode`,`email`,`subject`,`password`,`message_raw` FROM `"+config.DBprefix+"posts` WHERE `id` = ? AND `boardid` = ? AND `deleted_timestamp` = ?",
|
||||
[]interface{}{post.ID, post.BoardID, nilTimestamp},
|
||||
[]interface{}{
|
||||
&post.ParentID, &post.Name, &post.Tripcode, &post.Email, &post.Subject,
|
||||
&post.Password, &post.MessageText},
|
||||
); err != nil {
|
||||
html += handleError(1, fmt.Sprintf("Failed building /%s/res/%d.html: %s", board.Dir, 0, err.Error())) + "<br />"
|
||||
serveErrorPage(writer, handleError(0, err.Error()))
|
||||
return
|
||||
} */
|
||||
}
|
||||
|
||||
if post.Password != passwordMD5 && rank == 0 {
|
||||
serveErrorPage(writer, "Wrong password")
|
||||
return
|
||||
}
|
||||
|
||||
if err = post_edit_tmpl.Execute(writer, map[string]interface{}{
|
||||
"config": config,
|
||||
"post": post,
|
||||
"referrer": request.Referer(),
|
||||
}); err != nil {
|
||||
serveErrorPage(writer, handleError(0, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if doEdit == "1" {
|
||||
var postPassword string
|
||||
|
||||
postid, err := strconv.Atoi(request.FormValue("postid"))
|
||||
if err != nil {
|
||||
serveErrorPage(writer, handleError(0, "Invalid form data: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
boardid, err := strconv.Atoi(request.FormValue("boardid"))
|
||||
if err != nil {
|
||||
serveErrorPage(writer, handleError(0, "Invalid form data: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if err = queryRowSQL("SELECT `password` FROM `"+config.DBprefix+"posts` WHERE `id` = ? AND `boardid` = ?",
|
||||
[]interface{}{postid, boardid},
|
||||
[]interface{}{&postPassword},
|
||||
); err != nil {
|
||||
serveErrorPage(writer, handleError(0, "Invalid form data: %s", err.Error()))
|
||||
}
|
||||
|
||||
rank := getStaffRank(request)
|
||||
if request.FormValue("password") != password && rank == 0 {
|
||||
serveErrorPage(writer, "Wrong password")
|
||||
return
|
||||
}
|
||||
|
||||
board, err := getBoardFromID(boardid)
|
||||
if err != nil {
|
||||
serveErrorPage(writer, handleError(0, "Invalid form data: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = execSQL("UPDATE `"+config.DBprefix+"posts` SET "+
|
||||
"`email` = ?, `subject` = ?, `message` = ?, `message_raw` = ? WHERE `id` = ? AND `boardid` = ?",
|
||||
request.FormValue("editemail"), request.FormValue("editsubject"), formatMessage(request.FormValue("editmsg")), request.FormValue("editmsg"),
|
||||
postid, boardid,
|
||||
); err != nil {
|
||||
serveErrorPage(writer, handleError(0, "editing post: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
buildBoards(false, boardid)
|
||||
if request.FormValue("parentid") == "0" {
|
||||
http.Redirect(writer, request, "/"+board.Dir+"/res/"+strconv.Itoa(postid)+".html", http.StatusFound)
|
||||
} else {
|
||||
http.Redirect(writer, request, "/"+board.Dir+"/res/"+request.FormValue("parentid")+".html#"+strconv.Itoa(postid), http.StatusFound)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if deleteBtn == "Delete" {
|
||||
// Delete a post or thread
|
||||
writer.Header().Add("Content-Type", "text/plain")
|
||||
passwordMD5 := md5Sum(password)
|
||||
rank := getStaffRank()
|
||||
rank := getStaffRank(request)
|
||||
|
||||
if passwordMD5 == "" && rank == 0 {
|
||||
serveErrorPage(writer, "Password required for post deletion")
|
||||
|
@ -264,7 +324,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
); 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)
|
||||
fmt.Fprintf(writer, "%d has already been deleted or is a post in a deleted thread.\n", post.ID)
|
||||
continue
|
||||
} else if err != nil {
|
||||
serveErrorPage(writer, handleError(1, err.Error()+"\n"))
|
||||
|
@ -313,7 +373,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
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)
|
||||
fmt.Fprintf(writer, "Attached image from %d deleted successfully\n", post.ID) //<br />\n<meta http-equiv=\"refresh\" content=\"1;url=/"+board+"/\">", post.ID)
|
||||
} else {
|
||||
// delete the post
|
||||
if _, err = execSQL(
|
||||
|
@ -362,7 +422,7 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
buildBoards(false, post.BoardID)
|
||||
|
||||
writer.Header().Add("refresh", "4;url="+request.Referer())
|
||||
fmt.Fprintf(writer, "%d deleted successfully\n<br />", post.ID)
|
||||
fmt.Fprintf(writer, "%d deleted successfully\n", post.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
@ -57,8 +55,12 @@ var funcMap = template.FuncMap{
|
|||
println(v, i...)
|
||||
return ""
|
||||
},
|
||||
"stringAppend": func(a, b string) string {
|
||||
return a + b
|
||||
"stringAppend": func(strings ...string) string {
|
||||
var appended string
|
||||
for _, str := range strings {
|
||||
appended += str
|
||||
}
|
||||
return appended
|
||||
},
|
||||
"truncateMessage": func(msg string, limit int, max_lines int) string {
|
||||
var truncated bool
|
||||
|
@ -89,12 +91,10 @@ var funcMap = template.FuncMap{
|
|||
if len(msg) > limit {
|
||||
if ellipsis {
|
||||
return msg[:limit] + "..."
|
||||
} else {
|
||||
return msg[:limit]
|
||||
}
|
||||
} else {
|
||||
return msg
|
||||
return msg[:limit]
|
||||
}
|
||||
return msg
|
||||
},
|
||||
"escapeString": func(a string) string {
|
||||
return html.EscapeString(a)
|
||||
|
@ -129,9 +129,9 @@ var funcMap = template.FuncMap{
|
|||
} else if name[len(name)-4:] == "webm" {
|
||||
name = name[:len(name)-4] + "jpg"
|
||||
}
|
||||
ext_begin := strings.LastIndex(name, ".")
|
||||
new_name := name[:ext_begin] + "t." + getFileExtension(name)
|
||||
return new_name
|
||||
extBegin := strings.LastIndex(name, ".")
|
||||
newName := name[:extBegin] + "t." + getFileExtension(name)
|
||||
return newName
|
||||
},
|
||||
"getUploadType": func(name string) string {
|
||||
extension := getFileExtension(name)
|
||||
|
@ -177,26 +177,29 @@ var funcMap = template.FuncMap{
|
|||
|
||||
var (
|
||||
banpage_tmpl *template.Template
|
||||
errorpage_tmpl *template.Template
|
||||
front_page_tmpl *template.Template
|
||||
global_header_tmpl *template.Template
|
||||
img_boardpage_tmpl *template.Template
|
||||
img_threadpage_tmpl *template.Template
|
||||
img_post_form_tmpl *template.Template
|
||||
post_edit_tmpl *template.Template
|
||||
manage_header_tmpl *template.Template
|
||||
manage_boards_tmpl *template.Template
|
||||
manage_config_tmpl *template.Template
|
||||
front_page_tmpl *template.Template
|
||||
// manage_bans_tmpl *template.Template
|
||||
manage_boards_tmpl *template.Template
|
||||
manage_config_tmpl *template.Template
|
||||
manage_header_tmpl *template.Template
|
||||
post_edit_tmpl *template.Template
|
||||
)
|
||||
|
||||
func loadTemplate(files ...string) (*template.Template, error) {
|
||||
if len(files) == 0 {
|
||||
return nil, errors.New("ERROR: no files named in call to loadTemplate")
|
||||
return nil, errors.New("No files named in call to loadTemplate")
|
||||
}
|
||||
var templates []string
|
||||
for i, file := range files {
|
||||
templates = append(templates, file)
|
||||
files[i] = config.TemplateDir + "/" + files[i]
|
||||
}
|
||||
|
||||
return template.New(templates[0]).Funcs(funcMap).ParseFiles(files...)
|
||||
}
|
||||
|
||||
|
@ -212,6 +215,11 @@ func initTemplates() error {
|
|||
return templateError("banpage.html", err)
|
||||
}
|
||||
|
||||
errorpage_tmpl, err = loadTemplate("error.html")
|
||||
if err != nil {
|
||||
return templateError("error.html", err)
|
||||
}
|
||||
|
||||
global_header_tmpl, err = loadTemplate("global_header.html")
|
||||
if err != nil {
|
||||
return templateError("global_header.html", err)
|
||||
|
@ -227,16 +235,16 @@ func initTemplates() error {
|
|||
return templateError("img_threadpage.html", err)
|
||||
}
|
||||
|
||||
/* post_edit_tmpl, err = loadTemplate("post_edit_tmpl", "post_edit.html")
|
||||
post_edit_tmpl, err = loadTemplate("post_edit.html", "img_header.html", "global_footer.html")
|
||||
if err != nil {
|
||||
return templateError("img_threadpage.html", err)
|
||||
} */
|
||||
|
||||
manage_header_tmpl, err = loadTemplate("manage_header.html")
|
||||
if err != nil {
|
||||
return templateError("manage_header.html", err)
|
||||
}
|
||||
|
||||
/* manage_bans_tmpl, err = loadTemplate("manage_bans.html")
|
||||
if err != nil {
|
||||
return templateError("manage_bans.html", err)
|
||||
} */
|
||||
|
||||
manage_boards_tmpl, err = loadTemplate("manage_boards.html")
|
||||
if err != nil {
|
||||
return templateError("manage_boards.html", err)
|
||||
|
@ -247,21 +255,14 @@ func initTemplates() error {
|
|||
return templateError("manage_config.html", err)
|
||||
}
|
||||
|
||||
manage_header_tmpl, err = loadTemplate("manage_header.html")
|
||||
if err != nil {
|
||||
return templateError("manage_header.html", err)
|
||||
}
|
||||
|
||||
front_page_tmpl, err = loadTemplate("front.html", "global_footer.html")
|
||||
if err != nil {
|
||||
return templateError("front.html", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStyleLinks(w http.ResponseWriter, stylesheet string) {
|
||||
styles_map := make(map[int]string)
|
||||
for i := 0; i < len(config.Styles_img); i++ {
|
||||
styles_map[i] = config.Styles_img[i]
|
||||
}
|
||||
|
||||
if err := manage_header_tmpl.Execute(w, config); err != nil {
|
||||
handleError(0, customError(err))
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
|
10
src/util.go
10
src/util.go
|
@ -328,16 +328,6 @@ func getSectionArr(where string) (sections []interface{}, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getCookie(name string) *http.Cookie {
|
||||
numCookies := len(cookies)
|
||||
for c := 0; c < numCookies; c++ {
|
||||
if cookies[c].Name == name {
|
||||
return cookies[c]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCountryCode(ip string) (string, error) {
|
||||
if config.EnableGeoIP && config.GeoIPDBlocation != "" {
|
||||
gi, err := libgeo.Load(config.GeoIPDBlocation)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Error :c</title>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{.ErrorTitle}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<h1>Error!</h1>
|
||||
<h2>{ERRORTEXT}</h2>
|
||||
</center>
|
||||
<h1>{{.ErrorHeader}}</h1>
|
||||
<img src="{{.ErrorImage}}" border="0" alt="">
|
||||
<p>{{.ErrorText}}</p>
|
||||
<hr><address>http://gochan.org powered by Gochan {{.config.Version}}</address>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
38
templates/post_edit.html
Normal file
38
templates/post_edit.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Post</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}}];
|
||||
var webroot = "{{$.config.SiteWebfolder}}";
|
||||
</script>
|
||||
<script type="text/javascript" src="/javascript/gochan.js"></script>
|
||||
<script type="text/javascript" src="/javascript/manage.js"></script>
|
||||
<link rel="stylesheet" href="/css/global/img.css" />
|
||||
{{range $_, $style := .config.Styles_img}}
|
||||
<link rel="{{if not (isStyleDefault_img $style)}}alternate {{end}}stylesheet" href="/css/{{$style}}/img.css" />{{end}}
|
||||
<link rel="shortcut icon" href="/favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Edit post</h1><br />
|
||||
<div class="subtitle"><a href="{{.referrer}}">Return</a></div>
|
||||
</header>
|
||||
|
||||
<form action="/util" method="POST" id="edit-form">
|
||||
<input name="postid" type="hidden" value="{{.post.ID}}" />
|
||||
<input name="boardid" type="hidden" value="{{.post.BoardID}}" />
|
||||
<input name="parentid" type="hidden" value="{{.post.ParentID}}" />
|
||||
<input name="password" type="hidden" value="{{.post.Password}}" />
|
||||
<input name="doedit" type="hidden" value="1" />
|
||||
<table id="postbox-static" align="center">
|
||||
<tr><th class="postblock">Name</th><td>{{stringAppend .post.Name "#" .post.Tripcode}}</td></tr>
|
||||
<tr><th class="postblock">Email</th><td>{{.post.Email}}</td></tr>
|
||||
<tr><th class="postblock">Subject</th><td><input type="text" name="editsubject" maxlength="100" size="30" autocomplete="off" value="{{.post.Subject}}"/><input type="submit" value="{{with .op}}Reply{{else}}Post{{end}}"/></td></tr>
|
||||
<tr><th class="postblock">Message</th><td><textarea rows="4" cols="48" name="editmsg" id="editmsg">{{.post.MessageText}}</textarea></td></tr>
|
||||
</table>
|
||||
</form><br />
|
||||
{{template "global_footer.html" .}}
|
Loading…
Add table
Add a link
Reference in a new issue