mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-20 09:26:23 -07:00
generate pages for boards and threads
This commit is contained in:
parent
a8ab09a48f
commit
4a1d0c1efd
17 changed files with 1379 additions and 1447 deletions
4
build.sh
4
build.sh
|
@ -8,6 +8,10 @@ fi
|
|||
CGO_ENABLED=0
|
||||
GOARCH=amd64
|
||||
SUFFIX=""
|
||||
if [[ $GOOS == "windows" ]]
|
||||
then
|
||||
SUFFIX=".exe"
|
||||
fi
|
||||
|
||||
go build -v -ldflags "-w" -o gochan$SUFFIX ./src
|
||||
# the -w ldflag omits debugging stuff
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
body{margin:0;padding:8px;margin-bottom:auto;}blockquote blockquote{margin-left:0em;}form{margin-bottom:0px;}form .trap{display:none;}.blotter{color:red;font-size:12pt;}.postarea{text-align:center;}.postarea table{margin:0px auto;text-align:left;}.thumb{border:none;float:left;margin:2px 20px;}.nothumb{float:left;background:inherit;border:2px dashed #aaa;text-align:center;margin:2px 20px;padding:1em 0.5em 1em 0.5em;font-family:none;}.reply blockquote,blockquote :last-child{margin-bottom:0em;}.reflink a{color:inherit;text-decoration:none;}.reflink a:hover{color:#800000;}.reply .filesize{
|
||||
}.userdelete{float:right;text-align:center;white-space:nowrap;}.replypage .replylink{display:none;}.pagelist{max-width:600px;}.admin{color:#800080;font-weight:normal;}.mod{color:#FF0000;font-weight:normal;}.vip{color:#336600;font-weight:normal;}#watchedthreads{position:absolute;background-color:#F0E0D6;border:1px dotted #EEAA88;border-top:0px none;}#watchedthreadsdraghandle{text-align:center;font-family:Trebuchet MS;cursor:move;}#watchedthreadlist{padding:3px;font-size:0.8em;}#watchedthreadsbuttons{position:absolute;bottom:3px;left:3px;}.spoiler{color:black;background-color:black;}.extrabtns{vertical-align:middle;}.hidethread{background:transparent url('./icons/blue/icons.gif') -32px -16px no-repeat;}.unhidethread{background:transparent url('./icons/blue/icons.gif') -48px 0px no-repeat;}.watchthread{background:transparent url('./icons/blue/icons.gif') -32px 0px no-repeat;}.expandthread{background:transparent url('./icons/blue/icons.gif') 0px -16px no-repeat;}.quickreply{background:transparent url('./icons/blue/icons.gif') 0px 0px no-repeat;}.hidewatchedthreads{background:transparent url('./icons/blue/icons.gif') -48px -16px no-repeat;}.refreshwatchedthreads{background:transparent url('./icons/blue/icons.gif') -16px -16px no-repeat;}.restorewatchedthreads{background:transparent url('./icons/blue/icons.gif') -16px 0px no-repeat;}.reflinkpreview{position:absolute;padding:5px;background-color:#F0E0D6;border:1px dotted #000000;}
|
5
html/error/404.html
Normal file → Executable file
5
html/error/404.html
Normal file → Executable file
|
@ -5,9 +5,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<h1>404: File not found</h1>
|
||||
<!--<img src="/error.png" border="0" alt=""> -->
|
||||
<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>
|
||||
<audio src="http://dl.dropbox.com/u/10266670/forever.wav" autoplay="autoplay"></audio>
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.8</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v0.9</address>
|
||||
</body>
|
||||
</html>
|
4
html/error/500.html
Normal file → Executable file
4
html/error/500.html
Normal file → Executable file
|
@ -6,7 +6,7 @@
|
|||
<body>
|
||||
<h1>500: Internal Server error</h1>
|
||||
<marquee><img src="/error/derpy server.gif" border="0" alt=""></marquee>
|
||||
<p>Someone let Derpy into the server room again...sorry about that. Please try reloading the page. If that doesn't fix the problem, you can email me <a href="mailto:admin@lunachan.net">here</a>, noting the time and the page you tried to access.
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.8</address>
|
||||
<p>Someone dun goof'd...sorry about that. Please try reloading the page. If that doesn't fix the problem, you can email the admin at admin@email.here, noting the time and the page you tried to access.
|
||||
<hr><address>http://gochan.org powered by Gochan v0.9</address>
|
||||
</body>
|
||||
</html>
|
2
html/error/500_example.html
Normal file → Executable file
2
html/error/500_example.html
Normal file → Executable file
|
@ -6,6 +6,6 @@
|
|||
<body>
|
||||
<h1>500: Internal Server error</h1>
|
||||
<p>The server encountered an error while trying to serve the page. We apologize for the inconvenience.</p>
|
||||
<hr><address>http://lunachan.net powered by Gochan v0.8</address>
|
||||
<hr><address>http://gochan.org powered by Gochan v0.9</address>
|
||||
</body>
|
||||
</html>
|
BIN
html/error/lol 404.gif
Executable file
BIN
html/error/lol 404.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 191 KiB |
7
src/gochan.go
Normal file → Executable file
7
src/gochan.go
Normal file → Executable file
|
@ -4,8 +4,7 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
const version float32 = 0.8
|
||||
|
||||
const version float32 = 0.9
|
||||
|
||||
func main() {
|
||||
defer db.Close()
|
||||
|
@ -17,7 +16,7 @@ func main() {
|
|||
initTemplates()
|
||||
fmt.Println("Initializing server...")
|
||||
if db != nil {
|
||||
db.Exec("USE `"+config.DBname+"`;")
|
||||
db.Exec("USE `" + config.DBname + "`;")
|
||||
}
|
||||
initServer()
|
||||
}
|
||||
}
|
||||
|
|
1214
src/manage.go
1214
src/manage.go
File diff suppressed because it is too large
Load diff
453
src/posting.go
Normal file → Executable file
453
src/posting.go
Normal file → Executable file
|
@ -26,7 +26,9 @@ import (
|
|||
const whitespace_match = "[\000-\040]"
|
||||
|
||||
var (
|
||||
last_post PostTable
|
||||
last_post PostTable
|
||||
all_sections []interface{}
|
||||
all_boards []interface{}
|
||||
)
|
||||
|
||||
func generateTripCode(input string) string {
|
||||
|
@ -38,143 +40,231 @@ func generateTripCode(input string) string {
|
|||
return crypt.Crypt(input, salt)[3:]
|
||||
}
|
||||
|
||||
func buildBoardPage(boardid int, boards []BoardsTable, sections []interface{}) (html string) {
|
||||
start_time := benchmarkTimer("buildBoard"+string(boardid), time.Now(), true)
|
||||
var board BoardsTable
|
||||
for b, _ := range boards {
|
||||
if boards[b].ID == boardid {
|
||||
board = boards[b]
|
||||
}
|
||||
func buildAll() {
|
||||
buildFrontPage()
|
||||
buildBoards(true, 0)
|
||||
}
|
||||
|
||||
func buildBoards(all bool, which int) (html string) {
|
||||
// if all is set to true, ignore which, otherwise, which = build only specified boardid
|
||||
if !all {
|
||||
_board, _ := getBoardArr("`id` = " + strconv.Itoa(which))
|
||||
board := _board[0]
|
||||
html += buildBoardPages(&board) + "<br />\n"
|
||||
html += buildThreads(true, board.ID, 0)
|
||||
}
|
||||
boards, _ := getBoardArr("")
|
||||
if len(boards) == 0 {
|
||||
return html + "No boards to build.<br />\n"
|
||||
}
|
||||
|
||||
for _, board := range boards {
|
||||
html += buildBoardPages(&board) + "<br />\n"
|
||||
html += buildThreads(true, board.ID, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func buildBoardPages(board *BoardsTable) (html string) {
|
||||
// start_time := benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), time.Now(), true)
|
||||
var boardinfo_i []interface{}
|
||||
var current_page_file *os.File
|
||||
var interfaces []interface{}
|
||||
var threads []interface{}
|
||||
var op_posts []interface{}
|
||||
op_posts, err := getPostArr("SELECT * FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = 0 AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `bumped` DESC LIMIT " + strconv.Itoa(config.ThreadsPerPage_img))
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
op_posts = make([]interface{}, 0)
|
||||
}
|
||||
var thread_pages [][]interface{}
|
||||
var stickied_threads []interface{}
|
||||
var nonstickied_threads []interface{}
|
||||
|
||||
for _, op_post_i := range op_posts {
|
||||
var thread Thread
|
||||
var posts_in_thread []interface{}
|
||||
|
||||
op_post := op_post_i.(PostTable)
|
||||
|
||||
if op_post.Stickied {
|
||||
thread.IName = "thread"
|
||||
|
||||
posts_in_thread, err = getPostArr("SELECT * FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID) + " AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `id` DESC LIMIT " + strconv.Itoa(config.StickyRepliesOnBoardPage))
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
err = db.QueryRow("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID)).Scan(&thread.NumReplies)
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
thread.OP = op_post_i
|
||||
if len(posts_in_thread) > 0 {
|
||||
thread.BoardReplies = posts_in_thread
|
||||
}
|
||||
threads = append(threads, thread)
|
||||
defer func() {
|
||||
if uhoh, ok := recover().(error); ok {
|
||||
error_log.Print("buildBoardPages failed: " + uhoh.Error())
|
||||
fmt.Println("buildBoardPages failed: " + uhoh.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for _, op_post_i := range op_posts {
|
||||
var thread Thread
|
||||
var posts_in_thread []interface{}
|
||||
|
||||
op_post := op_post_i.(PostTable)
|
||||
if !op_post.Stickied {
|
||||
thread.IName = "thread"
|
||||
|
||||
posts_in_thread, err = getPostArr("SELECT * FROM (SELECT * FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID) + " AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `id` DESC LIMIT " + strconv.Itoa(config.RepliesOnBoardpage) + ") t ORDER BY `id` ASC")
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
err = db.QueryRow("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID)).Scan(&thread.NumReplies)
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
thread.OP = op_post_i
|
||||
if len(posts_in_thread) > 0 {
|
||||
thread.BoardReplies = posts_in_thread
|
||||
}
|
||||
threads = append(threads, thread)
|
||||
}
|
||||
}
|
||||
|
||||
interfaces = append(interfaces, config)
|
||||
|
||||
var boards_i []interface{}
|
||||
for _, b := range boards {
|
||||
boards_i = append(boards_i, b)
|
||||
}
|
||||
var boardinfo_i []interface{}
|
||||
boardinfo_i = append(boardinfo_i, board)
|
||||
|
||||
interfaces = append(interfaces, &Wrapper{IName: "boards", Data: boards_i})
|
||||
interfaces = append(interfaces, &Wrapper{IName: "sections", Data: sections})
|
||||
interfaces = append(interfaces, &Wrapper{IName: "threads", Data: threads})
|
||||
interfaces = append(interfaces, &Wrapper{IName: "boardinfo", Data: boardinfo_i})
|
||||
|
||||
wrapped := &Wrapper{IName: "boardpage", Data: interfaces}
|
||||
os.Remove(path.Join(config.DocumentRoot, board.Dir, "board.html"))
|
||||
current_page_file.Close()
|
||||
}()
|
||||
|
||||
results, err := os.Stat(path.Join(config.DocumentRoot, board.Dir))
|
||||
if err != nil {
|
||||
err = os.Mkdir(path.Join(config.DocumentRoot, board.Dir), 0777)
|
||||
if err != nil {
|
||||
html += "Failed creating /" + board.Dir + "/: " + err.Error() + "<br />\n"
|
||||
error_log.Println("Failed creating /" + board.Dir + "/: " + err.Error())
|
||||
}
|
||||
} else if !results.IsDir() {
|
||||
html += "Error: /" + board.Dir + "/ exists, but is not a folder. <br />\n"
|
||||
error_log.Println("Error: /" + board.Dir + "/ exists, but is not a folder.")
|
||||
}
|
||||
|
||||
board_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
op_posts, err := getPostArr("`boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = 0 AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `bumped` DESC")
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />\n"
|
||||
html += err.Error() + "<br />"
|
||||
op_posts = make([]interface{}, 0)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if uhoh, ok := recover().(error); ok {
|
||||
error_log.Print("Failed executing template.")
|
||||
fmt.Println(uhoh.Error())
|
||||
for _, op_post_i := range op_posts {
|
||||
var thread Thread
|
||||
var posts_in_thread []interface{}
|
||||
|
||||
thread.IName = "thread"
|
||||
|
||||
op_post := op_post_i.(PostTable)
|
||||
|
||||
if op_post.Stickied {
|
||||
posts_in_thread, err = getPostArr("`boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID) + " AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `id` DESC LIMIT " + strconv.Itoa(config.StickyRepliesOnBoardPage))
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
err = db.QueryRow("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID)).Scan(&thread.NumReplies)
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
thread.OP = op_post_i
|
||||
if len(posts_in_thread) > 0 {
|
||||
thread.BoardReplies = posts_in_thread
|
||||
}
|
||||
stickied_threads = append(stickied_threads, thread)
|
||||
} else {
|
||||
posts_in_thread, err = getPostArr("`boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID) + " AND `deleted_timestamp` = '" + nil_timestamp + "' ORDER BY `id` DESC LIMIT " + strconv.Itoa(config.RepliesOnBoardpage))
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
err = db.QueryRow("SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board.ID) + " AND `parentid` = " + strconv.Itoa(op_post.ID)).Scan(&thread.NumReplies)
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
}
|
||||
thread.OP = op_post_i
|
||||
if len(posts_in_thread) > 0 {
|
||||
thread.BoardReplies = posts_in_thread
|
||||
}
|
||||
nonstickied_threads = append(nonstickied_threads, thread)
|
||||
}
|
||||
if board_file != nil {
|
||||
board_file.Close()
|
||||
}
|
||||
}()
|
||||
err = img_boardpage_tmpl.Execute(board_file, wrapped)
|
||||
if err != nil {
|
||||
html += "Failed building /" + board.Dir + "/: " + err.Error() + "<br />\n"
|
||||
error_log.Print(err.Error())
|
||||
} else {
|
||||
html += "/" + board.Dir + "/ built successfully.\n"
|
||||
}
|
||||
benchmarkTimer("buildBoard"+string(boardid), start_time, false)
|
||||
threads = append(stickied_threads, nonstickied_threads...)
|
||||
thread_pages = paginate(config.ThreadsPerPage_img, threads)
|
||||
|
||||
deleteMatchingFiles(path.Join(config.DocumentRoot, board.Dir), "\\.html$")
|
||||
board.NumPages = len(thread_pages) - 1
|
||||
for page_num, page_threads := range thread_pages {
|
||||
board.CurrentPage = page_num
|
||||
boardinfo_i = nil
|
||||
boardinfo_i = append(boardinfo_i, board)
|
||||
|
||||
interfaces = nil
|
||||
interfaces = append(interfaces, config,
|
||||
&Wrapper{IName: "boards", Data: all_boards},
|
||||
&Wrapper{IName: "sections", Data: all_sections},
|
||||
&Wrapper{IName: "threads", Data: page_threads},
|
||||
&Wrapper{IName: "boardinfo", Data: boardinfo_i})
|
||||
wrapped := &Wrapper{IName: "boardpage", Data: interfaces}
|
||||
|
||||
if board.CurrentPage == 0 {
|
||||
current_page_file, err = os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
} else {
|
||||
current_page_file, err = os.OpenFile(path.Join(config.DocumentRoot, board.Dir, strconv.Itoa(page_num)+".html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
}
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />\n"
|
||||
error_log.Println(err.Error())
|
||||
}
|
||||
|
||||
err = img_boardpage_tmpl.Execute(current_page_file, wrapped)
|
||||
if err != nil {
|
||||
html += "Failed building /" + board.Dir + "/: " + err.Error() + "<br />\n"
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
html += "/" + board.Dir + "/ built successfully.\n"
|
||||
//benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
return
|
||||
}
|
||||
|
||||
func buildFrontPage(boards []BoardsTable, sections []interface{}) (html string) {
|
||||
initTemplates()
|
||||
func buildThreads(all bool, boardid, threadid int) (html string) {
|
||||
// TODO: detect which page will be built and only build that one and the board page
|
||||
// if all is set to true, ignore which, otherwise, which = build only specified boardid
|
||||
if !all {
|
||||
_thread, _ := getPostArr("`boardid` = " + strconv.Itoa(boardid) + " AND `id` = " + strconv.Itoa(threadid) + " AND `parentid` = 0 AND `deleted_timestamp` = '" + nil_timestamp + "'")
|
||||
thread := _thread[0]
|
||||
thread_struct := thread.(PostTable)
|
||||
html += buildThreadPages(&thread_struct) + "<br />\n"
|
||||
}
|
||||
threads, _ := getPostArr("`boardid` = " + strconv.Itoa(boardid) + " AND `parentid` = 0 AND `deleted_timestamp` = '" + nil_timestamp + "'")
|
||||
if len(threads) == 0 {
|
||||
return html + "No threads to build.<br />\n"
|
||||
}
|
||||
for _, op := range threads {
|
||||
op_struct := op.(PostTable)
|
||||
html += buildThreadPages(&op_struct) + "<br />\n"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func buildThreadPages(op *PostTable) (html string) {
|
||||
var board_dir string
|
||||
var replies []interface{}
|
||||
var current_page_file *os.File
|
||||
|
||||
row := db.QueryRow("SELECT `dir` FROM `" + config.DBprefix + "boards` WHERE `id` = '" + strconv.Itoa(op.BoardID) + "';")
|
||||
err := row.Scan(&board_dir)
|
||||
if err != nil {
|
||||
error_log.Println(err.Error())
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
replies, err = getPostArr("`boardid` = " + strconv.Itoa(op.BoardID) + " AND `parentid` = " + strconv.Itoa(op.ID) + " AND `deleted_timestamp` = '" + nil_timestamp + "'")
|
||||
if err != nil {
|
||||
return "Error building thread " + strconv.Itoa(op.ID) + ":" + err.Error()
|
||||
}
|
||||
thread_pages := paginate(config.PostsPerThreadpage, replies)
|
||||
for i, _ := range thread_pages {
|
||||
thread_pages[i] = append([]interface{}{op}, thread_pages[i]...)
|
||||
}
|
||||
deleteMatchingFiles(path.Join(config.DocumentRoot, board_dir, "res"), "\\.html$")
|
||||
op.NumPages = len(thread_pages) - 1
|
||||
for page_num, page_posts := range thread_pages {
|
||||
fmt.Printf("len(page_posts): %d\n", len(page_posts))
|
||||
op.CurrentPage = page_num
|
||||
var interfaces []interface{}
|
||||
interfaces = append(interfaces, config,
|
||||
&Wrapper{IName: "boards_", Data: all_boards},
|
||||
&Wrapper{IName: "sections_w", Data: all_sections},
|
||||
&Wrapper{IName: "posts_w", Data: page_posts})
|
||||
|
||||
wrapped := &Wrapper{IName: "threadpage", Data: interfaces}
|
||||
|
||||
if op.CurrentPage == 0 {
|
||||
current_page_file, err = os.OpenFile(path.Join(config.DocumentRoot, board_dir, "res", strconv.Itoa(op.ID)+".html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
} else {
|
||||
current_page_file, err = os.OpenFile(path.Join(config.DocumentRoot, board_dir, "res", strconv.Itoa(op.ID)+"p"+strconv.Itoa(op.CurrentPage)+".html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
}
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />\n"
|
||||
error_log.Println(err.Error())
|
||||
}
|
||||
|
||||
err = img_threadpage_tmpl.Execute(current_page_file, wrapped)
|
||||
if err != nil {
|
||||
html += "Failed building /" + board_dir + "/" + strconv.Itoa(op.ID) + ": " + err.Error() + "<br />\n"
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func buildFrontPage() (html string) {
|
||||
initTemplates()
|
||||
var front_arr []interface{}
|
||||
var recent_posts_arr []interface{}
|
||||
var boards_arr []interface{}
|
||||
|
||||
for _, board := range boards {
|
||||
boards_arr = append(boards_arr, board)
|
||||
}
|
||||
|
||||
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, 0777)
|
||||
/*defer func() {
|
||||
defer func() {
|
||||
if front_file != nil {
|
||||
front_file.Close()
|
||||
}
|
||||
}()*/
|
||||
}()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
@ -227,17 +317,12 @@ func buildFrontPage(boards []BoardsTable, sections []interface{}) (html string)
|
|||
recent_posts_arr = append(recent_posts_arr, recent_post)
|
||||
}
|
||||
|
||||
page_data := &Wrapper{IName: "fronts", Data: front_arr}
|
||||
board_data := &Wrapper{IName: "boards", Data: boards_arr}
|
||||
section_data := &Wrapper{IName: "sections", Data: sections}
|
||||
recent_posts_data := &Wrapper{IName: "recent posts", Data: recent_posts_arr}
|
||||
|
||||
var interfaces []interface{}
|
||||
interfaces = append(interfaces, config)
|
||||
interfaces = append(interfaces, page_data)
|
||||
interfaces = append(interfaces, board_data)
|
||||
interfaces = append(interfaces, section_data)
|
||||
interfaces = append(interfaces, recent_posts_data)
|
||||
interfaces = append(interfaces, config,
|
||||
&Wrapper{IName: "fronts", Data: front_arr},
|
||||
&Wrapper{IName: "boards", Data: all_boards},
|
||||
&Wrapper{IName: "sections", Data: all_sections},
|
||||
&Wrapper{IName: "recent posts", Data: recent_posts_arr})
|
||||
|
||||
wrapped := &Wrapper{IName: "frontpage", Data: interfaces}
|
||||
err = front_page_tmpl.Execute(front_file, wrapped)
|
||||
|
@ -251,104 +336,7 @@ func buildFrontPage(boards []BoardsTable, sections []interface{}) (html string)
|
|||
return "Front page rebuilt successfully.<br />"
|
||||
}
|
||||
|
||||
func buildThread(op_id int, board_id int) (err error) {
|
||||
var posts []PostTable
|
||||
var post_table_interface []interface{}
|
||||
start_time := benchmarkTimer("buildThread"+string(op_id), time.Now(), true)
|
||||
|
||||
rows, err := db.Query("SELECT * FROM `" + config.DBprefix + "posts` WHERE `deleted_timestamp` = '" + nil_timestamp + "' AND (`parentid` = " + strconv.Itoa(op_id) + " OR `id` = " + strconv.Itoa(op_id) + ") AND `boardid` = " + strconv.Itoa(board_id))
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var post PostTable
|
||||
err = rows.Scan(&post.ID, &post.BoardID, &post.ParentID, &post.Name, &post.Tripcode, &post.Email, &post.Subject, &post.Message, &post.Password, &post.Filename, &post.FilenameOriginal, &post.FileChecksum, &post.Filesize, &post.ImageW, &post.ImageH, &post.ThumbW, &post.ThumbH, &post.IP, &post.Tag, &post.Timestamp, &post.Autosage, &post.PosterAuthority, &post.DeletedTimestamp, &post.Bumped, &post.Stickied, &post.Locked, &post.Reviewed, &post.Sillytag)
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
|
||||
for _, post := range posts {
|
||||
post_msg_before := post.Message
|
||||
post.Message = parseBacklinks(post.Message, post.BoardID)
|
||||
if post_msg_before != post.Message {
|
||||
_, err := db.Exec("UPDATE `" + config.DBprefix + "posts` SET `message` = '" + post.Message + "' WHERE `id` = " + strconv.Itoa(post.ID))
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
}
|
||||
}
|
||||
post_table_interface = append(post_table_interface, post)
|
||||
}
|
||||
board_arr := getBoardArr("")
|
||||
sections_arr := getSectionArr("")
|
||||
|
||||
var board_dir string
|
||||
for _, board_i := range board_arr {
|
||||
board := board_i
|
||||
|
||||
if board.ID == board_id {
|
||||
board_dir = board.Dir
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// create a file object of the board's thread directory so we can search for and delete the given thread's sub pages to be rebuilt
|
||||
threads_dir, err := os.Open(path.Join(config.DocumentRoot, board_dir, "res"))
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
thread_files, err := threads_dir.Readdir(-1)
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}
|
||||
for _, thread_file := range thread_files {
|
||||
if strings.Index(thread_file.Name(), "p") > -1 {
|
||||
os.Remove(path.Join(config.DocumentRoot, board_dir, "res", thread_file.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
//var num_pages int
|
||||
/*err = db.QueryRow("SELECT (SELECT COUNT(*) FROM `" + config.DBprefix + "posts` WHERE `boardid` = " + strconv.Itoa(board_id) + ") AS `count` WHERE `boardid` = " + strconv.Itoa(board_id) + " ORDER BY `" + config.DBprefix + "posts`.`id` DESC LIMIT 1").Scan(&num_posts)
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
}*/
|
||||
var interfaces []interface{}
|
||||
interfaces = append(interfaces, config)
|
||||
interfaces = append(interfaces, post_table_interface)
|
||||
var board_arr_i []interface{}
|
||||
for _, b := range board_arr {
|
||||
board_arr_i = append(board_arr_i, b)
|
||||
}
|
||||
interfaces = append(interfaces, &Wrapper{IName: "boards", Data: board_arr_i})
|
||||
interfaces = append(interfaces, &Wrapper{IName: "sections", Data: sections_arr})
|
||||
|
||||
wrapped := &Wrapper{IName: "threadpage", Data: interfaces}
|
||||
os.Remove(path.Join(config.DocumentRoot, board_dir+"/res/"+strconv.Itoa(op_id)+".html"))
|
||||
thread_file, err := os.OpenFile(path.Join(config.DocumentRoot, board_dir+"/res/"+strconv.Itoa(op_id)+".html"), os.O_CREATE|os.O_RDWR, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if _, ok := recover().(error); ok {
|
||||
error_log.Print("Failed executing template.")
|
||||
}
|
||||
if thread_file != nil {
|
||||
thread_file.Close()
|
||||
}
|
||||
}()
|
||||
err = img_thread_tmpl.Execute(thread_file, wrapped)
|
||||
benchmarkTimer("buildThread"+string(op_id), start_time, false)
|
||||
return err
|
||||
}
|
||||
|
||||
// checks to see if the poster's tripcode/name is banned, if the IP is banned, or if the file checksum is banned
|
||||
// Checks check poster's name/tripcode/file checksum (from PostTable post) for banned status
|
||||
// returns true if the user is banned
|
||||
func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interface{}, error) {
|
||||
var is_expired bool
|
||||
|
@ -371,9 +359,7 @@ func checkBannedStatus(post *PostTable, writer *http.ResponseWriter) ([]interfac
|
|||
return interfaces, err
|
||||
}
|
||||
} else {
|
||||
|
||||
is_expired = ban_entry.Expires.After(time.Now()) == false
|
||||
|
||||
if is_expired {
|
||||
// if it is expired, send a message saying that it's expired, but still post
|
||||
fmt.Println("expired")
|
||||
|
@ -420,19 +406,6 @@ func createThumbnail(image_obj image.Image, size string) image.Image {
|
|||
return image_obj
|
||||
}
|
||||
|
||||
func getFiletype(name string) string {
|
||||
filetype := strings.ToLower(name[len(name)-4:])
|
||||
if filetype == ".gif" {
|
||||
return "gif"
|
||||
} else if filetype == ".jpg" || filetype == "jpeg" {
|
||||
return "jpg"
|
||||
} else if filetype == ".png" {
|
||||
return "png"
|
||||
} else {
|
||||
return name[len(name)-3:]
|
||||
}
|
||||
}
|
||||
|
||||
func getNewFilename() string {
|
||||
now := time.Now().Unix()
|
||||
rand.Seed(now)
|
||||
|
@ -525,7 +498,8 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
|
||||
var email_command string
|
||||
|
||||
post_name := escapeString(request.FormValue("postname"))
|
||||
post_name := html.EscapeString(escapeString(request.FormValue("postname")))
|
||||
|
||||
if strings.Index(post_name, "#") == -1 {
|
||||
post.Name = post_name
|
||||
} else if strings.Index(post_name, "#") == 0 {
|
||||
|
@ -601,18 +575,19 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
server.ServeErrorPage(w, "Couldn't read file")
|
||||
} else {
|
||||
post.FilenameOriginal = handler.Filename
|
||||
filetype := getFiletype(post.FilenameOriginal)
|
||||
filetype := getFileExtension(post.FilenameOriginal)
|
||||
thumb_filetype := filetype
|
||||
if thumb_filetype == "gif" {
|
||||
thumb_filetype = "jpg"
|
||||
}
|
||||
post.FilenameOriginal = escapeString(post.FilenameOriginal)
|
||||
post.Filename = getNewFilename() + "." + getFiletype(post.FilenameOriginal)
|
||||
board_arr := getBoardArr("`id` = " + request.FormValue("boardid"))
|
||||
post.Filename = getNewFilename() + "." + getFileExtension(post.FilenameOriginal)
|
||||
board_arr, _ := getBoardArr("`id` = " + request.FormValue("boardid"))
|
||||
if len(board_arr) == 0 {
|
||||
server.ServeErrorPage(w, "No boards have been created yet")
|
||||
}
|
||||
board_dir := getBoardArr("`id` = " + request.FormValue("boardid"))[0].Dir
|
||||
_board_dir, _ := getBoardArr("`id` = " + request.FormValue("boardid"))
|
||||
board_dir := _board_dir[0].Dir
|
||||
file_path := path.Join(config.DocumentRoot, "/"+board_dir+"/src/", post.Filename)
|
||||
thumb_path := path.Join(config.DocumentRoot, "/"+board_dir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "t."+thumb_filetype, -1))
|
||||
catalog_thumb_path := path.Join(config.DocumentRoot, "/"+board_dir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "c."+thumb_filetype, -1))
|
||||
|
@ -737,19 +712,11 @@ func makePost(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// rebuild the thread page
|
||||
if post.ParentID > 0 {
|
||||
buildThread(post.ParentID, post.BoardID)
|
||||
} else {
|
||||
buildThread(post.ID, post.BoardID)
|
||||
}
|
||||
|
||||
boards, _ := getBoardArr("")
|
||||
// rebuild the board page
|
||||
boards := getBoardArr("")
|
||||
sections := getSectionArr("")
|
||||
buildBoardPage(post.BoardID, boards, sections)
|
||||
buildBoards(false, post.BoardID)
|
||||
|
||||
buildFrontPage(boards, sections)
|
||||
buildFrontPage()
|
||||
|
||||
if email_command == "noko" {
|
||||
if post.ParentID == 0 {
|
||||
|
|
165
src/server.go
Normal file → Executable file
165
src/server.go
Normal file → Executable file
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
@ -15,18 +15,18 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
form url.Values
|
||||
header http.Header
|
||||
cookies []*http.Cookie
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
form url.Values
|
||||
header http.Header
|
||||
cookies []*http.Cookie
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
exit_error bool
|
||||
server *GochanServer
|
||||
server *GochanServer
|
||||
)
|
||||
|
||||
type GochanServer struct{
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
type GochanServer struct {
|
||||
writer http.ResponseWriter
|
||||
request http.Request
|
||||
namespaces map[string]func(http.ResponseWriter, *http.Request, interface{})
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,8 @@ func (s GochanServer) AddNamespace(base_path string, namespace_function func(htt
|
|||
func (s GochanServer) getFileData(writer http.ResponseWriter, url string) ([]byte, bool) {
|
||||
var file_bytes []byte
|
||||
filepath := path.Join(config.DocumentRoot, url)
|
||||
results,err := os.Stat(filepath)
|
||||
results, err := os.Stat(filepath)
|
||||
if err != nil {
|
||||
fmt.Println("404 at ", filepath)
|
||||
// the requested path isn't a file or directory, 404
|
||||
return file_bytes, false
|
||||
} else {
|
||||
|
@ -50,12 +49,12 @@ func (s GochanServer) getFileData(writer http.ResponseWriter, url string) ([]byt
|
|||
|
||||
//check to see if one of the specified index pages exists
|
||||
for i := 0; i < len(config.FirstPage); i++ {
|
||||
newpath = path.Join(filepath,config.FirstPage[i])
|
||||
_,err := os.Stat(newpath)
|
||||
newpath = path.Join(filepath, config.FirstPage[i])
|
||||
_, err := os.Stat(newpath)
|
||||
if err == nil {
|
||||
// serve the index page
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
file_bytes,err = ioutil.ReadFile(newpath)
|
||||
file_bytes, err = ioutil.ReadFile(newpath)
|
||||
return file_bytes, true
|
||||
found_index = true
|
||||
break
|
||||
|
@ -71,27 +70,26 @@ func (s GochanServer) getFileData(writer http.ResponseWriter, url string) ([]byt
|
|||
file_bytes, err = ioutil.ReadFile(filepath)
|
||||
extension := getFileExtension(url)
|
||||
switch {
|
||||
case extension == "png":
|
||||
writer.Header().Add("Content-Type", "image/png")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "gif":
|
||||
writer.Header().Add("Content-Type", "image/gif")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "jpg":
|
||||
writer.Header().Add("Content-Type", "image/jpeg")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "css":
|
||||
writer.Header().Add("Content-Type", "text/css")
|
||||
writer.Header().Add("Cache-Control", "max-age=43200")
|
||||
case extension == "js":
|
||||
writer.Header().Add("Content-Type", "text/javascript")
|
||||
writer.Header().Add("Cache-Control", "max-age=43200")
|
||||
case extension == "png":
|
||||
writer.Header().Add("Content-Type", "image/png")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "gif":
|
||||
writer.Header().Add("Content-Type", "image/gif")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "jpg":
|
||||
writer.Header().Add("Content-Type", "image/jpeg")
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
case extension == "css":
|
||||
writer.Header().Add("Content-Type", "text/css")
|
||||
writer.Header().Add("Cache-Control", "max-age=43200")
|
||||
case extension == "js":
|
||||
writer.Header().Add("Content-Type", "text/javascript")
|
||||
writer.Header().Add("Cache-Control", "max-age=43200")
|
||||
}
|
||||
if extension == "html" || extension == "htm" {
|
||||
if extension == "html" || extension == "htm" {
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
}
|
||||
//http.ServeFile(writer, request, filepath)
|
||||
access_log.Print("Success: 200 from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
access_log.Print("Success: 200 from " + getRealIP(&request) + " @ " + request.RequestURI)
|
||||
return file_bytes, true
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +97,7 @@ func (s GochanServer) getFileData(writer http.ResponseWriter, url string) ([]byt
|
|||
}
|
||||
|
||||
func (s GochanServer) Redirect(location string) {
|
||||
http.Redirect(writer,&request,location,http.StatusFound)
|
||||
http.Redirect(writer, &request, location, http.StatusFound)
|
||||
}
|
||||
|
||||
func (s GochanServer) serve404(writer http.ResponseWriter, request *http.Request) {
|
||||
|
@ -109,13 +107,13 @@ func (s GochanServer) serve404(writer http.ResponseWriter, request *http.Request
|
|||
} else {
|
||||
writer.Write(error_page)
|
||||
}
|
||||
error_log.Print("Error: 404 Not Found from " + request.RemoteAddr + " @ " + request.RequestURI)
|
||||
error_log.Print("Error: 404 Not Found from " + getRealIP(request) + " @ " + request.RequestURI)
|
||||
}
|
||||
|
||||
func (s GochanServer) ServeErrorPage(writer http.ResponseWriter, err string) {
|
||||
error_page_bytes,_ := ioutil.ReadFile("templates/error.html")
|
||||
error_page_bytes, _ := ioutil.ReadFile("templates/error.html")
|
||||
error_page := string(error_page_bytes)
|
||||
error_page = strings.Replace(error_page,"{ERRORTEXT}", err,-1)
|
||||
error_page = strings.Replace(error_page, "{ERRORTEXT}", err, -1)
|
||||
writer.Write([]byte(error_page))
|
||||
exit_error = true
|
||||
}
|
||||
|
@ -123,12 +121,12 @@ func (s GochanServer) ServeErrorPage(writer http.ResponseWriter, err string) {
|
|||
func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
for name, namespace_function := range s.namespaces {
|
||||
//if len(request.URL)
|
||||
if request.URL.Path == "/" + name {
|
||||
if request.URL.Path == "/"+name {
|
||||
namespace_function(writer, request, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
fb,found := s.getFileData(writer, request.URL.Path)
|
||||
fb, found := s.getFileData(writer, request.URL.Path)
|
||||
writer.Header().Add("Cache-Control", "max-age=86400")
|
||||
if !found {
|
||||
s.serve404(writer, request)
|
||||
|
@ -138,9 +136,9 @@ func (s GochanServer) ServeHTTP(writer http.ResponseWriter, request *http.Reques
|
|||
}
|
||||
|
||||
func initServer() {
|
||||
listener,err := net.Listen("tcp", config.Domain+":"+strconv.Itoa(config.Port))
|
||||
if(err != nil) {
|
||||
fmt.Printf("Failed listening on "+config.Domain+":%d, see log for details",config.Port)
|
||||
listener, err := net.Listen("tcp", config.Domain+":"+strconv.Itoa(config.Port))
|
||||
if err != nil {
|
||||
fmt.Printf("Failed listening on "+config.Domain+":%d, see log for details", config.Port)
|
||||
error_log.Fatal(err.Error())
|
||||
}
|
||||
server = new(GochanServer)
|
||||
|
@ -155,22 +153,23 @@ func initServer() {
|
|||
server.AddNamespace("manage", callManageFunction)
|
||||
server.AddNamespace("post", makePost)
|
||||
server.AddNamespace("util", utilHandler)
|
||||
// eventually plugins will be able to register new namespaces. Or they will be restricted to something like /plugin
|
||||
if config.UseFastCGI {
|
||||
fcgi.Serve(listener,server)
|
||||
fcgi.Serve(listener, server)
|
||||
} else {
|
||||
http.Serve(listener, server)
|
||||
}
|
||||
}
|
||||
|
||||
func getRealIP(request *http.Request) (ip string) {
|
||||
func getRealIP(r *http.Request) (ip string) {
|
||||
// HTTP_CF_CONNECTING_IP > X-Forwarded-For > RemoteAddr
|
||||
if request.Header.Get("HTTP_CF_CONNECTING_IP") != "" {
|
||||
ip = request.Header.Get("HTTP_CF_CONNECTING_IP")
|
||||
if r.Header.Get("HTTP_CF_CONNECTING_IP") != "" {
|
||||
ip = r.Header.Get("HTTP_CF_CONNECTING_IP")
|
||||
} else {
|
||||
if request.Header.Get("X-Forwarded-For") != "" {
|
||||
ip = request.Header.Get("X-Forwarded-For")
|
||||
if r.Header.Get("X-Forwarded-For") != "" {
|
||||
ip = r.Header.Get("X-Forwarded-For")
|
||||
} else {
|
||||
ip = request.RemoteAddr
|
||||
ip = r.RemoteAddr
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -178,7 +177,7 @@ func getRealIP(request *http.Request) (ip string) {
|
|||
|
||||
func validReferrer(request http.Request) (valid bool) {
|
||||
if request.Referer() == "" || request.Referer()[7:len(config.SiteDomain)+7] != config.SiteDomain {
|
||||
// if request.Referer() == "" || request.Referer()[7:len(config.Domain)+7] != config.Domain {
|
||||
// if request.Referer() == "" || request.Referer()[7:len(config.Domain)+7] != config.Domain {
|
||||
valid = false
|
||||
} else {
|
||||
valid = true
|
||||
|
@ -186,19 +185,20 @@ func validReferrer(request http.Request) (valid bool) {
|
|||
return
|
||||
}
|
||||
|
||||
// register /util handler
|
||||
func utilHandler(writer http.ResponseWriter, request *http.Request, data interface{}) {
|
||||
writer.Header().Add("Content-Type", "text/css")
|
||||
action := request.FormValue("action")
|
||||
board := request.FormValue("board")
|
||||
var err error
|
||||
if action == "" && request.PostFormValue("delete_btn") != "Delete" && request.PostFormValue("report_btn") != "Report" {
|
||||
http.Redirect(writer,request,path.Join(config.SiteWebfolder,"/"),http.StatusFound)
|
||||
http.Redirect(writer, request, path.Join(config.SiteWebfolder, "/"), http.StatusFound)
|
||||
return
|
||||
}
|
||||
var posts_arr []string
|
||||
for key,_ := range request.PostForm {
|
||||
if strings.Index(key,"check") == 0 {
|
||||
posts_arr = append(posts_arr,key[5:])
|
||||
for key, _ := range request.PostForm {
|
||||
if strings.Index(key, "check") == 0 {
|
||||
posts_arr = append(posts_arr, key[5:])
|
||||
}
|
||||
}
|
||||
if request.PostFormValue("delete_btn") == "Delete" {
|
||||
|
@ -207,12 +207,12 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
password := md5_sum(request.FormValue("password"))
|
||||
rank := getStaffRank()
|
||||
|
||||
if request.FormValue("password") == "" && rank == 0 {
|
||||
if request.FormValue("password") == "" && rank == 0 {
|
||||
server.ServeErrorPage(writer, "Password required for post deletion")
|
||||
return
|
||||
}
|
||||
|
||||
for _,post := range posts_arr {
|
||||
for _, post := range posts_arr {
|
||||
var parent_id int
|
||||
var filename string
|
||||
var filetype string
|
||||
|
@ -220,21 +220,21 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
var board_id int
|
||||
//post_int,err := strconv.Atoi(post)
|
||||
|
||||
err = db.QueryRow("SELECT `parentid`,`filename`,`password` FROM `" + config.DBprefix + "posts` WHERE `id` = " + post + " AND `deleted_timestamp` = '" + nil_timestamp + "'").Scan(&parent_id, &filename, &password_checksum)
|
||||
err = db.QueryRow("SELECT `parentid`,`filename`,`password` FROM `"+config.DBprefix+"posts` WHERE `id` = "+post+" AND `deleted_timestamp` = '"+nil_timestamp+"'").Scan(&parent_id, &filename, &password_checksum)
|
||||
if err == sql.ErrNoRows {
|
||||
//the post has already been deleted
|
||||
writer.Header().Add("refresh", "3;url=" + request.Referer())
|
||||
fmt.Fprintf(writer, "%s has already been deleted or is a post in a deleted thread.\n<br />",post)
|
||||
writer.Header().Add("refresh", "3;url="+request.Referer())
|
||||
fmt.Fprintf(writer, "%s has already been deleted or is a post in a deleted thread.\n<br />", post)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer,err.Error())
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT `id` FROM `" + config.DBprefix + "boards` WHERE `dir` = '" + board + "'").Scan(&board_id)
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer,err.Error())
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -245,62 +245,63 @@ func utilHandler(writer http.ResponseWriter, request *http.Request, data interfa
|
|||
|
||||
if file_only {
|
||||
if filename != "" {
|
||||
filetype = filename[strings.Index(filename,".")+1:]
|
||||
filename = filename[:strings.Index(filename,".")]
|
||||
err := os.Remove(path.Join(config.DocumentRoot,board,"/src/"+filename+"."+filetype))
|
||||
filetype = filename[strings.Index(filename, ".")+1:]
|
||||
filename = filename[:strings.Index(filename, ".")]
|
||||
err := os.Remove(path.Join(config.DocumentRoot, board, "/src/"+filename+"."+filetype))
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer,err.Error())
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
err = os.Remove(path.Join(config.DocumentRoot,board,"/thumb/"+filename+"t."+filetype))
|
||||
err = os.Remove(path.Join(config.DocumentRoot, board, "/thumb/"+filename+"t."+filetype))
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer,err.Error())
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
_,err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `filename` = 'deleted' WHERE `id` = " + post)
|
||||
_, err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `filename` = 'deleted' WHERE `id` = " + post)
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
writer.Header().Add("refresh", "3;url=" + request.Referer())
|
||||
fmt.Fprintf(writer, "Attached image from %s deleted successfully<br />\n<meta http-equiv=\"refresh\" content=\"1;url=" + config.DocumentRoot + "/" + board + "/\">", post)
|
||||
writer.Header().Add("refresh", "3;url="+request.Referer())
|
||||
fmt.Fprintf(writer, "Attached image from %s deleted successfully<br />\n<meta http-equiv=\"refresh\" content=\"1;url="+config.DocumentRoot+"/"+board+"/\">", post)
|
||||
} else {
|
||||
|
||||
// delete the post
|
||||
_,err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `id` = " + post)
|
||||
_, err = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `id` = " + post)
|
||||
if parent_id == 0 {
|
||||
err = os.Remove(path.Join(config.DocumentRoot, board, "/res/" + post + ".html"))
|
||||
err = os.Remove(path.Join(config.DocumentRoot, board, "/res/"+post+".html"))
|
||||
} else {
|
||||
err = buildThread(parent_id,board_id)
|
||||
_board, _ := getBoardArr("`id` = " + strconv.Itoa(board_id))
|
||||
buildBoardPages(&_board[0])
|
||||
}
|
||||
|
||||
// if the deleted post is actually a thread, delete its posts
|
||||
_,_ = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `parentid` = " + post)
|
||||
_, _ = db.Exec("UPDATE `" + config.DBprefix + "posts` SET `deleted_timestamp` = '" + getSQLDateTime() + "' WHERE `parentid` = " + post)
|
||||
if err != nil {
|
||||
server.ServeErrorPage(writer,err.Error())
|
||||
server.ServeErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// delete the
|
||||
// delete the
|
||||
var deleted_filename string
|
||||
err = db.QueryRow("SELECT `filename` FROM `" + config.DBprefix + "posts` WHERE `id` = " + post + " AND `filename` != ''").Scan(&deleted_filename)
|
||||
if err == nil {
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/src/", deleted_filename))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "t.",-1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "c.",-1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "t.", -1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "c.", -1)))
|
||||
}
|
||||
|
||||
err = db.QueryRow("SELECT `filename` FROM `" + config.DBprefix + "posts` WHERE `parentid` = " + post + " AND `filename` != ''").Scan(&deleted_filename)
|
||||
if err == nil {
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/src/", deleted_filename))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "t.",-1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "c.",-1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "t.", -1)))
|
||||
os.Remove(path.Join(config.DocumentRoot, board, "/thumb/", strings.Replace(deleted_filename, ".", "c.", -1)))
|
||||
}
|
||||
|
||||
buildBoardPage(board_id, getBoardArr(""), getSectionArr(""))
|
||||
buildBoards(false, board_id)
|
||||
|
||||
writer.Header().Add("refresh", "3;url=" + request.Referer())
|
||||
writer.Header().Add("refresh", "3;url="+request.Referer())
|
||||
fmt.Fprintf(writer, "%s deleted successfully\n<br />", post)
|
||||
}
|
||||
}
|
||||
|
|
0
src/sql.go
Normal file → Executable file
0
src/sql.go
Normal file → Executable file
182
src/template.go
Normal file → Executable file
182
src/template.go
Normal file → Executable file
|
@ -13,20 +13,16 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
|
||||
|
||||
type FooterData struct {
|
||||
Version float32
|
||||
Version float32
|
||||
GeneratedTime float32
|
||||
}
|
||||
|
||||
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"add": func(a,b int) int {
|
||||
"add": func(a, b int) int {
|
||||
return a + b
|
||||
},
|
||||
"subtract": func(a,b int) int {
|
||||
"subtract": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"len": func(arr []interface{}) int {
|
||||
|
@ -47,6 +43,9 @@ var funcMap = template.FuncMap{
|
|||
"lt": func(a int, b int) bool {
|
||||
return a < b
|
||||
},
|
||||
"makeLoop": func(n int) []struct{} {
|
||||
return make([]struct{}, n)
|
||||
},
|
||||
"stringAppend": func(a, b string) string {
|
||||
return a + b
|
||||
},
|
||||
|
@ -58,11 +57,11 @@ var funcMap = template.FuncMap{
|
|||
},
|
||||
"truncateMessage": func(msg string, limit int, max_lines int) string {
|
||||
var truncated bool
|
||||
split := strings.SplitN(msg,"<br />",-1)
|
||||
split := strings.SplitN(msg, "<br />", -1)
|
||||
|
||||
if len(split) > max_lines {
|
||||
split = split[:max_lines]
|
||||
msg = strings.Join(split,"<br />")
|
||||
msg = strings.Join(split, "<br />")
|
||||
truncated = true
|
||||
}
|
||||
|
||||
|
@ -93,11 +92,14 @@ var funcMap = template.FuncMap{
|
|||
"isStyleNotDefault_img": func(style string) bool {
|
||||
return style != config.DefaultStyle_img
|
||||
},
|
||||
"getInterface":func(in []interface{}, index int) interface{} {
|
||||
"getElement": func(in []interface{}, element int) interface{} {
|
||||
return in[element]
|
||||
},
|
||||
"getInterface": func(in []interface{}, index int) interface{} {
|
||||
var nope interface{}
|
||||
if len(in) == 0 {
|
||||
return nope
|
||||
} else if len(in) < index + 1 {
|
||||
} else if len(in) < index+1 {
|
||||
return nope
|
||||
}
|
||||
return in[index]
|
||||
|
@ -118,22 +120,22 @@ var funcMap = template.FuncMap{
|
|||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
if name[len(name) - 3:] == "gif" || name[len(name) - 3:] == "gif" {
|
||||
name = name[:len(name) - 3] + "jpg"
|
||||
if name[len(name)-3:] == "gif" || name[len(name)-3:] == "gif" {
|
||||
name = name[:len(name)-3] + "jpg"
|
||||
}
|
||||
ext_begin := strings.LastIndex(name, ".")
|
||||
new_name := name[:ext_begin] + "t." + getFiletype(name)
|
||||
new_name := name[:ext_begin] + "t." + getFileExtension(name)
|
||||
fmt.Println(new_name)
|
||||
return new_name
|
||||
},
|
||||
"formatFilesize": func(size_int int) string {
|
||||
size := float32(size_int)
|
||||
if(size < 1000) {
|
||||
if size < 1000 {
|
||||
return fmt.Sprintf("%fB", size)
|
||||
} else if(size <= 100000) {
|
||||
} else if size <= 100000 {
|
||||
//size = size * 0.2
|
||||
return fmt.Sprintf("%0.1f KB", size/1024)
|
||||
} else if(size <= 100000000) {
|
||||
} else if size <= 100000000 {
|
||||
//size = size * 0.2
|
||||
return fmt.Sprintf("%0.2f MB", size/1024/1024)
|
||||
}
|
||||
|
@ -145,7 +147,7 @@ var funcMap = template.FuncMap{
|
|||
filetype = "jpg"
|
||||
}
|
||||
index := strings.LastIndex(img, ".")
|
||||
return img[0:index]+"t."+filetype
|
||||
return img[0:index] + "t." + filetype
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -153,142 +155,142 @@ var (
|
|||
footer_data = FooterData{version, float32(0)}
|
||||
|
||||
banpage_tmpl_str string
|
||||
banpage_tmpl *template.Template
|
||||
banpage_tmpl *template.Template
|
||||
|
||||
global_footer_tmpl_str string
|
||||
global_footer_tmpl *template.Template
|
||||
|
||||
global_footer_tmpl *template.Template
|
||||
|
||||
global_header_tmpl_str string
|
||||
global_header_tmpl *template.Template
|
||||
global_header_tmpl *template.Template
|
||||
|
||||
img_boardpage_tmpl_str string
|
||||
img_boardpage_tmpl *template.Template
|
||||
|
||||
img_thread_tmpl_str string
|
||||
img_thread_tmpl *template.Template
|
||||
|
||||
img_boardpage_tmpl *template.Template
|
||||
|
||||
img_threadpage_tmpl_str string
|
||||
img_threadpage_tmpl *template.Template
|
||||
|
||||
manage_header_tmpl_str string
|
||||
manage_header_tmpl *template.Template
|
||||
manage_header_tmpl *template.Template
|
||||
|
||||
front_page_tmpl_str string
|
||||
front_page_tmpl *template.Template
|
||||
front_page_tmpl *template.Template
|
||||
|
||||
template_buffer bytes.Buffer
|
||||
starting_time int
|
||||
starting_time int
|
||||
)
|
||||
|
||||
func initTemplates() {
|
||||
banpage_tmpl_bytes,tmpl_err := ioutil.ReadFile(config.TemplateDir+"/banpage.html")
|
||||
resetBoardSectionArrays()
|
||||
banpage_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/banpage.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/banpage.html\": " + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
banpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
|
||||
"{{$ban := getInterface .Data 1}}" +
|
||||
string(banpage_tmpl_bytes)
|
||||
banpage_tmpl,tmpl_err = template.New("banpage_tmpl").Funcs(funcMap).Parse(string(banpage_tmpl_str))
|
||||
"{{$ban := getInterface .Data 1}}" +
|
||||
string(banpage_tmpl_bytes)
|
||||
banpage_tmpl, tmpl_err = template.New("banpage_tmpl").Funcs(funcMap).Parse(string(banpage_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/banpage.html\": " + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/banpage.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
global_footer_tmpl_bytes,tmpl_err := ioutil.ReadFile(config.TemplateDir+"/global_footer.html")
|
||||
global_footer_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_footer.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_footer.html\": " + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
global_footer_tmpl_str = string(global_footer_tmpl_bytes)
|
||||
global_footer_tmpl,tmpl_err = template.New("global_footer_tmpl").Funcs(funcMap).Parse(string(global_footer_tmpl_str))
|
||||
global_footer_tmpl, tmpl_err = template.New("global_footer_tmpl").Funcs(funcMap).Parse(string(global_footer_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_footer.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
global_header_tmpl_bytes,tmpl_err := ioutil.ReadFile(config.TemplateDir+"/global_header.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_header.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
global_header_tmpl_str = string(global_header_tmpl_bytes)
|
||||
global_header_tmpl,tmpl_err = template.New("global_header_tmpl").Funcs(funcMap).Parse(string(global_header_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/global_header.html\": " + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_footer.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
img_boardpage_tmpl_bytes,_ := ioutil.ReadFile(path.Join(config.TemplateDir,"img_boardpage.html"))
|
||||
global_header_tmpl_bytes, tmpl_err := ioutil.ReadFile(config.TemplateDir + "/global_header.html")
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
global_header_tmpl_str = string(global_header_tmpl_bytes)
|
||||
global_header_tmpl, tmpl_err = template.New("global_header_tmpl").Funcs(funcMap).Parse(string(global_header_tmpl_str))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/global_header.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
img_boardpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_boardpage.html"))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
img_boardpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
|
||||
"{{$board_arr := getInterface .Data 1}}" +
|
||||
"{{$section_arr := getInterface .Data 2}}" +
|
||||
"{{$thread_arr := getInterface .Data 3}}" +
|
||||
"{{$board_info := getInterface .Data 4}}" +
|
||||
"{{$board := getInterface $board_info.Data 0}}" +
|
||||
string(img_boardpage_tmpl_bytes)
|
||||
img_boardpage_tmpl,tmpl_err = template.New("img_boardpage_tmpl").Funcs(funcMap).Parse(img_boardpage_tmpl_str)
|
||||
"{{$board_arr := (getInterface .Data 1).Data}}" +
|
||||
"{{$section_arr := (getInterface .Data 2).Data}}" +
|
||||
"{{$thread_arr := (getInterface .Data 3).Data}}" +
|
||||
"{{$board_info := (getInterface .Data 4).Data}}" +
|
||||
"{{$board := getInterface $board_info 0}}" +
|
||||
string(img_boardpage_tmpl_bytes)
|
||||
img_boardpage_tmpl, tmpl_err = template.New("img_boardpage_tmpl").Funcs(funcMap).Parse(img_boardpage_tmpl_str)
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/img_boardpage.html: \"" + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_boardpage.html: \"" + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
img_thread_tmpl_bytes,_ := ioutil.ReadFile(path.Join(config.TemplateDir,"img_thread.html"))
|
||||
img_threadpage_tmpl_bytes, _ := ioutil.ReadFile(path.Join(config.TemplateDir, "img_threadpage.html"))
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/img_thread.html\": " + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
img_thread_tmpl_str = "{{$config := getInterface .Data 0}}" +
|
||||
"{{$post_arr := getInterface .Data 1}}" +
|
||||
"{{$board_arr := getInterface .Data 2}}" +
|
||||
"{{$section_arr := getInterface .Data 3}}" +
|
||||
"{{$op := getInterface $post_arr 0}}" +
|
||||
"{{$boardid := subtract $op.BoardID 1}}" +
|
||||
"{{$board := getInterface $board_arr.Data $boardid}}" +
|
||||
string(img_thread_tmpl_bytes)
|
||||
img_thread_tmpl,tmpl_err = template.New("img_thread_tmpl").Funcs(funcMap).Parse(img_thread_tmpl_str)
|
||||
img_threadpage_tmpl_str = "{{$config := getInterface .Data 0}}" +
|
||||
"{{$board_arr := (getInterface .Data 1).Data}}" +
|
||||
"{{$section_arr := (getInterface .Data 2).Data}}" +
|
||||
"{{$post_arr := (getInterface .Data 3).Data}}" +
|
||||
"{{$op := getElement $post_arr 0}}" +
|
||||
"{{$board := getElement $board_arr (subtract $op.BoardID 1)}}" +
|
||||
string(img_threadpage_tmpl_bytes)
|
||||
img_threadpage_tmpl, tmpl_err = template.New("img_threadpage_tmpl").Funcs(funcMap).Parse(img_threadpage_tmpl_str)
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/img_thread.html: \"" + tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/img_threadpage.html: \"" + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
manage_header_tmpl_bytes,err := ioutil.ReadFile(config.TemplateDir+"/manage_header.html")
|
||||
manage_header_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/manage_header.html")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
manage_header_tmpl_str = string(manage_header_tmpl_bytes)
|
||||
manage_header_tmpl,tmpl_err = template.New("manage_header_tmpl").Funcs(funcMap).Parse(manage_header_tmpl_str)
|
||||
manage_header_tmpl, tmpl_err = template.New("manage_header_tmpl").Funcs(funcMap).Parse(manage_header_tmpl_str)
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/manage_header.html\": "+tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/manage_header.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
front_page_tmpl_bytes,err := ioutil.ReadFile(config.TemplateDir+"/front.html")
|
||||
front_page_tmpl_bytes, err := ioutil.ReadFile(config.TemplateDir + "/front.html")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
front_page_tmpl_str = "{{$config := getInterface .Data 0}}" +
|
||||
"{{$page_arr := getInterface .Data 1}}" +
|
||||
"{{$board_arr := getInterface .Data 2}}" +
|
||||
"{{$section_arr := getInterface .Data 3}}" +
|
||||
"{{$recent_posts_arr := getInterface .Data 4}}" +
|
||||
string(front_page_tmpl_bytes)
|
||||
front_page_tmpl,tmpl_err = template.New("front_page_tmpl").Funcs(funcMap).Parse(front_page_tmpl_str)
|
||||
front_page_tmpl_str = "{{$config := getInterface .Data 0}}\n" +
|
||||
"{{$page_arr := getInterface .Data 1}}\n" +
|
||||
"{{$board_arr := getInterface .Data 2}}\n" +
|
||||
"{{$section_arr := getInterface .Data 3}}\n" +
|
||||
"{{$recent_posts_arr := getInterface .Data 4}}\n" +
|
||||
string(front_page_tmpl_bytes)
|
||||
front_page_tmpl, tmpl_err = template.New("front_page_tmpl").Funcs(funcMap).Parse(front_page_tmpl_str)
|
||||
if tmpl_err != nil {
|
||||
fmt.Println("Failed loading template \""+config.TemplateDir+"/front.html\": "+tmpl_err.Error())
|
||||
fmt.Println("Failed loading template \"" + config.TemplateDir + "/front.html\": " + tmpl_err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func getTemplateAsString(templ template.Template) (string,error) {
|
||||
func getTemplateAsString(templ template.Template) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
err := templ.Execute(&buf,config)
|
||||
err := templ.Execute(&buf, config)
|
||||
if err == nil {
|
||||
return buf.String(),nil
|
||||
return buf.String(), nil
|
||||
}
|
||||
return "",err
|
||||
return "", err
|
||||
}
|
||||
|
||||
func getStyleLinks(w http.ResponseWriter, stylesheet string) {
|
||||
|
@ -297,7 +299,7 @@ func getStyleLinks(w http.ResponseWriter, stylesheet string) {
|
|||
styles_map[i] = config.Styles_img[i]
|
||||
}
|
||||
|
||||
err := manage_header_tmpl.Execute(w,config)
|
||||
err := manage_header_tmpl.Execute(w, config)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
|
|
600
src/types.go
600
src/types.go
File diff suppressed because it is too large
Load diff
79
src/util.go
79
src/util.go
|
@ -5,11 +5,14 @@ import (
|
|||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
//"golang.org/x/crypto/bcrypt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -69,23 +72,23 @@ func byteByByteReplace(input, from, to string) string {
|
|||
return input
|
||||
}
|
||||
|
||||
func walkfolder(path string, f os.FileInfo, err error) error {
|
||||
func deleteMatchingFiles(root, match string) (int, error) {
|
||||
files_deleted := 0
|
||||
files, err := ioutil.ReadDir(root)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
if !f.IsDir() {
|
||||
return os.Remove(path)
|
||||
} else {
|
||||
return nil
|
||||
for _, f := range files {
|
||||
match, _ := regexp.MatchString(match, f.Name())
|
||||
if match {
|
||||
os.Remove(filepath.Join(root, f.Name()))
|
||||
files_deleted++
|
||||
}
|
||||
}
|
||||
return files_deleted, err
|
||||
}
|
||||
|
||||
func deleteFolderContents(root string) error {
|
||||
err := filepath.Walk(root, walkfolder)
|
||||
return err
|
||||
}
|
||||
|
||||
func getBoardArr(where string) (boards []BoardsTable) {
|
||||
func getBoardArr(where string) (boards []BoardsTable, err error) {
|
||||
if where == "" {
|
||||
where = "1"
|
||||
}
|
||||
|
@ -136,8 +139,11 @@ func getBoardArr(where string) (boards []BoardsTable) {
|
|||
return
|
||||
}
|
||||
|
||||
func getPostArr(sql string) (posts []interface{}, err error) {
|
||||
rows, err := db.Query(sql)
|
||||
func getPostArr(where string) (posts []interface{}, err error) {
|
||||
if where == "" {
|
||||
where = "1"
|
||||
}
|
||||
rows, err := db.Query("SELECT * FROM `" + config.DBprefix + "posts` WHERE " + where)
|
||||
if err != nil {
|
||||
error_log.Print(err.Error())
|
||||
return
|
||||
|
@ -151,10 +157,10 @@ func getPostArr(sql string) (posts []interface{}, err error) {
|
|||
}
|
||||
posts = append(posts, post)
|
||||
}
|
||||
return posts, err
|
||||
return
|
||||
}
|
||||
|
||||
func getSectionArr(where string) (sections []interface{}) {
|
||||
func getSectionArr(where string) (sections []interface{}, err error) {
|
||||
if where == "" {
|
||||
where = "1"
|
||||
}
|
||||
|
@ -231,6 +237,47 @@ func humanReadableTime(t time.Time) string {
|
|||
return t.Format(config.DateTimeFormat)
|
||||
}
|
||||
|
||||
func paginate(interface_length int, interf []interface{}) [][]interface{} {
|
||||
// interface_length = the max number of interfaces per super-interface
|
||||
// (for example, threads per page)
|
||||
// interf = the raw interface to be split up
|
||||
// paginated_interfaces = the finished interface array
|
||||
// num_arrays = the current number of arrays (before remainder overflow)
|
||||
// interfaces_remaining = if greater than 0, these are the remaining interfaces
|
||||
// that will be added to the super-interface
|
||||
|
||||
var paginated_interfaces [][]interface{}
|
||||
num_arrays := len(interf) / interface_length
|
||||
interfaces_remaining := len(interf) % interface_length
|
||||
paginated_interfaces = append(paginated_interfaces, interf)
|
||||
current_interface := 0
|
||||
for l := 0; l < num_arrays; l++ {
|
||||
paginated_interfaces = append(paginated_interfaces,
|
||||
interf[current_interface:current_interface+interface_length])
|
||||
current_interface += interface_length
|
||||
}
|
||||
if interfaces_remaining > 0 {
|
||||
paginated_interfaces = append(paginated_interfaces, interf[len(interf)-interfaces_remaining:])
|
||||
}
|
||||
fmt.Println(len(paginated_interfaces[0]))
|
||||
return paginated_interfaces
|
||||
}
|
||||
|
||||
func resetBoardSectionArrays() {
|
||||
// run when the board list needs to be changed (board/section is added, deleted, etc)
|
||||
all_boards = nil
|
||||
all_sections = nil
|
||||
|
||||
all_boards_a, _ := getBoardArr("")
|
||||
for _, b := range all_boards_a {
|
||||
all_boards = append(all_boards, b)
|
||||
}
|
||||
all_sections_a, _ := getSectionArr("")
|
||||
for _, b := range all_sections_a {
|
||||
all_boards = append(all_sections, b)
|
||||
}
|
||||
}
|
||||
|
||||
func searchStrings(item string, arr []string, permissive bool) int {
|
||||
var length = len(arr)
|
||||
for i := 0; i < length; i++ {
|
||||
|
|
4
templates/front.html
Normal file → Executable file
4
templates/front.html
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{$config.SiteName}}</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/msgpack.js"></script>
|
||||
<script type="text/javascript">
|
||||
var styles = [{{range $ii, $style := $config.Styles_img}}{{if gt $ii 0}}, {{end}}"{{$style}}"{{end}}];
|
||||
|
@ -124,7 +124,7 @@
|
|||
</div>
|
||||
<div id="footer">
|
||||
<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 Gochan {{$config.Version}}<br />
|
||||
Powered by <a href="http://github.com/eggbertx/gochan">Gochan {{$config.Version}}</a><br />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
50
templates/img_boardpage.html
Normal file → Executable file
50
templates/img_boardpage.html
Normal file → Executable file
|
@ -3,9 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{$board.Title}}</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.10.2.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/javascript/msgpack.js"></script>
|
||||
<script type="text/javascript" src="/javascript/jquery-1.10.2.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}}";
|
||||
|
@ -19,8 +17,8 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
{{range $i, $board := $board_arr.Data}}
|
||||
<a href="/{{$board.Dir}}/" class="topbar-item">/{{$board.Dir}}/</a>
|
||||
{{range $i, $boardlink := $board_arr}}
|
||||
<a href="/{{$boardlink.Dir}}/" class="topbar-item">/{{$boardlink.Dir}}/</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="top-pane">
|
||||
|
@ -37,12 +35,12 @@
|
|||
<input type="hidden" name="threadid" value="0" />
|
||||
<input type="hidden" name="boardid" value="{{$board.ID}}" />
|
||||
<table id="postbox-static">
|
||||
<tr><td class="postblock">Name</td><td><input type="text" id="postname" name="postname" maxlength="75" size="28" {{/* value="Name" onFocus="if(this.value=='Name') {this,value= ''}" onBlur="if(this.value == '') {this.value = 'Name'}"*/}}/></td></tr>
|
||||
<tr><td class="postblock">Email</td><td><input type="text" id="postemail" name="postemail" maxlength="75" size="28" /></td></tr>
|
||||
<tr><td class="postblock">Subject</td><td><input type="text" name="postsubject" maxlength="75" size="35" /><input type="submit" value="Post"/></td></tr>
|
||||
<tr><td class="postblock">Message</td><td><textarea rows="4" cols="48" name="postmsg"></textarea></td></tr>
|
||||
<tr><td class="postblock">File</td><td><input name="imagefile" type="file"><input type="checkbox" id="spoiler" name="spoiler"/><label for="spoiler">Spoiler</label></td></tr>
|
||||
<tr><td class="postblock">Password</td><td><input type="password" id="postpassword" name="postpassword" size="14" /> (for post/file deletion)</td></tr>
|
||||
<tr><th class="postblock">Name</th><td><input type="text" id="postname" name="postname" maxlength="75" size="28" {{/* value="Name" onFocus="if(this.value=='Name') {this,value= ''}" onBlur="if(this.value == '') {this.value = 'Name'}"*/}}/></td></tr>
|
||||
<tr><th class="postblock">Email</th><td><input type="text" id="postemail" name="postemail" maxlength="75" size="28" /></td></tr>
|
||||
<tr><th class="postblock">Subject</th><td><input type="text" name="postsubject" maxlength="75" size="35" /><input type="submit" value="Post"/></td></tr>
|
||||
<tr><th class="postblock">Message</th><td><textarea rows="4" cols="48" name="postmsg"></textarea></td></tr>
|
||||
<tr><th class="postblock">File</th><td><input name="imagefile" type="file"><input type="checkbox" id="spoiler" name="spoiler"/><label for="spoiler">Spoiler</label></td></tr>
|
||||
<tr><th class="postblock">Password</th><td><input type="password" id="postpassword" name="postpassword" size="14" /> (for post/file deletion)</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
|
@ -50,7 +48,7 @@
|
|||
<hr />
|
||||
<div id="content">
|
||||
<form action="/util" method="POST" id="main-form">
|
||||
{{range $t, $thread := $thread_arr.Data}}
|
||||
{{range $t, $thread := $thread_arr}}
|
||||
{{$op := $thread.OP}}
|
||||
<div class="thread">
|
||||
<div class="op-post" id="op{{$op.ID}}">
|
||||
|
@ -93,13 +91,6 @@
|
|||
</div>
|
||||
<hr />
|
||||
{{end}}
|
||||
|
||||
<div id="left-bottom-content">
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $board := $board_arr.Data}} {{if gt $i 0}}/{{end}} <a href="/{{$board.Dir}}/">{{$board.Dir}}</a> {{end}}]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="right-bottom-content">
|
||||
<div id="report-delbox">
|
||||
<input type="hidden" name="board" value="{{$board.Dir}}" />
|
||||
|
@ -108,10 +99,29 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="left-bottom-content">
|
||||
<table id="pages">
|
||||
<tr><td>{{if gt $board.CurrentPage 1}}
|
||||
<form method="GET" action="{{$config.SiteWebfolder}}{{$board.Dir}}/{{subtract $board.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Previous" />
|
||||
</form>
|
||||
{{else}}Previous{{end}}</td>
|
||||
|
||||
<td>[<a href="{{$config.SiteWebfolder}}{{$board.Dir}}/">Index</a>]{{range $i,$_ := makeLoop $board.NumPages}} [{{if eq $i $board.CurrentPage}}<b>{{end}}<a href="{{$config.SiteWebfolder}}{{$board.Dir}}/{{add $i 1}}.html">{{add $i 1}}</a>{{if eq $i $board.CurrentPage}}</b>{{end}}]{{end}}</td>
|
||||
<td>{{if lt $board.CurrentPage $board.NumPages}}
|
||||
<form method="GET" action="{{$config.SiteWebfolder}}{{$board.Dir}}/{{add $board.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Next" />
|
||||
</form>
|
||||
{{else}}Next{{end}}</td></tr>
|
||||
</table>
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $boardlink := $board_arr}} {{if gt $i 0}}/{{end}} <a href="/{{$boardlink.Dir}}/">{{$boardlink.Dir}}</a> {{end}}]
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<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 Gochan {{$config.Version}}<br />
|
||||
Powered by <a href="http://github.com/eggbertx/gochan/">Gochan {{$config.Version}}</a><br />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
55
templates/img_thread.html → templates/img_threadpage.html
Normal file → Executable file
55
templates/img_thread.html → templates/img_threadpage.html
Normal file → Executable file
|
@ -3,8 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{$board.Title}}</title>
|
||||
<script type="text/javascript" src="/javascript/jquery/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/javascript/msgpack.js"></script>
|
||||
<script type="text/javascript" src="/javascript/jquery-1.10.2.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}}";
|
||||
|
@ -21,7 +20,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
{{range $i, $board := $board_arr.Data}}
|
||||
{{range $i, $board := $board_arr}}
|
||||
<a href="/{{$board.Dir}}/" class="topbar-item">/{{$board.Dir}}/</a>
|
||||
{{end}}
|
||||
</div>
|
||||
|
@ -49,14 +48,14 @@
|
|||
<div id="postbox-area">
|
||||
<form name="postform" action="/post" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="threadid" value="{{$op.ID}}" />
|
||||
<input type="hidden" name="boardid" value="{{$board.ID}}" />
|
||||
<input type="hidden" name="boardid" value="{{$op.BoardID}}" />
|
||||
<table id="postbox-static">
|
||||
<tr><td class="postblock">Name</td><td><input type="text" id="postname" name="postname" maxlength="75" size="28" {{/* value="Name" onFocus="if(this.value=='Name') {this,value= ''}" onBlur="if(this.value == '') {this.value = 'Name'}"*/}}/></td></tr>
|
||||
<tr><td class="postblock">Email</td><td><input type="text" id="postemail" name="postemail" maxlength="75" size="28" /></td></tr>
|
||||
<tr><td class="postblock">Subject</td><td><input type="text" name="postsubject" maxlength="75" size="35" /><input type="submit" value="Post"/></td></tr>
|
||||
<tr><td class="postblock">Message</td><td><textarea rows="4" cols="48" name="postmsg"></textarea></td></tr>
|
||||
<tr><td class="postblock">File</td><td><input name="imagefile" type="file"><input type="checkbox" id="spoiler" name="spoiler"/><label for="spoiler">Spoiler</label></td></tr>
|
||||
<tr><td class="postblock">Password</td><td><input type="password" id="postpassword" name="postpassword" size="14" /> (for post/file deletion)</td></tr>
|
||||
<tr><th class="postblock">Name</th><td><input type="text" id="postname" name="postname" maxlength="75" size="28" {{/* value="Name" onFocus="if(this.value=='Name') {this,value= ''}" onBlur="if(this.value == '') {this.value = 'Name'}"*/}}/></td></tr>
|
||||
<tr><th class="postblock">Email</th><td><input type="text" id="postemail" name="postemail" maxlength="75" size="28" /></td></tr>
|
||||
<tr><th class="postblock">Subject</th><td><input type="text" name="postsubject" maxlength="75" size="35" /><input type="submit" value="Post"/></td></tr>
|
||||
<tr><th class="postblock">Message</th><td><textarea rows="4" cols="48" name="postmsg"></textarea></td></tr>
|
||||
<tr><th class="postblock">File</th><td><input name="imagefile" type="file"><input type="checkbox" id="spoiler" name="spoiler"/><label for="spoiler">Spoiler</label></td></tr>
|
||||
<tr><th class="postblock">Password</th><td><input type="password" id="postpassword" name="postpassword" size="14" /> (for post/file deletion)</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -99,32 +98,36 @@
|
|||
{{end}}{{end}}
|
||||
</div>
|
||||
<hr />
|
||||
<div id="left-bottom-content">
|
||||
<table id="pages">
|
||||
<tr><td>Previous</td><td>[0] [<a href="{{$op.ID}}p1.html">1</a>]</td><td><input type="button" value="Next" onclick="window.location.href = '{{$op.ID}}p1.html'" /></td></tr>
|
||||
</table>
|
||||
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $board := $board_arr.Data}} {{if gt $i 0}}/{{end}} <a href="/{{$board.Dir}}/">{{$board.Dir}}</a> {{end}}]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="right-bottom-content">
|
||||
<span id="threadlinks-bottom">
|
||||
[<a href="{{$config.SiteWebfolder}}{{$board.Dir}}/board.html">Return</a>] [<a href="{{$op.ID}}-100.html">First 100 posts</a>] [<a href="{{$op.ID}}+50.html">Last 50 posts</a>]
|
||||
</span>
|
||||
|
||||
<div id="report-delbox">
|
||||
<input type="hidden" name="board" value="{{$board.Dir}}" />
|
||||
<label>[<input type="checkbox" name="fileonly"/>File only]</label> <input type="password" size="10" name="password" id="delete-password" /> <input type="submit" name="delete_btn" value="Delete" onclick="return confirm('Are you sure you want to delete these posts?')" /><br />
|
||||
Reason: <input type="text" size="10" name="reason" id="reason" /> <input type="submit" value="Report" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
<div id="left-bottom-content">
|
||||
<table id="pages">
|
||||
<tr><td>{{if gt $op.CurrentPage 1}}
|
||||
<form method="GET" action="{{$config.SiteWebfolder}}{{$board.Dir}}/res/{{$op.ID}}p{{subtract $op.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Previous" />
|
||||
</form>
|
||||
{{else}}Previous{{end}}</td>
|
||||
<td>[<a href="{{$config.SiteWebfolder}}{{$board.Dir}}/res/{{$op.ID}}.html">Index</a>]{{range $i,$_ := makeLoop $op.NumPages}} [{{if eq $i (subtract $op.CurrentPage 1)}}<b>{{end}}<a href="{{$config.SiteWebfolder}}{{$board.Dir}}/res/{{$op.ID}}p{{add $i 1}}.html">{{add $i 1}}</a>{{if eq $i (subtract $op.CurrentPage 1)}}</b>{{end}}]{{end}}</td>
|
||||
<td>{{if lt $op.CurrentPage $op.NumPages}}
|
||||
<form method="GET" action="{{$config.SiteWebfolder}}{{$board.Dir}}/res/{{$op.ID}}p{{add $op.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Next" />
|
||||
</form>
|
||||
{{else}}Next{{end}}</td></tr>
|
||||
</table>
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $boardlink := $board_arr}} {{if gt $i 0}}/{{end}} <a href="/{{$boardlink.Dir}}/">{{$boardlink.Dir}}</a> {{end}}]
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<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 Gochan {{$config.Version}}<br />
|
||||
Powered by <a href="http://github.com/eggbertx/gochan/">Gochan {{$config.Version}}</a><br />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue