mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 10:56:25 -07:00
Start making templates more readable
Also change most remaining underscore var names to camelCase
This commit is contained in:
parent
6a96420e3e
commit
267a5eeb6f
16 changed files with 446 additions and 465 deletions
117
src/building.go
117
src/building.go
|
@ -21,8 +21,8 @@ func buildFrontPage() string {
|
|||
var recentPostsArr []interface{}
|
||||
|
||||
os.Remove(path.Join(config.DocumentRoot, "index.html"))
|
||||
front_file, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(front_file)
|
||||
frontFile, err := os.OpenFile(path.Join(config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(frontFile)
|
||||
if err != nil {
|
||||
return handleError(1, "Failed opening front page for writing: "+err.Error()) + "<br />\n"
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func buildFrontPage() string {
|
|||
}
|
||||
}
|
||||
|
||||
if err = frontPageTmpl.Execute(front_file, map[string]interface{}{
|
||||
if err = frontPageTmpl.Execute(frontFile, map[string]interface{}{
|
||||
"config": config,
|
||||
"sections": allSections,
|
||||
"boards": allBoards,
|
||||
|
@ -119,27 +119,28 @@ func buildBoardPages(board *Board) (html string) {
|
|||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
start_time := benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), time.Now(), true)
|
||||
var current_page_file *os.File
|
||||
startTime := benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), time.Now(), true)
|
||||
var currentPageFile *os.File
|
||||
var threads []interface{}
|
||||
var thread_pages [][]interface{}
|
||||
var stickied_threads []interface{}
|
||||
var nonstickied_threads []interface{}
|
||||
var threadPages [][]interface{}
|
||||
var stickiedThreads []interface{}
|
||||
var nonStickiedThreads []interface{}
|
||||
|
||||
var opPosts []Post
|
||||
|
||||
// Get all top level posts for the board.
|
||||
op_posts, err := getPostArr(map[string]interface{}{
|
||||
if opPosts, err = getPostArr(map[string]interface{}{
|
||||
"boardid": board.ID,
|
||||
"parentid": 0,
|
||||
"deleted_timestamp": nilTimestamp,
|
||||
}, " ORDER BY bumped DESC")
|
||||
if err != nil {
|
||||
}, " ORDER BY bumped DESC"); err != nil {
|
||||
html += handleError(1, "Error getting OP posts for /%s/: %s", board.Dir, err.Error()) + "<br />\n"
|
||||
op_posts = nil
|
||||
opPosts = nil
|
||||
return
|
||||
}
|
||||
|
||||
// For each top level post, start building a Thread struct
|
||||
for _, op := range op_posts {
|
||||
for _, op := range opPosts {
|
||||
var thread Thread
|
||||
var postsInThread []Post
|
||||
|
||||
|
@ -201,43 +202,42 @@ func buildBoardPages(board *Board) (html string) {
|
|||
thread.BoardReplies = reversedPosts
|
||||
|
||||
// Count number of images on board page
|
||||
image_count := 0
|
||||
imageCount := 0
|
||||
for _, reply := range postsInThread {
|
||||
if reply.Filesize != 0 {
|
||||
image_count++
|
||||
imageCount++
|
||||
}
|
||||
}
|
||||
// Then calculate number of omitted images.
|
||||
thread.OmittedImages = thread.NumImages - image_count
|
||||
thread.OmittedImages = thread.NumImages - imageCount
|
||||
}
|
||||
|
||||
// Add thread struct to appropriate list
|
||||
if op.Stickied {
|
||||
stickied_threads = append(stickied_threads, thread)
|
||||
stickiedThreads = append(stickiedThreads, thread)
|
||||
} else {
|
||||
nonstickied_threads = append(nonstickied_threads, thread)
|
||||
nonStickiedThreads = append(nonStickiedThreads, thread)
|
||||
}
|
||||
}
|
||||
|
||||
num, _ := deleteMatchingFiles(path.Join(config.DocumentRoot, board.Dir), "\\d.html$")
|
||||
printf(2, "Number of files deleted: %d\n", num)
|
||||
// Order the threads, stickied threads first, then nonstickied threads.
|
||||
threads = append(stickied_threads, nonstickied_threads...)
|
||||
threads = append(stickiedThreads, nonStickiedThreads...)
|
||||
|
||||
// If there are no posts on the board
|
||||
if len(threads) == 0 {
|
||||
board.CurrentPage = 1
|
||||
// Open board.html for writing to the first page.
|
||||
board_page_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
boardPageFile, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "board.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
html += handleError(1,
|
||||
"Failed opening /%s/board.html: %s", board.Dir, err.Error()) + "<br />"
|
||||
html += handleError(1, "Failed opening /%s/board.html: %s", board.Dir, err.Error()) + "<br />"
|
||||
return
|
||||
}
|
||||
|
||||
// Render board page template to the file,
|
||||
// packaging the board/section list, threads, and board info
|
||||
if err = boardpageTmpl.Execute(board_page_file, map[string]interface{}{
|
||||
if err = boardpageTmpl.Execute(boardPageFile, map[string]interface{}{
|
||||
"config": config,
|
||||
"boards": allBoards,
|
||||
"sections": allSections,
|
||||
|
@ -249,42 +249,43 @@ func buildBoardPages(board *Board) (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), startTime, false)
|
||||
return
|
||||
} else {
|
||||
}
|
||||
|
||||
// Create the archive pages.
|
||||
thread_pages = paginate(config.ThreadsPerPage, threads)
|
||||
board.NumPages = len(thread_pages) - 1
|
||||
threadPages = paginate(config.ThreadsPerPage, threads)
|
||||
board.NumPages = len(threadPages) - 1
|
||||
|
||||
// Create array of page wrapper objects, and open the file.
|
||||
pagesArr := make([]map[string]interface{}, board.NumPages)
|
||||
|
||||
catalog_json_file, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(catalog_json_file)
|
||||
catalogJSONFile, err := os.OpenFile(path.Join(config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(catalogJSONFile)
|
||||
if err != nil {
|
||||
html += handleError(1, "Failed opening /"+board.Dir+"/catalog.json: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
currentBoardPage := board.CurrentPage
|
||||
for _, page_threads := range thread_pages {
|
||||
for _, pageThreads := range threadPages {
|
||||
board.CurrentPage++
|
||||
var current_page_filepath string
|
||||
var currentPageFilepath string
|
||||
pageFilename := strconv.Itoa(board.CurrentPage) + ".html"
|
||||
current_page_filepath = path.Join(config.DocumentRoot, board.Dir, pageFilename)
|
||||
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(current_page_file)
|
||||
currentPageFilepath = path.Join(config.DocumentRoot, board.Dir, pageFilename)
|
||||
currentPageFile, err = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
defer closeHandle(currentPageFile)
|
||||
if err != nil {
|
||||
html += handleError(1, "Failed opening board page: "+err.Error()) + "<br />"
|
||||
continue
|
||||
}
|
||||
|
||||
// Render the boardpage template, don't forget config
|
||||
if err = boardpageTmpl.Execute(current_page_file, map[string]interface{}{
|
||||
if err = boardpageTmpl.Execute(currentPageFile, map[string]interface{}{
|
||||
"config": config,
|
||||
"boards": allBoards,
|
||||
"sections": allSections,
|
||||
"threads": page_threads,
|
||||
"threads": pageThreads,
|
||||
"board": board,
|
||||
"posts": []interface{}{
|
||||
Post{BoardID: board.ID},
|
||||
|
@ -297,7 +298,7 @@ func buildBoardPages(board *Board) (html string) {
|
|||
if board.CurrentPage == 1 {
|
||||
boardPage := path.Join(config.DocumentRoot, board.Dir, "board.html")
|
||||
os.Remove(boardPage)
|
||||
if err = syscall.Symlink(current_page_filepath, boardPage); !os.IsExist(err) && err != nil {
|
||||
if err = syscall.Symlink(currentPageFilepath, boardPage); !os.IsExist(err) && err != nil {
|
||||
html += handleError(1, "Failed building /"+board.Dir+"/: "+err.Error()) + "<br />"
|
||||
}
|
||||
}
|
||||
|
@ -305,23 +306,23 @@ func buildBoardPages(board *Board) (html string) {
|
|||
// Collect up threads for this page.
|
||||
pageMap := make(map[string]interface{})
|
||||
pageMap["page"] = board.CurrentPage
|
||||
pageMap["threads"] = page_threads
|
||||
pageMap["threads"] = pageThreads
|
||||
pagesArr = append(pagesArr, pageMap)
|
||||
}
|
||||
board.CurrentPage = currentBoardPage
|
||||
|
||||
catalog_json, err := json.Marshal(pagesArr)
|
||||
catalogJSON, err := json.Marshal(pagesArr)
|
||||
if err != nil {
|
||||
html += handleError(1, "Failed to marshal to JSON: "+err.Error()) + "<br />"
|
||||
return
|
||||
}
|
||||
if _, err = catalog_json_file.Write(catalog_json); err != nil {
|
||||
if _, err = catalogJSONFile.Write(catalogJSON); err != nil {
|
||||
html += handleError(1, "Failed writing /"+board.Dir+"/catalog.json: "+err.Error()) + "<br />"
|
||||
return
|
||||
}
|
||||
html += "/" + board.Dir + "/ built successfully.\n"
|
||||
}
|
||||
benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), start_time, false)
|
||||
|
||||
benchmarkTimer("buildBoard"+strconv.Itoa(board.ID), startTime, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -435,7 +436,7 @@ func buildThreadPages(op *Post) (html string) {
|
|||
}
|
||||
|
||||
var replies []Post
|
||||
var current_page_file *os.File
|
||||
var currentPageFile *os.File
|
||||
var board *Board
|
||||
if board, err = getBoardFromID(op.BoardID); err != nil {
|
||||
html += handleError(1, err.Error())
|
||||
|
@ -457,20 +458,20 @@ func buildThreadPages(op *Post) (html string) {
|
|||
repliesInterface = append(repliesInterface, reply)
|
||||
}
|
||||
|
||||
thread_pages := paginate(config.PostsPerThreadPage, repliesInterface)
|
||||
threadPages := paginate(config.PostsPerThreadPage, repliesInterface)
|
||||
deleteMatchingFiles(path.Join(config.DocumentRoot, board.Dir, "res"), "^"+strconv.Itoa(op.ID)+"p")
|
||||
|
||||
op.NumPages = len(thread_pages)
|
||||
op.NumPages = len(threadPages)
|
||||
|
||||
current_page_filepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
|
||||
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
currentPageFilepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
|
||||
currentPageFile, err = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
html += handleError(1, "Failed opening "+current_page_filepath+": "+err.Error())
|
||||
html += handleError(1, "Failed opening "+currentPageFilepath+": "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// render main page
|
||||
if err = threadpageTmpl.Execute(current_page_file, map[string]interface{}{
|
||||
if err = threadpageTmpl.Execute(currentPageFile, map[string]interface{}{
|
||||
"config": config,
|
||||
"boards": allBoards,
|
||||
"board": board,
|
||||
|
@ -496,9 +497,7 @@ func buildThreadPages(op *Post) (html string) {
|
|||
threadMap["posts"] = []Post{*op}
|
||||
|
||||
// Iterate through each reply, which are of type Post
|
||||
for _, reply := range replies {
|
||||
threadMap["posts"] = append(threadMap["posts"], reply)
|
||||
}
|
||||
threadMap["posts"] = append(threadMap["posts"], replies...)
|
||||
threadJSON, err := json.Marshal(threadMap)
|
||||
if err != nil {
|
||||
html += handleError(1, "Failed to marshal to JSON: %s", err.Error()) + "<br />"
|
||||
|
@ -512,21 +511,21 @@ func buildThreadPages(op *Post) (html string) {
|
|||
|
||||
html += fmt.Sprintf("Built /%s/%d successfully", board.Dir, op.ID)
|
||||
|
||||
for page_num, page_posts := range thread_pages {
|
||||
op.CurrentPage = page_num + 1
|
||||
current_page_filepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+"p"+strconv.Itoa(op.CurrentPage)+".html")
|
||||
current_page_file, err = os.OpenFile(current_page_filepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
for pageNum, pagePosts := range threadPages {
|
||||
op.CurrentPage = pageNum + 1
|
||||
currentPageFilepath := path.Join(config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+"p"+strconv.Itoa(op.CurrentPage)+".html")
|
||||
currentPageFile, err = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
html += handleError(1, "<br />Failed opening "+current_page_filepath+": "+err.Error()) + "<br />\n"
|
||||
html += handleError(1, "<br />Failed opening "+currentPageFilepath+": "+err.Error()) + "<br />\n"
|
||||
return
|
||||
}
|
||||
|
||||
if err = threadpageTmpl.Execute(current_page_file, map[string]interface{}{
|
||||
if err = threadpageTmpl.Execute(currentPageFile, map[string]interface{}{
|
||||
"config": config,
|
||||
"boards": allBoards,
|
||||
"board": board,
|
||||
"sections": allSections,
|
||||
"posts": page_posts,
|
||||
"posts": pagePosts,
|
||||
"op": op,
|
||||
}); err != nil {
|
||||
html += handleError(1, "<br />Failed building /%s/%d: %s", board.Dir, op.ID, err.Error())
|
||||
|
|
|
@ -37,7 +37,7 @@ func main() {
|
|||
go tempCleaner()
|
||||
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||
go func() {
|
||||
initServer()
|
||||
}()
|
||||
|
|
|
@ -54,13 +54,13 @@ func callManageFunction(writer http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
if _, ok := manage_functions[action]; ok {
|
||||
if staffRank >= manage_functions[action].Permissions {
|
||||
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(writer, request)))
|
||||
if _, ok := manageFunctions[action]; ok {
|
||||
if staffRank >= manageFunctions[action].Permissions {
|
||||
managePageBuffer.Write([]byte(manageFunctions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 && manageFunctions[action].Permissions == 0 {
|
||||
managePageBuffer.Write([]byte(manageFunctions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 {
|
||||
managePageBuffer.Write([]byte(manage_functions["login"].Callback(writer, request)))
|
||||
managePageBuffer.Write([]byte(manageFunctions["login"].Callback(writer, request)))
|
||||
} else {
|
||||
managePageBuffer.Write([]byte(action + " is undefined."))
|
||||
}
|
||||
|
@ -71,11 +71,7 @@ func callManageFunction(writer http.ResponseWriter, request *http.Request) {
|
|||
managePageBuffer.Write([]byte("\n</body>\n</html>"))
|
||||
}
|
||||
|
||||
/* extension := getFileExtension(request.URL.Path)
|
||||
if extension == "" {
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
} */
|
||||
fmt.Fprintf(writer, managePageBuffer.String())
|
||||
writer.Write(managePageBuffer.Bytes())
|
||||
}
|
||||
|
||||
func getCurrentStaff(request *http.Request) (string, error) {
|
||||
|
@ -148,13 +144,15 @@ func createSession(key string, username string, password string, request *http.R
|
|||
if err != nil {
|
||||
handleError(1, customError(err))
|
||||
return 1
|
||||
} else {
|
||||
}
|
||||
|
||||
success := bcrypt.CompareHashAndPassword([]byte(staff.PasswordChecksum), []byte(password))
|
||||
if success == bcrypt.ErrMismatchedHashAndPassword {
|
||||
// password mismatch
|
||||
modLog.Print("Failed login (password mismatch) from " + request.RemoteAddr + " at " + getSQLDateTime())
|
||||
return 1
|
||||
} else {
|
||||
}
|
||||
|
||||
// successful login, add cookie that expires in one month
|
||||
http.SetCookie(writer, &http.Cookie{
|
||||
Name: "sessiondata",
|
||||
|
@ -177,11 +175,9 @@ func createSession(key string, username string, password string, request *http.R
|
|||
handleError(1, customError(err))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var manage_functions = map[string]ManageFunction{
|
||||
var manageFunctions = map[string]ManageFunction{
|
||||
"cleanup": {
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
|
@ -433,7 +429,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
html += manageConfigBuffer.String()
|
||||
return
|
||||
}},
|
||||
"purgeeverything": {
|
||||
/*"purgeeverything": {
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = "<img src=\"/css/purge.jpg\" />"
|
||||
|
@ -494,7 +490,7 @@ var manage_functions = map[string]ManageFunction{
|
|||
buildBoards() + "<hr />\n" +
|
||||
buildFrontPage()
|
||||
return
|
||||
}},
|
||||
}},*/
|
||||
"executesql": {
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
|
@ -837,7 +833,6 @@ var manage_functions = map[string]ManageFunction{
|
|||
println(2, "Boards rebuilt successfully")
|
||||
done = true
|
||||
}
|
||||
break
|
||||
case do == "del":
|
||||
// resetBoardSectionArrays()
|
||||
case do == "edit":
|
||||
|
@ -877,7 +872,11 @@ var manage_functions = map[string]ManageFunction{
|
|||
manageBoardsBuffer := bytes.NewBufferString("")
|
||||
allSections, _ = getSectionArr("")
|
||||
if len(allSections) == 0 {
|
||||
execSQL("INSERT INTO " + config.DBprefix + "sections (hidden,name,abbreviation) VALUES(0,'Main','main')")
|
||||
if _, err = execSQL(
|
||||
"INSERT INTO " + config.DBprefix + "sections (hidden,name,abbreviation) VALUES(0,'Main','main')",
|
||||
); err != nil {
|
||||
html += handleError(1, err.Error())
|
||||
}
|
||||
}
|
||||
allSections, _ = getSectionArr("")
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ var (
|
|||
allBoards []Board
|
||||
tempPosts []Post
|
||||
tempCleanerTicker *time.Ticker
|
||||
tempCleanerQuit = make(chan struct{})
|
||||
)
|
||||
|
||||
// bumps the given thread on the given board and returns true if there were no errors
|
||||
|
@ -130,7 +129,7 @@ func sinceLastPost(post *Post) int {
|
|||
return int(time.Since(lastPostTime).Seconds())
|
||||
}
|
||||
|
||||
func createImageThumbnail(image_obj image.Image, size string) image.Image {
|
||||
func createImageThumbnail(imageObj image.Image, size string) image.Image {
|
||||
var thumbWidth int
|
||||
var thumbHeight int
|
||||
|
||||
|
@ -145,14 +144,14 @@ func createImageThumbnail(image_obj image.Image, size string) image.Image {
|
|||
thumbWidth = config.ThumbWidth_catalog
|
||||
thumbHeight = config.ThumbHeight_catalog
|
||||
}
|
||||
old_rect := image_obj.Bounds()
|
||||
if thumbWidth >= old_rect.Max.X && thumbHeight >= old_rect.Max.Y {
|
||||
return image_obj
|
||||
oldRect := imageObj.Bounds()
|
||||
if thumbWidth >= oldRect.Max.X && thumbHeight >= oldRect.Max.Y {
|
||||
return imageObj
|
||||
}
|
||||
|
||||
thumbW, thumbH := getThumbnailSize(old_rect.Max.X, old_rect.Max.Y, size)
|
||||
image_obj = imaging.Resize(image_obj, thumbW, thumbH, imaging.CatmullRom) // resize to 600x400 px using CatmullRom cubic filter
|
||||
return image_obj
|
||||
thumbW, thumbH := getThumbnailSize(oldRect.Max.X, oldRect.Max.Y, size)
|
||||
imageObj = imaging.Resize(imageObj, thumbW, thumbH, imaging.CatmullRom) // resize to 600x400 px using CatmullRom cubic filter
|
||||
return imageObj
|
||||
}
|
||||
|
||||
func createVideoThumbnail(video, thumb string, size int) error {
|
||||
|
@ -588,10 +587,10 @@ func makePost(writer http.ResponseWriter, request *http.Request) {
|
|||
if err = banpageTmpl.Execute(&banpageBuffer, map[string]interface{}{
|
||||
"config": config, "ban": banStatus, "banBoards": boards[post.BoardID-1].Dir,
|
||||
}); err != nil {
|
||||
fmt.Fprintf(writer, handleError(1, err.Error()))
|
||||
writer.Write([]byte(handleError(1, err.Error())))
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(writer, banpageBuffer.String())
|
||||
writer.Write(banpageBuffer.Bytes())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -758,5 +757,5 @@ func banHandler(writer http.ResponseWriter, request *http.Request) {
|
|||
fmt.Fprintf(writer, handleError(1, err.Error())+"\n</body>\n</html>")
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(writer, banpageBuffer.String())
|
||||
writer.Write(banpageBuffer.Bytes())
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
|
|||
// the requested path isn't a file or directory, 404
|
||||
serveNotFound(writer, request)
|
||||
return
|
||||
} else {
|
||||
}
|
||||
|
||||
//the file exists, or there is a folder here
|
||||
if results.IsDir() {
|
||||
//check to see if one of the specified index pages exists
|
||||
|
@ -82,12 +83,12 @@ func (s GochanServer) serveFile(writer http.ResponseWriter, request *http.Reques
|
|||
}
|
||||
accessLog.Print("Success: 200 from " + getRealIP(request) + " @ " + request.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
writer.Write(fileBytes)
|
||||
}
|
||||
|
||||
func serveNotFound(writer http.ResponseWriter, request *http.Request) {
|
||||
|
|
17
src/sql.go
17
src/sql.go
|
@ -52,7 +52,6 @@ func connectToSQLServer() {
|
|||
os.Exit(2)
|
||||
}
|
||||
|
||||
nullTime, _ = time.Parse("2006-01-02 15:04:05", nilTimestamp)
|
||||
if db, err = sql.Open(config.DBtype, connStr); err != nil {
|
||||
handleError(0, "Failed to connect to the database: %s\n", customError(err))
|
||||
os.Exit(2)
|
||||
|
@ -69,8 +68,11 @@ func connectToSQLServer() {
|
|||
}
|
||||
|
||||
var sqlVersionStr string
|
||||
err = queryRowSQL("SELECT value FROM "+config.DBprefix+"info WHERE name = 'version'",
|
||||
[]interface{}{}, []interface{}{&sqlVersionStr})
|
||||
if err = queryRowSQL("SELECT value FROM "+config.DBprefix+"info WHERE name = 'version'",
|
||||
[]interface{}{}, []interface{}{&sqlVersionStr}); err != nil {
|
||||
handleError(0, "failed: %s\n", customError(err))
|
||||
os.Exit(2)
|
||||
}
|
||||
var numBoards, numStaff int
|
||||
rows, err := querySQL("SELECT COUNT(*) FROM " + config.DBprefix + "boards UNION ALL SELECT COUNT(*) FROM " + config.DBprefix + "staff")
|
||||
if err != nil {
|
||||
|
@ -106,7 +108,11 @@ func connectToSQLServer() {
|
|||
buildFrontPage()
|
||||
buildBoardListJSON()
|
||||
buildBoards()
|
||||
_, err = execSQL("INSERT INTO "+config.DBprefix+"info (name,value) VALUES('version',?)", versionStr)
|
||||
if _, err = execSQL(
|
||||
"INSERT INTO "+config.DBprefix+"info (name,value) VALUES('version',?)",
|
||||
versionStr); err != nil {
|
||||
handleError(0, "failed: %s\n", err.Error())
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
handleError(0, "failed: %s\n", customError(err))
|
||||
|
@ -146,7 +152,6 @@ func initDB(initFile string) error {
|
|||
if statement != "" && statement != " " {
|
||||
if _, err := db.Exec(statement + ";"); err != nil {
|
||||
panic("Error with SQL statement:" + statement)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +189,6 @@ func prepareSQL(query string) (*sql.Stmt, error) {
|
|||
fallthrough
|
||||
case "sqlite3":
|
||||
preparedStr = query
|
||||
break
|
||||
case "postgres":
|
||||
arr := strings.Split(query, "?")
|
||||
for i := range arr {
|
||||
|
@ -194,7 +198,6 @@ func prepareSQL(query string) (*sql.Stmt, error) {
|
|||
arr[i] += fmt.Sprintf("$%d", i+1)
|
||||
}
|
||||
preparedStr = strings.Join(arr, "")
|
||||
break
|
||||
}
|
||||
stmt, err := db.Prepare(preparedStr)
|
||||
return stmt, sqlVersionErr(err)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -61,10 +62,10 @@ var funcMap = template.FuncMap{
|
|||
"escapeString": func(a string) string {
|
||||
return html.EscapeString(a)
|
||||
},
|
||||
"formatFilesize": func(size_int int) string {
|
||||
size := float32(size_int)
|
||||
"formatFilesize": func(sizeInt int) string {
|
||||
size := float32(sizeInt)
|
||||
if size < 1000 {
|
||||
return fmt.Sprintf("%d B", size_int)
|
||||
return fmt.Sprintf("%d B", sizeInt)
|
||||
} else if size <= 100000 {
|
||||
return fmt.Sprintf("%0.1f KB", size/1024)
|
||||
} else if size <= 100000000 {
|
||||
|
@ -88,12 +89,12 @@ var funcMap = template.FuncMap{
|
|||
}
|
||||
return appended
|
||||
},
|
||||
"truncateMessage": func(msg string, limit int, max_lines int) string {
|
||||
"truncateMessage": func(msg string, limit int, maxLines int) string {
|
||||
var truncated bool
|
||||
split := strings.SplitN(msg, "<br />", -1)
|
||||
|
||||
if len(split) > max_lines {
|
||||
split = split[:max_lines]
|
||||
if len(split) > maxLines {
|
||||
split = split[:maxLines]
|
||||
msg = strings.Join(split, "<br />")
|
||||
truncated = true
|
||||
}
|
||||
|
@ -143,8 +144,8 @@ var funcMap = template.FuncMap{
|
|||
"getCatalogThumbnail": func(img string) string {
|
||||
return getThumbnailPath("catalog", img)
|
||||
},
|
||||
"getThreadID": func(post_i interface{}) (thread int) {
|
||||
post, ok := post_i.(Post)
|
||||
"getThreadID": func(postInterface interface{}) (thread int) {
|
||||
post, ok := postInterface.(Post)
|
||||
if !ok {
|
||||
thread = 0
|
||||
} else if post.ParentID == 0 {
|
||||
|
@ -154,20 +155,20 @@ var funcMap = template.FuncMap{
|
|||
}
|
||||
return
|
||||
},
|
||||
"getPostURL": func(post_i interface{}, typeOf string, withDomain bool) (postURL string) {
|
||||
"getPostURL": func(postInterface interface{}, typeOf string, withDomain bool) (postURL string) {
|
||||
if withDomain {
|
||||
postURL = config.SiteDomain
|
||||
}
|
||||
postURL += config.SiteWebfolder
|
||||
|
||||
if typeOf == "recent" {
|
||||
post, ok := post_i.(*RecentPost)
|
||||
post, ok := postInterface.(*RecentPost)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
postURL = post.GetURL(withDomain)
|
||||
} else {
|
||||
post, ok := post_i.(*Post)
|
||||
post, ok := postInterface.(*Post)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -297,7 +298,6 @@ var (
|
|||
frontPageTmpl *template.Template
|
||||
boardpageTmpl *template.Template
|
||||
threadpageTmpl *template.Template
|
||||
postFormTmpl *template.Template
|
||||
postEditTmpl *template.Template
|
||||
manageBansTmpl *template.Template
|
||||
manageBoardsTmpl *template.Template
|
||||
|
@ -310,10 +310,12 @@ func loadTemplate(files ...string) (*template.Template, error) {
|
|||
var templates []string
|
||||
for i, file := range files {
|
||||
templates = append(templates, file)
|
||||
if _, err := os.Stat(config.TemplateDir + "/override/" + file); !os.IsNotExist(err) {
|
||||
files[i] = config.TemplateDir + "/override/" + files[i]
|
||||
tmplPath := path.Join(config.TemplateDir, "override", file)
|
||||
|
||||
if _, err := os.Stat(tmplPath); !os.IsNotExist(err) {
|
||||
files[i] = tmplPath
|
||||
} else {
|
||||
files[i] = config.TemplateDir + "/" + files[i]
|
||||
files[i] = path.Join(config.TemplateDir, file)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,9 +85,7 @@ type BanAppeal struct {
|
|||
|
||||
func (a *BanAppeal) GetBan() (BanInfo, error) {
|
||||
var ban BanInfo
|
||||
var err error
|
||||
|
||||
err = queryRowSQL("SELECT * FROM "+config.DBprefix+"banlist WHERE id = ? LIMIT 1",
|
||||
err := queryRowSQL("SELECT * FROM "+config.DBprefix+"banlist WHERE id = ? LIMIT 1",
|
||||
[]interface{}{a.ID}, []interface{}{
|
||||
&ban.ID, &ban.AllowRead, &ban.IP, &ban.Name, &ban.NameIsRegex, &ban.SilentBan,
|
||||
&ban.Boards, &ban.Staff, &ban.Timestamp, &ban.Expires, &ban.Permaban, &ban.Reason,
|
||||
|
|
44
src/util.go
44
src/util.go
|
@ -25,7 +25,6 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
nullTime time.Time
|
||||
errEmptyDurationString = errors.New("Empty Duration string")
|
||||
errInvalidDurationString = errors.New("Invalid Duration string")
|
||||
durationRegexp = regexp.MustCompile(`^((\d+)\s?ye?a?r?s?)?\s?((\d+)\s?mon?t?h?s?)?\s?((\d+)\s?we?e?k?s?)?\s?((\d+)\s?da?y?s?)?\s?((\d+)\s?ho?u?r?s?)?\s?((\d+)\s?mi?n?u?t?e?s?)?\s?((\d+)\s?s?e?c?o?n?d?s?)?$`)
|
||||
|
@ -409,9 +408,7 @@ func resetBoardSectionArrays() {
|
|||
allSections = nil
|
||||
|
||||
allBoardsArr, _ := getBoardArr(nil, "")
|
||||
for _, b := range allBoardsArr {
|
||||
allBoards = append(allBoards, b)
|
||||
}
|
||||
allBoards = append(allBoards, allBoardsArr...)
|
||||
|
||||
allSectionsArr, _ := getSectionArr("")
|
||||
allSections = append(allSections, allSectionsArr...)
|
||||
|
@ -426,20 +423,6 @@ func searchStrings(item string, arr []string, permissive bool) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
func bToI(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bToA(b bool) string {
|
||||
if b {
|
||||
return "1"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
// Checks the validity of the Akismet API key given in the config file.
|
||||
func checkAkismetAPIKey(key string) error {
|
||||
if key == "" {
|
||||
|
@ -536,11 +519,6 @@ func marshalJSON(tag string, data interface{}, indent bool) (string, error) {
|
|||
return string(jsonBytes), err
|
||||
}
|
||||
|
||||
func jsonError(err string) string {
|
||||
errJSON, _ := marshalJSON("error", err, false)
|
||||
return errJSON
|
||||
}
|
||||
|
||||
func limitArraySize(arr []string, maxSize int) []string {
|
||||
if maxSize > len(arr)-1 || maxSize < 0 {
|
||||
return arr
|
||||
|
@ -559,26 +537,6 @@ func numReplies(boardid, threadid int) int {
|
|||
return num
|
||||
}
|
||||
|
||||
func ipMatch(newIP, existingIP string) bool {
|
||||
if newIP == existingIP {
|
||||
// both are single IPs and are the same
|
||||
return true
|
||||
}
|
||||
wildcardIndex := strings.Index(existingIP, "*")
|
||||
if wildcardIndex < 0 {
|
||||
// single (or invalid) and they don't match
|
||||
return false
|
||||
}
|
||||
ipRegexStr := existingIP[0:wildcardIndex]
|
||||
ipRegexStr = strings.Replace(ipRegexStr, ".", "\\.", -1) + ".*"
|
||||
ipRegex, err := regexp.Compile(ipRegexStr)
|
||||
if err != nil {
|
||||
// this shouldn't happen unless you enter an invalid IP in the db
|
||||
return false
|
||||
}
|
||||
return ipRegex.MatchString(newIP)
|
||||
}
|
||||
|
||||
// based on TinyBoard's parse_time function
|
||||
func parseDurationString(str string) (time.Duration, error) {
|
||||
if str == "" {
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
{{template "page_header.html" .}}
|
||||
<header>
|
||||
<header>
|
||||
<h1 id="board-title">/{{$.board.Dir}}/ - {{$.board.Title}}</h1>
|
||||
<span id="board-subtitle">{{$.board.Subtitle}}</span>
|
||||
</header>
|
||||
<hr />
|
||||
<div id="right-sidelinks">
|
||||
</header><hr />
|
||||
<div id="right-sidelinks">
|
||||
<a href="{{.config.SiteWebfolder}}{{.board.Dir}}/catalog.html">Board catalog</a><br />
|
||||
</div>
|
||||
{{template "postbox.html" .}}
|
||||
<hr />
|
||||
<div id="content">
|
||||
</div>
|
||||
{{- template "postbox.html" .}}
|
||||
<hr />
|
||||
<div id="content">
|
||||
<form action="/util" method="POST" id="main-form">
|
||||
{{range $t, $thread := .threads}}
|
||||
{{$op := $thread.OP}}
|
||||
{{- range $t, $thread := .threads}}{{$op := $thread.OP}}
|
||||
<div class="thread">
|
||||
<div class="op-post" id="op{{$op.ID}}">
|
||||
{{if ne $op.Filename ""}}
|
||||
{{if ne $op.Filename "deleted"}}
|
||||
{{- if ne $op.Filename "" -}}
|
||||
{{- if ne $op.Filename "deleted"}}
|
||||
<div class="file-info">File: <a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$op.Filename}}" target="_blank">{{$op.Filename}}</a> - ({{formatFilesize $op.Filesize}} , {{$op.ImageW}}x{{$op.ImageH}}, {{$op.FilenameOriginal}})</div>
|
||||
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$op.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{getThreadThumbnail $op.Filename}}" alt="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$op.Filename}}" width="{{$op.ThumbW}}" height="{{$op.ThumbH}}" class="upload" /></a>
|
||||
{{else}}
|
||||
|
@ -25,27 +23,29 @@
|
|||
{{end}}
|
||||
<input type="checkbox" id="check{{$op.ID}}" name="check{{$op.ID}}" /><label class="post-info" for="check{{$op.ID}}"> <span class="subject">{{$op.Subject}}</span> <span class="postername">{{if ne $op.Email ""}}<a href="mailto:{{$op.Email}}">{{end}}{{if ne $op.Name ""}}{{$op.Name}}{{else}}{{if eq $op.Tripcode ""}}{{$.board.Anonymous}}{{end}}{{end}}{{if ne $op.Email ""}}</a>{{end}}</span>{{if ne $op.Tripcode ""}}<span class="tripcode">!{{$op.Tripcode}}</span>{{end}} {{formatTimestamp $op.Timestamp}} </label><a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/res/{{$op.ID}}.html#{{$op.ID}}">No.</a> <a href="javascript:quote({{$op.ID}})" class="backlink-click">{{$op.ID}}</a> <span class="post-links"> <span class="thread-ddown">[<a href="javascript:void(0)">▼</a>]</span> <span>[<a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/res/{{$op.ID}}.html">View</a>]</span></span><br />
|
||||
<div class="post-text">{{truncateMessage $op.MessageHTML 2222 18}}</div>
|
||||
{{if gt $thread.NumReplies 3}}
|
||||
{{- if gt $thread.NumReplies 3}}
|
||||
<b>{{subtract $thread.NumReplies 3}} post{{if gt $thread.NumReplies 4}}s{{end}} omitted</b>
|
||||
{{end}}
|
||||
</div>
|
||||
{{range $reply_num,$reply := $thread.BoardReplies}}
|
||||
{{- range $reply_num,$reply := $thread.BoardReplies}}
|
||||
<div class="reply-container" id="replycontainer{{$reply.ID}}">
|
||||
<a class="anchor" id="{{$reply.ID}}"></a>
|
||||
<div class="reply" id="reply{{$reply.ID}}">
|
||||
<input type="checkbox" id="check{{$reply.ID}}" name="check{{$reply.ID}}" /> <label class="post-info" for="check{{$reply.ID}}"> <span class="subject">{{$reply.Subject}}</span> <span class="postername">{{if ne $reply.Email ""}}<a href="mailto:{{$reply.Email}}">{{end}}{{if ne $reply.Name ""}}{{$reply.Name}}{{else}}{{if eq $reply.Tripcode ""}}{{$.board.Anonymous}}{{end}}{{end}}{{if ne $reply.Email ""}}</a>{{end}}</span>{{if ne $reply.Tripcode ""}}<span class="tripcode">!{{$reply.Tripcode}}</span>{{end}} {{formatTimestamp $reply.Timestamp}} </label><a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/res/{{$op.ID}}.html#{{$reply.ID}}">No.</a> <a href="javascript:quote({{$reply.ID}})" class="backlink-click">{{$reply.ID}}</a> <span class="post-links"><span class="thread-ddown">[<a href="javascript:void(0)">▼</a>]</span></span><br />
|
||||
{{if ne $reply.Filename ""}}
|
||||
{{if ne $reply.Filename "deleted"}}
|
||||
{{if ne $reply.Filename "deleted" -}}
|
||||
<span class="file-info">File: <a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$reply.Filename}}" target="_blank">{{$reply.Filename}}</a> - ({{formatFilesize $reply.Filesize}} , {{$reply.ImageW}}x{{$reply.ImageH}}, {{$reply.FilenameOriginal}})</span><br />
|
||||
<a class="upload-container" href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$reply.Filename}}"><img src="{{$.config.SiteWebfolder}}{{$.board.Dir}}/thumb/{{getThreadThumbnail $reply.Filename}}" alt="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{$reply.Filename}}" width="{{$reply.ThumbW}}" height="{{$reply.ThumbH}}" class="upload" /></a>
|
||||
{{else}}
|
||||
<div class="file-deleted-box" style="text-align:center;">File removed</div>
|
||||
{{end}}{{end}}
|
||||
{{end}}
|
||||
{{end -}}
|
||||
<div class="post-text">{{$reply.MessageHTML}}</div>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
<hr />{{end}}
|
||||
{{end -}}
|
||||
</div><hr />
|
||||
{{- end}}
|
||||
<div id="right-bottom-content">
|
||||
<div id="report-delbox">
|
||||
<input type="hidden" name="board" value="{{.board.Dir}}" />
|
||||
|
@ -58,7 +58,8 @@
|
|||
</form>
|
||||
<div id="left-bottom-content">
|
||||
<table id="pages">
|
||||
<tr><td>{{if gt .board.CurrentPage 2}}
|
||||
<tr>
|
||||
<td>{{if gt .board.CurrentPage 2}}
|
||||
<form method="GET" action="{{.config.SiteWebfolder}}{{.board.Dir}}/{{subtract .board.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Previous" />
|
||||
</form>
|
||||
|
@ -72,11 +73,13 @@
|
|||
<form method="GET" action="{{.config.SiteWebfolder}}{{.board.Dir}}/{{add .board.CurrentPage 1}}.html">
|
||||
<input type="submit" value="Next" />
|
||||
</form>
|
||||
{{else}}Next{{end}}</td></tr>
|
||||
{{else}}Next{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $boardlink := $.boards}}{{if gt $i 0}}/{{end}} <a href="{{$.config.SiteWebfolder}}{{$boardlink.Dir}}/">{{$boardlink.Dir}}</a> {{end}}]
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{template "page_footer.html" .}}
|
||||
</div>
|
||||
{{template "page_footer.html" .}}
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
This will be used for storing configuration-dependent JS variables,
|
||||
instead of loading them on every HTML page.
|
||||
*/ -}}
|
||||
var styles = [{{range $ii, $style := .Styles -}}
|
||||
{{if gt $ii 0}}, {{end -}}
|
||||
var styles = [
|
||||
{{- range $ii, $style := .Styles -}}
|
||||
{{if gt $ii 0}},{{end -}}
|
||||
{Name: "{{js $style.Name}}", Filename: "{{js $style.Filename}}"}
|
||||
{{- end}}];
|
||||
{{- end -}}
|
||||
];
|
||||
var defaultStyle = "{{.DefaultStyle}}";
|
||||
var webroot = "{{.SiteWebfolder}}";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{template "page_header.html" .}}
|
||||
{{- template "page_header.html" .}}
|
||||
<div id="top-pane">
|
||||
<span id="site-title">{{.config.SiteName}}</span><br />
|
||||
<span id="site-slogan">{{.config.SiteSlogan}}</span>
|
||||
|
@ -12,26 +12,37 @@
|
|||
<div class="section-block">
|
||||
<div class="section-title-block"><b>Boards</b></div>
|
||||
<div class="section-body">
|
||||
{{range $_, $section := .sections}}{{if not $section.Hidden}}<ul style="float:left; list-style: none">
|
||||
{{- range $_, $section := .sections -}}
|
||||
{{if not $section.Hidden}}
|
||||
<ul style="float:left; list-style: none">
|
||||
<li style="text-align: center; font-weight: bold"><b><u>{{$section.Name}}</u></b></li>
|
||||
{{range $_, $board := $.boards}}{{if and (eq $board.Section $section.ID) (ne $board.Dir $.config.Modboard)}}
|
||||
{{range $_, $board := $.boards}}
|
||||
{{if and (eq $board.Section $section.ID) (ne $board.Dir $.config.Modboard)}}
|
||||
<li><a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" title="{{$board.Description}}">/{{$board.Dir}}/</a> — {{$board.Title}}</li>
|
||||
{{end}}{{end}}
|
||||
</ul>{{end}}{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if gt .config.MaxRecentPosts 0}}
|
||||
{{- if gt .config.MaxRecentPosts 0}}
|
||||
<div class="section-block">
|
||||
<div class="section-title-block"><b>Recent Posts</b></div>
|
||||
<div class="section-body">
|
||||
<div id="recent-posts">
|
||||
{{range $i, $post := $.recent_posts}}{{$postURL := getPostURL $post "recent" false}}
|
||||
{{- range $i, $post := $.recent_posts}}{{$postURL := getPostURL $post "recent" false}}
|
||||
<div class="recent-post">
|
||||
{{if and (ne $post.Filename "deleted") (ne $post.Filename "")}}<a href="{{$postURL}}" class="front-reply" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a><br />
|
||||
{{else}}<div class="file-deleted-box" style="text-align:center; float:none;"><a href="{{$postURL}}" class="front-reply" target="_blank">No file</a></div>{{end}}<br />
|
||||
<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/">/{{$post.BoardName}}/</a>
|
||||
<hr />
|
||||
{{truncateMessage (stripHTML $post.Message) 40 4}}</div>{{end}}</div>
|
||||
</div>{{end}}</div>
|
||||
{{if and (ne $post.Filename "deleted") (ne $post.Filename "") -}}
|
||||
<a href="{{$postURL}}" class="front-reply" target="_blank"><img src="{{$.config.SiteWebfolder}}{{$post.BoardName}}/thumb/{{getThreadThumbnail $post.Filename}}" alt="post thumbnail"/></a><br />
|
||||
{{else}}
|
||||
<div class="file-deleted-box" style="text-align:center; float:none;"><a href="{{$postURL}}" class="front-reply" target="_blank">No file</a></div>
|
||||
{{- end}}<br />
|
||||
<a href="{{$.config.SiteWebfolder}}{{$post.BoardName}}/">/{{$post.BoardName}}/</a><hr />
|
||||
{{truncateMessage (stripHTML $post.Message) 40 4}}
|
||||
</div>{{end}}
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{template "page_footer.html" .}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<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 <a href="http://github.com/eggbertx/gochan/">Gochan {{version}}</a><br />
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{{with .board}}
|
||||
{{with $.op}}
|
||||
{{if ne $.op.Subject ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
|
||||
{{else if ne $.op.MessageHTML ""}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
|
||||
{{else}}<title>/{{$.board.Dir}}/ - #{{$.op.ID}}</title>{{end}}
|
||||
{{else}}<title>/{{$.board.Dir}}/ - {{$.board.Title}}</title>{{end}}
|
||||
{{else}}<title>{{.config.SiteName}}</title>{{end}}
|
||||
{{with .board -}}
|
||||
{{with $.op -}}
|
||||
{{if ne $.op.Subject "" -}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.Subject 20 true}}</title>
|
||||
{{- else if ne $.op.MessageHTML "" -}}<title>/{{$.board.Dir}}/ - {{truncateString $.op.MessageText 20 true}}</title>
|
||||
{{- else}}<title>/{{$.board.Dir}}/ - #{{$.op.ID}}</title>{{end}}
|
||||
{{- else}}<title>/{{$.board.Dir}}/ - {{$.board.Title}}</title>{{end}}
|
||||
{{- else}}<title>{{.config.SiteName}}</title>{{end}}
|
||||
<link rel="stylesheet" href="{{.config.SiteWebfolder}}css/global.css" />
|
||||
<link id="theme" rel="stylesheet" href="{{.config.SiteWebfolder}}css/{{.config.DefaultStyle}}" />
|
||||
<link rel="shortcut icon" href="{{.config.SiteWebfolder}}favicon.png">
|
||||
|
@ -19,6 +19,6 @@
|
|||
<script type="text/javascript" src="{{$.config.SiteWebfolder}}javascript/manage.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
<div id="topbar">
|
||||
{{range $i, $board := .boards}}<a href="{{$.config.SiteWebfolder}}{{$board.Dir}}/" class="topbar-item">/{{$board.Dir}}/</a>{{end}}
|
||||
</div>
|
||||
</div>
|
|
@ -1,10 +1,13 @@
|
|||
{{define "postbox.html"}}
|
||||
<div id="postbox-area">
|
||||
<form id="postform" name="postform" action="/post" method="POST" enctype="multipart/form-data">
|
||||
{{with .op}}<input type="hidden" name="threadid" value="{{$.op.ID}}" />
|
||||
{{- with .op}}
|
||||
<input type="hidden" name="threadid" value="{{$.op.ID}}" />
|
||||
<input type="hidden" name="boardid" value="{{$.board.ID}}" />
|
||||
{{else}}<input type="hidden" name="threadid" value="0" />
|
||||
<input type="hidden" name="boardid" value="{{$.board.ID}}" />{{end}}
|
||||
{{- else -}}
|
||||
<input type="hidden" name="threadid" value="0" />
|
||||
<input type="hidden" name="boardid" value="{{$.board.ID}}" />
|
||||
{{- end}}
|
||||
<table id="postbox-static">
|
||||
<tr><th class="postblock">Name</th><td><input type="text" name="postname" maxlength="100" size="28" /></td></tr>
|
||||
<tr><th class="postblock">Email</th><td><input type="text" name="postemail" maxlength="100" size="28" /></td></tr>
|
||||
|
@ -13,8 +16,7 @@
|
|||
<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="postmsg" id="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>
|
||||
<input type="password" name="dummy2" style="display:none"/>
|
||||
<tr><th class="postblock">Password</th><td><input type="password" id="postpassword" name="postpassword" size="14" /> (for post/file deletion)</td></tr>
|
||||
</table>
|
||||
</table><input type="password" name="dummy2" style="display:none"/>
|
||||
</form>
|
||||
</div>{{end}}
|
|
@ -2,8 +2,7 @@
|
|||
<header>
|
||||
<h1 id="board-title">/{{$.board.Dir}}/ - {{$.board.Title}}</h1>
|
||||
<span id="board-subtitle">{{$.board.Subtitle}}</span>
|
||||
</header>
|
||||
<hr />
|
||||
</header><hr />
|
||||
<div id="threadlinks-top">
|
||||
<a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/board.html" >Return</a><br />
|
||||
<select id="changepage" onchange="changePage(this)">
|
||||
|
@ -17,23 +16,23 @@
|
|||
<div id="right-sidelinks">
|
||||
<a href="{{$.config.SiteWebfolder}}{{$.board.Dir}}/catalog.html">Board catalog</a><br />
|
||||
</div>
|
||||
{{template "postbox.html" .}}
|
||||
<hr />
|
||||
{{template "postbox.html" .}}<hr />
|
||||
<div id="content">
|
||||
<form action="/util" method="POST" id="main-form">
|
||||
<div class="thread" id="{{$.op.ID}}">
|
||||
<div class="op-post" id="op{{.op.ID}}">
|
||||
{{if ne $.op.Filename ""}}
|
||||
{{if ne $.op.Filename "deleted"}}
|
||||
{{- if ne $.op.Filename "deleted" -}}
|
||||
<div class="file-info">File: <a href="../src/{{.op.Filename}}" target="_blank">{{$.op.Filename}}</a> - ({{formatFilesize $.op.Filesize}} , {{$.op.ImageW}}x{{$.op.ImageH}}, {{$.op.FilenameOriginal}})</div>
|
||||
<a class="upload-container" href="{{.config.SiteWebfolder}}{{.board.Dir}}/src/{{.op.Filename}}"><img src="{{.config.SiteWebfolder}}{{.board.Dir}}/thumb/{{getThreadThumbnail .op.Filename}}" alt="{{$.config.SiteWebfolder}}{{$.board.Dir}}/src/{{.op.Filename}}" width="{{.op.ThumbW}}" height="{{.op.ThumbH}}" class="upload" /></a>
|
||||
{{else}}
|
||||
{{- else}}
|
||||
<div class="file-deleted-box" style="text-align:center;">File removed</div>
|
||||
{{end}}{{end}}
|
||||
{{end}}
|
||||
{{end -}}
|
||||
<input type="checkbox" id="check{{.op.ID}}" name="check{{.op.ID}}" /><label class="post-info" for="check{{.op.ID}}"> <span class="subject">{{.op.Subject}}</span> <span class="postername">{{if ne .op.Email ""}}<a href="mailto:{{.op.Email}}">{{end}}{{if ne .op.Name ""}}{{.op.Name}}{{else}}{{if eq .op.Tripcode ""}}{{.board.Anonymous}}{{end}}{{end}}{{if ne .op.Email ""}}</a>{{end}}</span>{{if ne .op.Tripcode ""}}<span class="tripcode">!{{.op.Tripcode}}</span>{{end}} {{formatTimestamp .op.Timestamp}} </label><a href="{{$.config.SiteWebfolder}}{{.board.Dir}}/res/{{.op.ID}}.html#{{.op.ID}}">No.</a> <a href="javascript:quote({{.op.ID}})" class="backlink-click">{{.op.ID}}</a> <span class="post-links"> <span class="thread-ddown">[<a href="javascript:void(0)">▼</a>]</span></span><br />
|
||||
<div class="post-text">{{.op.MessageHTML}}</div>
|
||||
</div>
|
||||
{{range $reply_num,$reply := .posts}}
|
||||
{{range $reply_num,$reply := .posts -}}
|
||||
<div class="reply-container" id="replycontainer{{$reply.ID}}">
|
||||
<a class="anchor" id="{{$reply.ID}}"></a>
|
||||
<div class="reply" id="reply{{$reply.ID}}">
|
||||
|
@ -47,9 +46,9 @@
|
|||
{{end}}{{end}}
|
||||
<div class="post-text">{{$reply.MessageHTML}}</div>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
<hr />
|
||||
{{end}}
|
||||
</div><hr />
|
||||
<div id="right-bottom-content">
|
||||
<div id="report-delbox">
|
||||
<input type="hidden" name="board" value="{{.board.Dir}}" />
|
||||
|
@ -64,15 +63,18 @@
|
|||
<table id="pages">
|
||||
<tr>
|
||||
<td><a href="{{.config.SiteWebfolder}}{{.board.Dir}}/">Return</a></td>
|
||||
<td>{{if gt .op.CurrentPage 1}}
|
||||
<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}}
|
||||
{{- else}}Previous{{end -}}
|
||||
</td>
|
||||
<td>[<a href="{{.config.SiteWebfolder}}{{.board.Dir}}/res/{{.op.ID}}.html">All</a>]
|
||||
{{range $i,$_ := makeLoop .op.NumPages 0}}
|
||||
[{{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>
|
||||
{{- range $i,$_ := makeLoop .op.NumPages 0 -}}
|
||||
[{{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" />
|
||||
|
@ -80,7 +82,9 @@
|
|||
{{else}}Next{{end}}</td></tr>
|
||||
</table>
|
||||
<span id="boardmenu-bottom">
|
||||
[{{range $i, $boardlink := .boards}} {{if gt $i 0}}/{{end}} <a href="/{{$boardlink.Dir}}/">{{$boardlink.Dir}}</a> {{end}}]
|
||||
[{{range $i, $boardlink := .boards -}}
|
||||
{{if gt $i 0}}/{{end -}} <a href="/{{$boardlink.Dir}}/">{{$boardlink.Dir}}</a>
|
||||
{{- end}}]
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue