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

Replace GcError struct usage with builtin error

Creating it was probably a bad idea and not worth the trouble.
This commit is contained in:
Eggbertx 2020-06-06 09:28:45 -07:00
parent 40ce904a10
commit e6838817fd
20 changed files with 410 additions and 556 deletions

View file

@ -20,7 +20,7 @@ const (
)
func startupRebuild(buildFlag int) {
var err *gcutil.GcError
var err error
gcutil.InitMinifier()
if err = gctemplates.InitTemplates(); err != nil {
gclog.Print(buildLogFlags, "Error initializing templates: ", err.Error())

View file

@ -2,6 +2,7 @@ package building
import (
"encoding/json"
"errors"
"fmt"
"os"
"path"
@ -22,14 +23,14 @@ const (
)
var (
ErrNoBoardDir = gcutil.NewError("board must have a directory before it is built", true)
ErrNoBoardTitle = gcutil.NewError("board must have a title before it is built", true)
ErrNoBoardDir = errors.New("board must have a directory before it is built")
ErrNoBoardTitle = errors.New("board must have a title before it is built")
)
// BuildBoardPages builds the pages for the board archive.
// `board` is a Board object representing the board to build archive pages for.
// The return value is a string of HTML with debug information from the build process.
func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
func BuildBoardPages(board *gcsql.Board) error {
err := gctemplates.InitTemplates("boardpage")
if err != nil {
return err
@ -43,8 +44,8 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
// Get all top level posts for the board.
if opPosts, err = gcsql.GetTopPosts(board.ID); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error getting OP posts for /%s/: %s", board.Dir, err.Error()), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error getting OP posts for /%s/: %s", board.Dir, err.Error()))
}
// For each top level post, start building a Thread struct
@ -54,17 +55,17 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
var replyCount, err = gcsql.GetReplyCount(op.ID)
if err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error getting replies to /%s/%d: %s",
board.Dir, op.ID, err.Error()), false)
board.Dir, op.ID, err.Error()))
}
thread.NumReplies = replyCount
fileCount, err := gcsql.GetReplyFileCount(op.ID)
if err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error getting file count to /%s/%d: %s",
board.Dir, op.ID, err.Error()), false)
board.Dir, op.ID, err.Error()))
}
thread.NumImages = fileCount
@ -83,9 +84,9 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
postsInThread, err = gcsql.GetExistingRepliesLimitedRev(op.ID, numRepliesOnBoardPage)
if err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error getting posts in /%s/%d: %s",
board.Dir, op.ID, err.Error()), false)
board.Dir, op.ID, err.Error()))
}
var reversedPosts []gcsql.Post
@ -122,15 +123,16 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
threads = append(stickiedThreads, nonStickiedThreads...)
// If there are no posts on the board
var boardPageFile *os.File
if len(threads) == 0 {
board.CurrentPage = 1
// Open 1.html for writing to the first page.
boardPageFile, gErr := os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "1.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
boardPageFile, err = os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "1.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/board.html: %s",
board.Dir, gErr.Error()), false)
board.Dir, err.Error()))
}
// Render board page template to the file,
@ -142,9 +144,8 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
"threads": threads,
"board": board,
}, boardPageFile, "text/html"); err != nil {
err.Message = gclog.Printf(gclog.LErrorLog,
"Failed building /%s/: %s", board.Dir, err.Message)
return err
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed building /%s/: %s", board.Dir, err.Error()))
}
return nil
}
@ -156,10 +157,10 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
// Create array of page wrapper objects, and open the file.
pagesArr := make([]map[string]interface{}, board.NumPages)
catalogJSONFile, gErr := os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/catalog.json: %s", board.Dir, gErr.Error()), false)
catalogJSONFile, err := os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "catalog.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/catalog.json: %s", board.Dir, err.Error()))
}
defer catalogJSONFile.Close()
@ -169,10 +170,10 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
var currentPageFilepath string
pageFilename := strconv.Itoa(board.CurrentPage) + ".html"
currentPageFilepath = path.Join(config.Config.DocumentRoot, board.Dir, pageFilename)
currentPageFile, gErr = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
err.AddSystemError(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/%s: %s", board.Dir, pageFilename, gErr.Error()))
currentPageFile, err = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
err = errors.New(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/%s: %s", board.Dir, pageFilename, err.Error()))
continue
}
defer currentPageFile.Close()
@ -188,8 +189,8 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
gcsql.Post{BoardID: board.ID},
},
}, currentPageFile, "text/html"); err != nil {
err.Message = gclog.Printf(gclog.LErrorLog,
"Failed building /%s/ boardpage: %s", board.Dir, err.Message)
err = errors.New(gclog.Printf(gclog.LErrorLog,
"Failed building /%s/ boardpage: %s", board.Dir, err.Error()))
return err
}
@ -201,23 +202,23 @@ func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
}
board.CurrentPage = currentBoardPage
catalogJSON, gErr := json.Marshal(pagesArr)
if gErr != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
"Failed to marshal to JSON: ", gErr.Error()), false)
var catalogJSON []byte
if catalogJSON, err = json.Marshal(pagesArr); err != nil {
return errors.New(gclog.Print(gclog.LErrorLog,
"Failed to marshal to JSON: ", err.Error()))
}
if _, gErr = catalogJSONFile.Write(catalogJSON); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed writing /%s/catalog.json: %s", board.Dir, gErr.Error()), false)
if _, err = catalogJSONFile.Write(catalogJSON); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed writing /%s/catalog.json: %s", board.Dir, err.Error()))
}
return nil
}
// BuildBoards builds the specified board IDs, or all boards if no arguments are passed
// it returns any errors that were encountered
func BuildBoards(verbose bool, which ...int) *gcutil.GcError {
func BuildBoards(verbose bool, which ...int) error {
var boards []gcsql.Board
var err *gcutil.GcError
var err error
if which == nil {
boards = gcsql.AllBoards
@ -225,8 +226,8 @@ func BuildBoards(verbose bool, which ...int) *gcutil.GcError {
for b, id := range which {
boards = append(boards, gcsql.Board{})
if err = boards[b].PopulateData(id); err != nil {
err.Message = gclog.Printf(gclog.LErrorLog, "Error getting board information (ID: %d): %s", id, err.Message)
return err
return errors.New(
gclog.Printf(gclog.LErrorLog, "Error getting board information (ID: %d): %s", id, err.Error()))
}
}
}
@ -236,9 +237,8 @@ func BuildBoards(verbose bool, which ...int) *gcutil.GcError {
for _, board := range boards {
if err = buildBoard(&board, false, true); err != nil {
err.Message = gclog.Printf(gclog.LErrorLog,
"Error building /%s/: %s", board.Dir, err.Error())
return err
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error building /%s/: %s", board.Dir, err.Error()))
}
if verbose {
gclog.Printf(gclog.LStdLog, "Built /%s/ successfully", board.Dir)
@ -260,10 +260,10 @@ func BuildCatalog(boardID int) string {
}
catalogPath := path.Join(config.Config.DocumentRoot, board.Dir, "catalog.html")
catalogFile, gErr := os.OpenFile(catalogPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
catalogFile, err := os.OpenFile(catalogPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/catalog.html: %s", board.Dir, gErr.Error()) + "<br />"
"Failed opening /%s/catalog.html: %s", board.Dir, err.Error()) + "<br />"
}
threadOPs, err := gcsql.GetTopPosts(boardID)
@ -298,8 +298,8 @@ func BuildCatalog(boardID int) string {
// Build builds the board and its thread files
// if newBoard is true, it adds a row to DBPREFIXboards and fails if it exists
// if force is true, it doesn't fail if the directories exist but does fail if it is a file
func buildBoard(board *gcsql.Board, newBoard bool, force bool) *gcutil.GcError {
var err *gcutil.GcError
func buildBoard(board *gcsql.Board, newBoard bool, force bool) error {
var err error
if board.Dir == "" {
return ErrNoBoardDir
}
@ -317,65 +317,66 @@ func buildBoard(board *gcsql.Board, newBoard bool, force bool) *gcutil.GcError {
thumbInfo, _ := os.Stat(thumbPath)
if dirInfo != nil {
if !force {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
pathExistsStr, dirPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
pathExistsStr, dirPath))
}
if !dirInfo.IsDir() {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, dirPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, dirPath))
}
} else {
if err = gcutil.FromError(os.Mkdir(dirPath, 0666), false); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
genericErrStr, dirPath, err.Error()), false)
if err = os.Mkdir(dirPath, 0666); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
genericErrStr, dirPath, err.Error()))
}
}
if resInfo != nil {
if !force {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
pathExistsStr, resPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
pathExistsStr, resPath))
}
if !resInfo.IsDir() {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, resPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, resPath))
}
} else {
if err = gcutil.FromError(os.Mkdir(resPath, 0666), false); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
genericErrStr, resPath, err.Error()), false)
if err = os.Mkdir(resPath, 0666); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
genericErrStr, resPath, err.Error()))
}
}
if srcInfo != nil {
if !force {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
pathExistsStr, srcPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
pathExistsStr, srcPath))
}
if !srcInfo.IsDir() {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, srcPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, srcPath))
}
} else {
if err = gcutil.FromError(os.Mkdir(srcPath, 0666), false); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
genericErrStr, srcPath, err.Error()), false)
if err = os.Mkdir(srcPath, 0666); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
genericErrStr, srcPath, err.Error()))
}
}
if thumbInfo != nil {
if !force {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
pathExistsStr, thumbPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
pathExistsStr, thumbPath))
}
if !thumbInfo.IsDir() {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, thumbPath), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
dirIsAFileStr, thumbPath))
}
} else {
if err = gcutil.FromError(os.Mkdir(thumbPath, 0666), false); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
genericErrStr, thumbPath, err.Error()), false)
if err = os.Mkdir(thumbPath, 0666); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
genericErrStr, thumbPath, err.Error()))
}
}

View file

@ -2,6 +2,7 @@ package building
import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path"
@ -14,26 +15,26 @@ import (
)
// BuildFrontPage builds the front page using templates/front.html
func BuildFrontPage() *gcutil.GcError {
func BuildFrontPage() error {
err := gctemplates.InitTemplates("front")
if err != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
"Error loading front page template: ", err.Error()), false)
return errors.New(gclog.Print(gclog.LErrorLog,
"Error loading front page template: ", err.Error()))
}
os.Remove(path.Join(config.Config.DocumentRoot, "index.html"))
frontFile, gErr := os.OpenFile(path.Join(config.Config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
frontFile, err := os.OpenFile(path.Join(config.Config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
"Failed opening front page for writing: ", err.Error()), false)
if err != nil {
return errors.New(gclog.Print(gclog.LErrorLog,
"Failed opening front page for writing: ", err.Error()))
}
defer frontFile.Close()
var recentPostsArr []gcsql.RecentPost
recentPostsArr, err = gcsql.GetRecentPostsGlobal(config.Config.MaxRecentPosts, !config.Config.RecentPostsWithNoFile)
if err != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
"Failed loading recent posts: "+err.Error()), false)
return errors.New(gclog.Print(gclog.LErrorLog,
"Failed loading recent posts: "+err.Error()))
}
for b := range gcsql.AllBoards {
@ -48,18 +49,18 @@ func BuildFrontPage() *gcutil.GcError {
"boards": gcsql.AllBoards,
"recent_posts": recentPostsArr,
}, frontFile, "text/html"); err != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
"Failed executing front page template: "+err.Error()), false)
return errors.New(gclog.Print(gclog.LErrorLog,
"Failed executing front page template: "+err.Error()))
}
return nil
}
// BuildBoardListJSON generates a JSON file with info about the boards
func BuildBoardListJSON() *gcutil.GcError {
boardListFile, gErr := os.OpenFile(path.Join(config.Config.DocumentRoot, "boards.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(
gclog.Print(gclog.LErrorLog, "Failed opening boards.json for writing: ", gErr.Error()), false)
func BuildBoardListJSON() error {
boardListFile, err := os.OpenFile(path.Join(config.Config.DocumentRoot, "boards.json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return errors.New(
gclog.Print(gclog.LErrorLog, "Failed opening boards.json for writing: ", err.Error()))
}
defer boardListFile.Close()
@ -78,61 +79,59 @@ func BuildBoardListJSON() *gcutil.GcError {
boardsMap["boards"] = append(boardsMap["boards"], gcsql.AllBoards[b])
}
boardJSON, gErr := json.Marshal(boardsMap)
if gErr != nil {
return gcutil.NewError(gclog.Print(gclog.LErrorLog, "Failed to create boards.json: ", gErr.Error()), false)
boardJSON, err := json.Marshal(boardsMap)
if err != nil {
return errors.New(
gclog.Print(gclog.LErrorLog, "Failed to create boards.json: ", err.Error()))
}
_, err := gcutil.MinifyWriter(boardListFile, boardJSON, "application/json")
if err != nil {
err.Message = gclog.Print(gclog.LErrorLog, "Failed writing boards.json file: ", err.Message)
return err
if _, err = gcutil.MinifyWriter(boardListFile, boardJSON, "application/json"); err != nil {
return errors.New(
gclog.Print(gclog.LErrorLog, "Failed writing boards.json file: ", err.Error()))
}
return nil
}
// BuildJS minifies (if enabled) gochan.js and consts.js (the latter is built from a template)
func BuildJS() *gcutil.GcError {
func BuildJS() error {
// minify gochan.js (if enabled)
gochanMinJSPath := path.Join(config.Config.DocumentRoot, "javascript", "gochan.min.js")
gochanMinJSFile, gErr := os.OpenFile(gochanMinJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", gochanMinJSPath, gErr.Error()), false)
gochanMinJSFile, err := os.OpenFile(gochanMinJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", gochanMinJSPath, err.Error()))
}
defer gochanMinJSFile.Close()
gochanJSPath := path.Join(config.Config.DocumentRoot, "javascript", "gochan.js")
gochanJSBytes, gErr := ioutil.ReadFile(gochanJSPath)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", gochanJSPath, gErr.Error()), false)
}
_, err := gcutil.MinifyWriter(gochanMinJSFile, gochanJSBytes, "text/javascript")
gochanJSBytes, err := ioutil.ReadFile(gochanJSPath)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", gochanJSPath, err.Error()))
}
if _, err = gcutil.MinifyWriter(gochanMinJSFile, gochanJSBytes, "text/javascript"); err != nil {
config.Config.UseMinifiedGochanJS = false
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error minifying %q: %s:", gochanMinJSPath, err.Error()), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error minifying %q: %s:", gochanMinJSPath, err.Error()))
}
config.Config.UseMinifiedGochanJS = true
// build consts.js from template
if err = gctemplates.InitTemplates("js"); err != nil {
err.Message = gclog.Println(gclog.LErrorLog,
"Error loading consts.js template:", err.Error())
return err
return errors.New(gclog.Println(gclog.LErrorLog,
"Error loading consts.js template:", err.Error()))
}
constsJSPath := path.Join(config.Config.DocumentRoot, "javascript", "consts.js")
constsJSFile, gErr := os.OpenFile(constsJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", constsJSPath, gErr.Error()), false)
constsJSFile, err := os.OpenFile(constsJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error opening %q for writing: %s", constsJSPath, err.Error()))
}
defer constsJSFile.Close()
if err = gcutil.MinifyTemplate(gctemplates.JsConsts, config.Config, constsJSFile, "text/javascript"); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error building %q: %s", constsJSPath, err.Error()), true)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error building %q: %s", constsJSPath, err.Error()))
}
return nil
}

View file

@ -2,6 +2,7 @@ package building
import (
"encoding/json"
"errors"
"os"
"path"
"strconv"
@ -39,7 +40,7 @@ func BuildThreads(all bool, boardid, threadid int) error {
}
// BuildThreadPages builds the pages for a thread given by a Post object.
func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
func BuildThreadPages(op *gcsql.Post) error {
err := gctemplates.InitTemplates("threadpage")
if err != nil {
return err
@ -54,8 +55,8 @@ func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
replies, err = gcsql.GetExistingReplies(op.ID)
if err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Error building thread %d: %s", op.ID, err.Error()), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Error building thread %d: %s", op.ID, err.Error()))
}
os.Remove(path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html"))
@ -65,10 +66,10 @@ func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
}
threadPageFilepath := path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
threadPageFile, gErr := os.OpenFile(threadPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/res/%d.html: %s", board.Dir, op.ID, gErr.Error()), false)
threadPageFile, err = os.OpenFile(threadPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/res/%d.html: %s", board.Dir, op.ID, err.Error()))
}
// render thread page
@ -80,15 +81,15 @@ func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
"posts": replies,
"op": op,
}, threadPageFile, "text/html"); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error()), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error()))
}
// Put together the thread JSON
threadJSONFile, gErr := os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if gErr != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/res/%d.json: %s", board.Dir, op.ID, gErr.Error()), false)
threadJSONFile, err := os.OpenFile(path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".json"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
if err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed opening /%s/res/%d.json: %s", board.Dir, op.ID, err.Error()))
}
defer threadJSONFile.Close()
@ -99,15 +100,15 @@ func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
// Iterate through each reply, which are of type Post
threadMap["posts"] = append(threadMap["posts"], replies...)
threadJSON, gErr := json.Marshal(threadMap)
threadJSON, err := json.Marshal(threadMap)
if err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed to marshal to JSON: %s", gErr.Error()), false)
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed to marshal to JSON: %s", err.Error()))
}
if _, gErr = threadJSONFile.Write(threadJSON); err != nil {
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
"Failed writing /%s/res/%d.json: %s", board.Dir, op.ID, gErr.Error()), false)
if _, err = threadJSONFile.Write(threadJSON); err != nil {
return errors.New(gclog.Printf(gclog.LErrorLog,
"Failed writing /%s/res/%d.json: %s", board.Dir, op.ID, err.Error()))
}
return nil

View file

@ -48,34 +48,33 @@ func ConnectToDB(host string, dbType string, dbName string, username string, pas
`Invalid DBtype %q in gochan.json, valid values are "mysql", "postgres", and "sqlite3"`, dbType)
}
dbDriver = dbType
var gErr error
if db, gErr = sql.Open(dbType, connStr); gErr != nil {
gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", gErr.Error())
var err error
if db, err = sql.Open(dbType, connStr); err != nil {
gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", err.Error())
}
err := handleVersioning(dbType)
if err != nil {
if err = handleVersioning(dbType); err != nil {
gclog.Print(fatalSQLFlags, "Failed to initialise database: ", err.Error())
}
gclog.Print(gclog.LStdLog|gclog.LErrorLog, "Finished initializing server...")
}
func initDB(initFile string) *gcutil.GcError {
func initDB(initFile string) error {
filePath := gcutil.FindResource(initFile,
"/usr/local/share/gochan/"+initFile,
"/usr/share/gochan/"+initFile)
if filePath == "" {
return gcutil.NewError(fmt.Sprintf(
"SQL database initialization file (%s) missing. Please reinstall gochan", initFile), false)
return fmt.Errorf(
"SQL database initialization file (%s) missing. Please reinstall gochan", initFile)
}
return runSQLFile(filePath)
}
func runSQLFile(path string) *gcutil.GcError {
func runSQLFile(path string) error {
sqlBytes, err := ioutil.ReadFile(path)
if err != nil {
return gcutil.FromError(err, false)
return err
}
sqlStr := regexp.MustCompile("--.*\n?").ReplaceAllString(string(sqlBytes), " ")
@ -86,13 +85,12 @@ func runSQLFile(path string) *gcutil.GcError {
if len(statement) > 0 {
if _, err = db.Exec(statement); err != nil {
if config.Config.DebugMode {
println("Error excecuting sql:")
println(err.Error())
println("Length sql: " + string(len(statement)))
println(statement)
gclog.Printf(gclog.LStdLog, "Error excecuting sql: %s\n", err.Error())
gclog.Printf(gclog.LStdLog, "Length sql: %d\n", len(statement))
gclog.Printf(gclog.LStdLog, "Statement: %s\n", statement)
fmt.Printf("%08b", []byte(statement))
}
return gcutil.FromError(err, false)
return err
}
}
}

View file

@ -2,10 +2,9 @@ package gcsql
import (
"database/sql"
"errors"
"html/template"
"strconv"
"github.com/gochan-org/gochan/pkg/gcutil"
)
var abstractSelectPosts = `
@ -85,7 +84,7 @@ LEFT JOIN
ON recentposts.selfid = singlefiles.post_id`
// getPostsExcecution excecutes a given variation on abstractSelectPosts with parameters and loads the result into an array of posts
func getPostsExcecution(sql string, arguments ...interface{}) ([]Post, *gcutil.GcError) {
func getPostsExcecution(sql string, arguments ...interface{}) ([]Post, error) {
rows, err := QuerySQL(sql, arguments...)
if err != nil {
return nil, err
@ -94,11 +93,11 @@ func getPostsExcecution(sql string, arguments ...interface{}) ([]Post, *gcutil.G
for rows.Next() {
post := new(Post)
var messageHTML string
err = gcutil.FromError(rows.Scan(&post.ID, &post.ParentID, &post.BoardID, &post.Name, &post.Tripcode, &post.Email,
if err = rows.Scan(&post.ID, &post.ParentID, &post.BoardID, &post.Name, &post.Tripcode, &post.Email,
&post.Subject, &messageHTML, &post.MessageText, &post.Password, &post.Filename,
&post.FilenameOriginal, &post.FileChecksum, &post.Filesize, &post.ImageW, &post.ImageH,
&post.ThumbW, &post.ThumbH, &post.IP, &post.Timestamp, &post.Autosage, &post.Bumped, &post.Stickied, &post.Locked), false)
if err != nil {
&post.ThumbW, &post.ThumbH, &post.IP, &post.Timestamp, &post.Autosage, &post.Bumped, &post.Stickied, &post.Locked,
); err != nil {
return nil, err
}
post.MessageHTML = template.HTML(messageHTML)
@ -115,7 +114,7 @@ var sortedTopPosts = onlyTopPosts + "\nORDER BY recentposts.last_bump DESC"
// Results are unsorted
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetTopPostsNoSort(boardID int) (posts []Post, err *gcutil.GcError) {
func GetTopPostsNoSort(boardID int) (posts []Post, err error) {
return getPostsExcecution(onlyTopPosts, boardID)
}
@ -123,7 +122,7 @@ func GetTopPostsNoSort(boardID int) (posts []Post, err *gcutil.GcError) {
// newestFirst sorts the ops by the newest first if true, by newest last if false
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetTopPosts(boardID int) (posts []Post, err *gcutil.GcError) {
func GetTopPosts(boardID int) (posts []Post, err error) {
return getPostsExcecution(sortedTopPosts, boardID)
}
@ -134,14 +133,14 @@ var newestFirstLimited = repliesToX + "\nORDER BY recentposts.created_on DESC\nL
// GetExistingReplies gets all the reply posts to a given thread, ordered by oldest first.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetExistingReplies(topPost int) (posts []Post, err *gcutil.GcError) {
func GetExistingReplies(topPost int) (posts []Post, err error) {
return getPostsExcecution(oldestRepliesFirst, topPost)
}
// GetExistingRepliesLimitedRev gets N amount of reply posts to a given thread, ordered by newest first.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetExistingRepliesLimitedRev(topPost int, limit int) (posts []Post, err *gcutil.GcError) {
func GetExistingRepliesLimitedRev(topPost int, limit int) (posts []Post, err error) {
return getPostsExcecution(newestFirstLimited, topPost, limit)
}
@ -150,7 +149,7 @@ func GetExistingRepliesLimitedRev(topPost int, limit int) (posts []Post, err *gc
// GetSpecificTopPost gets the information for the top post for a given id.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetSpecificTopPost(ID int) (Post, *gcutil.GcError) {
func GetSpecificTopPost(ID int) (Post, error) {
const topPostIDQuery = `SELECT posts.id from DBPREFIXposts as posts
JOIN (
SELECT threads.id from DBPREFIXthreads as threads
@ -172,7 +171,7 @@ func GetSpecificTopPost(ID int) (Post, *gcutil.GcError) {
// GetSpecificPostByString gets a specific post for a given string id.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetSpecificPostByString(ID string) (post Post, err *gcutil.GcError) {
func GetSpecificPostByString(ID string) (Post, error) {
return getSpecificPostStringDecorated(ID, false)
}
@ -180,14 +179,14 @@ func GetSpecificPostByString(ID string) (post Post, err *gcutil.GcError) {
// returns SQL.ErrNoRows if no post could be found
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetSpecificPost(ID int, onlyNotDeleted bool) (post Post, err *gcutil.GcError) {
func GetSpecificPost(ID int, onlyNotDeleted bool) (Post, error) {
return getSpecificPostStringDecorated(strconv.Itoa(ID), onlyNotDeleted)
}
var specificPostSQL = abstractSelectPosts + "\nWHERE recentposts.selfid = ?"
var specificPostSQLNotDeleted = specificPostSQL + "\nWHERE recentposts.is_deleted = FALSE"
func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, *gcutil.GcError) {
func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, error) {
var sql string
if onlyNotDeleted {
sql = specificPostSQL
@ -199,7 +198,7 @@ func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, *gcut
return Post{}, err
}
if len(posts) == 0 {
return Post{}, gcutil.NewError("Could not find a post with the ID: "+ID, false)
return Post{}, errors.New("Could not find a post with the ID: " + ID)
}
return posts[0], nil
}
@ -207,7 +206,7 @@ func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, *gcut
// getRecentPostsInternal returns the most recent N posts, on a specific board if specified, only with files if specified
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecificBoard bool) ([]RecentPost, *gcutil.GcError) {
func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecificBoard bool) ([]RecentPost, error) {
//TODO: rework so it uses all features/better sql
//get recent posts
recentQueryStr := `
@ -267,7 +266,7 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
ON recentposts.selfid = singlefiles.post_id`
var rows *sql.Rows
var err *gcutil.GcError
var err error
if onlyWithFile && onSpecificBoard {
recentQueryStr += "\n" + `WHERE singlefiles.filename IS NOT NULL AND recentposts.boardid = ?
@ -298,9 +297,9 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
for rows.Next() {
recentPost := new(RecentPost)
var formattedHTML template.HTML
if err = gcutil.FromError(rows.Scan(
if err = rows.Scan(
&recentPost.PostID, &recentPost.ParentID, &recentPost.BoardName, &recentPost.BoardID,
&recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH), false,
&recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH,
); err != nil {
return nil, err
}
@ -314,6 +313,6 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
// GetRecentPostsGlobal returns the global N most recent posts from the database.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetRecentPostsGlobal(amount int, onlyWithFile bool) ([]RecentPost, *gcutil.GcError) {
func GetRecentPostsGlobal(amount int, onlyWithFile bool) ([]RecentPost, error) {
return getRecentPostsInternal(amount, onlyWithFile, 0, false)
}

View file

@ -2,6 +2,7 @@ package gcsql
import (
"database/sql"
"errors"
"html/template"
"os"
"path"
@ -13,12 +14,12 @@ import (
)
var (
ErrMultipleDBVersions = gcutil.NewError("More than one version in database", false)
ErrNilBoard = gcutil.NewError("Board is nil", true)
ErrMultipleDBVersions = errors.New("More than one version in database")
ErrNilBoard = errors.New("Board is nil")
)
// GetAllNondeletedMessageRaw gets all the raw message texts from the database, saved per id
func GetAllNondeletedMessageRaw() ([]MessagePostContainer, *gcutil.GcError) {
func GetAllNondeletedMessageRaw() ([]MessagePostContainer, error) {
const sql = `select posts.id, posts.message, posts.message_raw from DBPREFIXposts as posts
WHERE posts.is_deleted = FALSE`
rows, err := QuerySQL(sql)
@ -29,8 +30,7 @@ func GetAllNondeletedMessageRaw() ([]MessagePostContainer, *gcutil.GcError) {
for rows.Next() {
var message MessagePostContainer
var formattedHTML template.HTML
err = gcutil.FromError(rows.Scan(&message.ID, &formattedHTML, &message.MessageRaw), false)
if err != nil {
if err = rows.Scan(&message.ID, &formattedHTML, &message.MessageRaw); err != nil {
return nil, err
}
message.Message = template.HTML(formattedHTML)
@ -40,7 +40,7 @@ func GetAllNondeletedMessageRaw() ([]MessagePostContainer, *gcutil.GcError) {
}
// SetFormattedInDatabase sets all the non-raw text for a given array of items.
func SetFormattedInDatabase(messages []MessagePostContainer) *gcutil.GcError {
func SetFormattedInDatabase(messages []MessagePostContainer) error {
const sql = `UPDATE DBPREFIXposts
SET message = ?
WHERE id = ?`
@ -50,16 +50,15 @@ func SetFormattedInDatabase(messages []MessagePostContainer) *gcutil.GcError {
return err
}
for _, message := range messages {
_, gErr := stmt.Exec(string(message.Message), message.ID)
if gErr != nil {
return gcutil.FromError(gErr, false)
if _, err = stmt.Exec(string(message.Message), message.ID); err != nil {
return err
}
}
return err
}
// GetReplyCount gets the total amount non-deleted of replies in a thread
func GetReplyCount(postID int) (int, *gcutil.GcError) {
func GetReplyCount(postID int) (int, error) {
const sql = `SELECT COUNT(posts.id) FROM DBPREFIXposts as posts
JOIN (
SELECT threads.id FROM DBPREFIXthreads as threads
@ -75,7 +74,7 @@ func GetReplyCount(postID int) (int, *gcutil.GcError) {
}
// GetReplyFileCount gets the amount of files non-deleted posted in total in a thread
func GetReplyFileCount(postID int) (int, *gcutil.GcError) {
func GetReplyFileCount(postID int) (int, error) {
const sql = `SELECT COUNT(files.id) from DBPREFIXfiles as files
JOIN (SELECT posts.id FROM DBPREFIXposts as posts
JOIN (
@ -93,7 +92,7 @@ func GetReplyFileCount(postID int) (int, *gcutil.GcError) {
}
// GetStaffName returns the name associated with a session
func GetStaffName(session string) (string, *gcutil.GcError) {
func GetStaffName(session string) (string, error) {
const sql = `SELECT staff.username from DBPREFIXstaff as staff
JOIN DBPREFIXsessions as sessions
ON sessions.staff_id = staff.id
@ -106,7 +105,7 @@ func GetStaffName(session string) (string, *gcutil.GcError) {
// GetStaffBySession gets the staff that is logged in in the given session
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetStaffBySession(session string) (*Staff, *gcutil.GcError) {
func GetStaffBySession(session string) (*Staff, error) {
const sql = `SELECT
staff.id,
staff.username,
@ -126,7 +125,7 @@ func GetStaffBySession(session string) (*Staff, *gcutil.GcError) {
// GetStaffByName gets the staff with a given name
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetStaffByName(name string) (*Staff, *gcutil.GcError) {
func GetStaffByName(name string) (*Staff, error) {
const sql = `SELECT
staff.id,
staff.username,
@ -141,7 +140,7 @@ func GetStaffByName(name string) (*Staff, *gcutil.GcError) {
return staff, err
}
func getStaffByID(id int) (*Staff, *gcutil.GcError) {
func getStaffByID(id int) (*Staff, error) {
const sql = `SELECT
staff.id,
staff.username,
@ -157,7 +156,7 @@ func getStaffByID(id int) (*Staff, *gcutil.GcError) {
}
// NewStaff creates a new staff account from a given username, password and rank
func NewStaff(username string, password string, rank int) *gcutil.GcError {
func NewStaff(username string, password string, rank int) error {
const sql = `INSERT INTO DBPREFIXstaff (username, password_checksum, global_rank)
VALUES (?, ?, ?)`
_, err := ExecSQL(sql, username, gcutil.BcryptSum(password), rank)
@ -166,13 +165,13 @@ func NewStaff(username string, password string, rank int) *gcutil.GcError {
// DeleteStaff deletes the staff with a given name.
// Implemented to change the account name to a random string and set it to inactive
func DeleteStaff(username string) *gcutil.GcError {
func DeleteStaff(username string) error {
const sql = `UPDATE DBPREFIXstaff SET username = ?, is_active = FALSE WHERE username = ?`
_, err := ExecSQL(sql, gcutil.RandomString(45), username)
return err
}
func getStaffID(username string) (int, *gcutil.GcError) {
func getStaffID(username string) (int, error) {
staff, err := GetStaffByName(username)
if err != nil {
return -1, err
@ -181,7 +180,7 @@ func getStaffID(username string) (int, *gcutil.GcError) {
}
// CreateSession inserts a session for a given key and username into the database
func CreateSession(key string, username string) *gcutil.GcError {
func CreateSession(key string, username string) error {
const sql1 = `INSERT INTO DBPREFIXsessions (staff_id,data,expires) VALUES(?,?,?)`
const sql2 = `UPDATE DBPREFIXstaff SET last_login = CURRENT_TIMESTAMP WHERE id = ?`
staffID, err := getStaffID(username)
@ -197,7 +196,7 @@ func CreateSession(key string, username string) *gcutil.GcError {
}
// PermanentlyRemoveDeletedPosts removes all posts and files marked as deleted from the database
func PermanentlyRemoveDeletedPosts() *gcutil.GcError {
func PermanentlyRemoveDeletedPosts() error {
const sql1 = `DELETE FROM DBPREFIXposts WHERE is_deleted`
const sql2 = `DELETE FROM DBPREFIXthreads WHERE is_deleted`
_, err := ExecSQL(sql1)
@ -209,7 +208,7 @@ func PermanentlyRemoveDeletedPosts() *gcutil.GcError {
}
// OptimizeDatabase peforms a database optimisation
func OptimizeDatabase() *gcutil.GcError {
func OptimizeDatabase() error {
tableRows, tablesErr := QuerySQL("SHOW TABLES")
if tablesErr != nil {
return tablesErr
@ -233,7 +232,7 @@ func getBoardIDFromURIOrNil(URI string) *int {
}
// CreateFileBan creates a new ban on a file. If boards = nil, the ban is global.
func CreateFileBan(fileChecksum string, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
func CreateFileBan(fileChecksum string, staffName string, permaban bool, staffNote string, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfile_ban (board_id, staff_id, staff_note, checksum) VALUES board_id = ?, staff_id = ?, staff_note = ?, checksum = ?`
staffID, err := getStaffID(staffName)
if err != nil {
@ -245,7 +244,7 @@ func CreateFileBan(fileChecksum string, staffName string, permaban bool, staffNo
}
// CreateFileNameBan creates a new ban on a filename. If boards = nil, the ban is global.
func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfilename_ban (board_id, staff_id, staff_note, filename, is_regex) VALUES board_id = ?, staff_id = ?, staff_note = ?, filename = ?, is_regex = ?`
staffID, err := getStaffID(staffName)
if err != nil {
@ -257,7 +256,7 @@ func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban
}
// CreateUserNameBan creates a new ban on a username. If boards = nil, the ban is global.
func CreateUserNameBan(userName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
func CreateUserNameBan(userName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) error {
const sql = `INSERT INTO DBPREFIXusername_ban (board_id, staff_id, staff_note, username, is_regex) VALUES board_id = ?, staff_id = ?, staff_note = ?, username = ?, is_regex = ?`
staffID, err := getStaffID(staffName)
if err != nil {
@ -272,7 +271,7 @@ func CreateUserNameBan(userName string, isRegex bool, staffName string, permaban
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func CreateUserBan(IP string, threadBan bool, staffName string, boardURI string, expires time.Time, permaban bool,
staffNote string, message string, canAppeal bool, appealAt time.Time) *gcutil.GcError {
staffNote string, message string, canAppeal bool, appealAt time.Time) error {
const sql = `INSERT INTO DBPREFIXip_ban (board_id, staff_id, staff_note, is_thread_ban, ip, appeal_at, expires_at, permanent, message, can_appeal, issued_at, copy_posted_text, is_active)
VALUES (?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP,'OLD SYSTEM BAN, NO TEXT AVAILABLE',TRUE)`
staffID, err := getStaffID(staffName)
@ -287,7 +286,7 @@ func CreateUserBan(IP string, threadBan bool, staffName string, boardURI string,
//GetAllAccouncements gets all announcements, newest first
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetAllAccouncements() ([]Announcement, *gcutil.GcError) {
func GetAllAccouncements() ([]Announcement, error) {
const sql = `SELECT s.username, a.timestamp, a.subject, a.message FROM DBPREFIXannouncements AS a
JOIN DBPREFIXstaff AS s
ON a.staff_id = s.id
@ -299,7 +298,7 @@ func GetAllAccouncements() ([]Announcement, *gcutil.GcError) {
var announcements []Announcement
for rows.Next() {
var announcement Announcement
err = gcutil.FromError(rows.Scan(&announcement.Poster, &announcement.Timestamp, &announcement.Subject, &announcement.Message), false)
err = rows.Scan(&announcement.Poster, &announcement.Timestamp, &announcement.Subject, &announcement.Message)
if err != nil {
return nil, err
}
@ -311,7 +310,7 @@ func GetAllAccouncements() ([]Announcement, *gcutil.GcError) {
//CreateBoard creates this board in the database if it doesnt exist already, also sets ID to correct value
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func CreateBoard(values *Board) *gcutil.GcError {
func CreateBoard(values *Board) error {
const maxThreads = 300
const sqlINSERT = `INSERT INTO DBPREFIXboards (navbar_position, dir, uri, title, subtitle, description, max_file_size, max_threads, default_style, locked, anonymous_name, force_anonymous, autosage_after, no_images_after, max_message_length, min_message_length, allow_embeds, redirect_to_thread, require_file, enable_catalog, section_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
@ -329,7 +328,7 @@ func CreateBoard(values *Board) *gcutil.GcError {
}
//GetBoardUris gets a list of all existing board URIs
func GetBoardUris() (URIS []string, err *gcutil.GcError) {
func GetBoardUris() (URIS []string, err error) {
const sql = `SELECT uri FROM DBPREFIXboards`
rows, err := QuerySQL(sql)
if err != nil {
@ -338,8 +337,7 @@ func GetBoardUris() (URIS []string, err *gcutil.GcError) {
var uris []string
for rows.Next() {
var uri string
err = gcutil.FromError(rows.Scan(&uri), false)
if err != nil {
if err = rows.Scan(&uri); err != nil {
return nil, err
}
uris = append(uris, uri)
@ -348,7 +346,7 @@ func GetBoardUris() (URIS []string, err *gcutil.GcError) {
}
//GetAllSections gets a list of all existing sections
func GetAllSections() ([]BoardSection, *gcutil.GcError) {
func GetAllSections() ([]BoardSection, error) {
const sql = `SELECT id, name, abbreviation, position, hidden FROM DBPREFIXsections ORDER BY position ASC, name ASC`
rows, err := QuerySQL(sql)
if err != nil {
@ -357,7 +355,7 @@ func GetAllSections() ([]BoardSection, *gcutil.GcError) {
var sections []BoardSection
for rows.Next() {
var section BoardSection
err = gcutil.FromError(rows.Scan(&section.ID, &section.Name, &section.Abbreviation, &section.ListOrder, &section.Hidden), false)
err = rows.Scan(&section.ID, &section.Name, &section.Abbreviation, &section.ListOrder, &section.Hidden)
if err != nil {
return nil, err
}
@ -369,7 +367,7 @@ func GetAllSections() ([]BoardSection, *gcutil.GcError) {
// GetAllSectionsOrCreateDefault gets all sections in the database, creates default if none exist
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetAllSectionsOrCreateDefault() ([]BoardSection, *gcutil.GcError) {
func GetAllSectionsOrCreateDefault() ([]BoardSection, error) {
_, err := GetOrCreateDefaultSectionID()
if err != nil {
return nil, err
@ -377,7 +375,7 @@ func GetAllSectionsOrCreateDefault() ([]BoardSection, *gcutil.GcError) {
return GetAllSections()
}
func getNextSectionListOrder() (int, *gcutil.GcError) {
func getNextSectionListOrder() (int, error) {
const sql = `SELECT COALESCE(MAX(position) + 1, 0) FROM DBPREFIXsections`
var ID int
err := QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&ID))
@ -385,11 +383,11 @@ func getNextSectionListOrder() (int, *gcutil.GcError) {
}
//GetOrCreateDefaultSectionID creates the default section if it does not exist yet, returns default section ID if it exists
func GetOrCreateDefaultSectionID() (sectionID int, err *gcutil.GcError) {
func GetOrCreateDefaultSectionID() (sectionID int, err error) {
const SQL = `SELECT id FROM DBPREFIXsections WHERE name = 'Main'`
var ID int
err = QueryRowSQL(SQL, interfaceSlice(), interfaceSlice(&ID))
if gcutil.CompareErrors(err, sql.ErrNoRows) {
if err == sql.ErrNoRows {
//create it
ID, err := getNextSectionListOrder()
if err != nil {
@ -406,7 +404,7 @@ func GetOrCreateDefaultSectionID() (sectionID int, err *gcutil.GcError) {
}
//CreateSection creates a section, setting the newly created id in the given struct
func CreateSection(section *BoardSection) *gcutil.GcError {
func CreateSection(section *BoardSection) error {
const sqlINSERT = `INSERT INTO DBPREFIXsections (name, abbreviation, hidden, position) VALUES (?,?,?,?)`
const sqlSELECT = `SELECT id FROM DBPREFIXsections WHERE position = ?`
//Excecuted in two steps this way because last row id functions arent thread safe, position is unique
@ -423,7 +421,7 @@ func CreateSection(section *BoardSection) *gcutil.GcError {
//GetAllStaffNopass gets all staff accounts without their password
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetAllStaffNopass() ([]Staff, *gcutil.GcError) {
func GetAllStaffNopass() ([]Staff, error) {
const sql = `SELECT id, username, global_rank, added_on, last_login FROM DBPREFIXstaff`
rows, err := QuerySQL(sql)
if err != nil {
@ -432,7 +430,7 @@ func GetAllStaffNopass() ([]Staff, *gcutil.GcError) {
var staffs []Staff
for rows.Next() {
var staff Staff
err = gcutil.FromError(rows.Scan(&staff.ID, &staff.Username, &staff.Rank, &staff.AddedOn, &staff.LastActive), false)
err = rows.Scan(&staff.ID, &staff.Username, &staff.Rank, &staff.AddedOn, &staff.LastActive)
if err != nil {
return nil, err
}
@ -445,7 +443,7 @@ func GetAllStaffNopass() ([]Staff, *gcutil.GcError) {
//Warning, currently only gets ip bans, not other types of bans, as the ban functionality needs a major revamp anyway
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetAllBans() ([]BanInfo, *gcutil.GcError) {
func GetAllBans() ([]BanInfo, error) {
const sql = `SELECT
ban.id,
ban.ip,
@ -470,7 +468,7 @@ ON ban.board_id = board.id`
var bans []BanInfo
for rows.Next() {
var ban BanInfo
err = gcutil.FromError(rows.Scan(&ban.ID, &ban.IP, &ban.Boards, &ban.Staff, &ban.Timestamp, &ban.Expires, &ban.Permaban, &ban.Reason, &ban.StaffNote, &ban.AppealAt, &ban.CanAppeal), false)
err = rows.Scan(&ban.ID, &ban.IP, &ban.Boards, &ban.Staff, &ban.Timestamp, &ban.Expires, &ban.Permaban, &ban.Reason, &ban.StaffNote, &ban.AppealAt, &ban.CanAppeal)
if err != nil {
return nil, err
}
@ -483,19 +481,19 @@ ON ban.board_id = board.id`
// name, filename and checksum may be empty strings and will be treated as not requested if done so
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func CheckBan(ip string, name string, filename string, checksum string) (*BanInfo, *gcutil.GcError) {
func CheckBan(ip string, name string, filename string, checksum string) (*BanInfo, error) {
ban := new(BanInfo)
ipban, err1 := checkIPBan(ip)
err1NoRows := gcutil.CompareErrors(err1, sql.ErrNoRows)
err1NoRows := (err1 == sql.ErrNoRows)
_, err2 := checkFileBan(checksum)
err2NoRows := gcutil.CompareErrors(err2, sql.ErrNoRows)
err2NoRows := (err2 == sql.ErrNoRows)
_, err3 := checkFilenameBan(filename)
err3NoRows := gcutil.CompareErrors(err3, sql.ErrNoRows)
err3NoRows := (err3 == sql.ErrNoRows)
_, err4 := checkUsernameBan(name)
err4NoRows := gcutil.CompareErrors(err4, sql.ErrNoRows)
err4NoRows := (err4 == sql.ErrNoRows)
if err1NoRows && err2NoRows && err3NoRows && err4NoRows {
return nil, gcutil.FromError(sql.ErrNoRows, false)
return nil, sql.ErrNoRows
}
if err1NoRows {
@ -530,7 +528,7 @@ func CheckBan(ip string, name string, filename string, checksum string) (*BanInf
return nil, gcutil.ErrNotImplemented
}
func checkIPBan(ip string) (*IPBan, *gcutil.GcError) {
func checkIPBan(ip string) (*IPBan, error) {
const sql = `SELECT id, staff_id, board_id, banned_for_post_id, copy_post_text, is_thread_ban, is_active, ip, issued_at, appeal_at, expires_at, permanent, staff_note, message, can_appeal
FROM DBPREFIXip_ban WHERE ip = ?`
var ban = new(IPBan)
@ -540,7 +538,7 @@ func checkIPBan(ip string) (*IPBan, *gcutil.GcError) {
return ban, err
}
func checkUsernameBan(name string) (*UsernameBan, *gcutil.GcError) {
func checkUsernameBan(name string) (*UsernameBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, username, is_regex
FROM DBPREFIXusername_ban WHERE username = ?`
var ban = new(UsernameBan)
@ -548,7 +546,7 @@ func checkUsernameBan(name string) (*UsernameBan, *gcutil.GcError) {
return ban, err
}
func checkFilenameBan(filename string) (*FilenameBan, *gcutil.GcError) {
func checkFilenameBan(filename string) (*FilenameBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, filename, is_regex
FROM DBPREFIXfilename_ban WHERE filename = ?`
var ban = new(FilenameBan)
@ -556,7 +554,7 @@ func checkFilenameBan(filename string) (*FilenameBan, *gcutil.GcError) {
return ban, err
}
func checkFileBan(checksum string) (*FileBan, *gcutil.GcError) {
func checkFileBan(checksum string) (*FileBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, checksum
FROM DBPREFIXfile_ban WHERE checksum = ?`
var ban = new(FileBan)
@ -567,7 +565,7 @@ func checkFileBan(checksum string) (*FileBan, *gcutil.GcError) {
//SinceLastPost returns the seconds since the last post by the ip address that made this post
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func SinceLastPost(postID int) (int, *gcutil.GcError) {
func SinceLastPost(postID int) (int, error) {
const sql = `SELECT MAX(created_on) FROM DBPREFIXposts as posts
JOIN (SELECT ip FROM DBPREFIXposts as sp
WHERE sp.id = ?) as ip
@ -583,12 +581,12 @@ func SinceLastPost(postID int) (int, *gcutil.GcError) {
// InsertPost insersts prepared post object into the SQL table so that it can be rendered
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func InsertPost(post *Post, bump bool) *gcutil.GcError {
func InsertPost(post *Post, bump bool) error {
const sql = `INSERT INTO DBPREFIXposts (id, thread_id, name, tripcode, is_role_signature, email, subject, ip, is_top_post, message, message_raw, banned_message, password)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
isNewThread := post.ParentID == 0
var threadID int
var err *gcutil.GcError
var err error
if isNewThread {
threadID, err = createThread(post.BoardID, post.Locked, post.Stickied, post.Autosage, false)
} else {
@ -629,7 +627,7 @@ func InsertPost(post *Post, bump bool) *gcutil.GcError {
return nil
}
func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclical bool) (threadID int, err *gcutil.GcError) {
func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclical bool) (threadID int, err error) {
const sql = `INSERT INTO DBPREFIXthreads (board_id, locked, stickied, anchored, cyclical) VALUES (?,?,?,?,?)`
//Retrieves next free ID, explicitly inserts it, keeps retrying until succesfull insert or until a non-pk error is encountered.
//This is done because mysql/sqlite doesnt support RETURNING and both LAST_INSERT_ID() and last_row_id() are not thread-safe
@ -649,7 +647,7 @@ func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclic
return threadID, nil
}
func bumpThreadOfPost(postID int) *gcutil.GcError {
func bumpThreadOfPost(postID int) error {
id, err := getThreadID(postID)
if err != nil {
return err
@ -657,13 +655,13 @@ func bumpThreadOfPost(postID int) *gcutil.GcError {
return bumpThread(id)
}
func bumpThread(threadID int) *gcutil.GcError {
func bumpThread(threadID int) error {
const sql = "UPDATE DBPREFIXthreads SET last_bump = CURRENT_TIMESTAMP WHERE id = ?"
_, err := ExecSQL(sql, threadID)
return err
}
func appendFile(postID int, originalFilename string, filename string, checksum string, fileSize int, isSpoilered bool, width int, height int, thumbnailWidth int, thumbnailHeight int) *gcutil.GcError {
func appendFile(postID int, originalFilename string, filename string, checksum string, fileSize int, isSpoilered bool, width int, height int, thumbnailWidth int, thumbnailHeight int) error {
const nextIDSQL = `SELECT COALESCE(MAX(file_order) + 1, 0) FROM DBPREFIXfiles WHERE post_id = ?`
var nextID int
err := QueryRowSQL(nextIDSQL, interfaceSlice(postID), interfaceSlice(&nextID))
@ -677,7 +675,7 @@ func appendFile(postID int, originalFilename string, filename string, checksum s
}
//GetMaxMessageLength returns the max message length on a board
func GetMaxMessageLength(boardID int) (length int, err *gcutil.GcError) {
func GetMaxMessageLength(boardID int) (length int, err error) {
const sql = `SELECT max_message_length FROM DBPREFIXboards
WHERE id = ?`
err = QueryRowSQL(sql, interfaceSlice(boardID), interfaceSlice(&length))
@ -685,7 +683,7 @@ func GetMaxMessageLength(boardID int) (length int, err *gcutil.GcError) {
}
//GetEmbedsAllowed returns if embeds are allowed on a given board
func GetEmbedsAllowed(boardID int) (allowed bool, err *gcutil.GcError) {
func GetEmbedsAllowed(boardID int) (allowed bool, err error) {
const sql = `SELECT allow_embeds FROM DBPREFIXboards
WHERE id = ?`
err = QueryRowSQL(sql, interfaceSlice(boardID), interfaceSlice(&allowed))
@ -693,7 +691,7 @@ func GetEmbedsAllowed(boardID int) (allowed bool, err *gcutil.GcError) {
}
//GetBoardFromPostID gets the boardURI that a given postid exists on
func GetBoardFromPostID(postID int) (boardURI string, err *gcutil.GcError) {
func GetBoardFromPostID(postID int) (boardURI string, err error) {
const sql = `SELECT board.uri FROM DBPREFIXboards as board
JOIN (
SELECT threads.board_id FROM DBPREFIXthreads as threads
@ -707,7 +705,7 @@ func GetBoardFromPostID(postID int) (boardURI string, err *gcutil.GcError) {
//GetThreadIDZeroIfTopPost gets the post id of the top post of the thread a post belongs to, zero if the post itself is the top post
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design. Posts do not directly reference their post post anymore.
func GetThreadIDZeroIfTopPost(postID int) (ID int, err *gcutil.GcError) {
func GetThreadIDZeroIfTopPost(postID int) (ID int, err error) {
const sql = `SELECT t1.id FROM DBPREFIXposts as t1
JOIN (SELECT thread_id FROM DBPREFIXposts where id = ?) as t2 ON t1.thread_id = t2.thread_id
WHERE t1.is_top_post`
@ -721,14 +719,14 @@ func GetThreadIDZeroIfTopPost(postID int) (ID int, err *gcutil.GcError) {
return ID, nil
}
func getThreadID(postID int) (ID int, err *gcutil.GcError) {
func getThreadID(postID int) (ID int, err error) {
const sql = `SELECT thread_id FROM DBPREFIXposts WHERE id = ?`
err = QueryRowSQL(sql, interfaceSlice(postID), interfaceSlice(&ID))
return ID, err
}
//AddBanAppeal adds a given appeal to a given ban
func AddBanAppeal(banID uint, message string) *gcutil.GcError {
func AddBanAppeal(banID uint, message string) error {
const sql1 = `
/*copy old to audit*/
INSERT INTO DBPREFIXip_ban_appeals_audit (appeal_id, staff_id, appeal_text, staff_response, is_denied)
@ -748,7 +746,7 @@ func AddBanAppeal(banID uint, message string) *gcutil.GcError {
}
//GetPostPassword gets the password associated with a given post
func GetPostPassword(postID int) (password string, err *gcutil.GcError) {
func GetPostPassword(postID int) (password string, err error) {
const sql = `SELECT password_checksum FROM DBPREFIXposts WHERE id = ?`
err = QueryRowSQL(sql, interfaceSlice(postID), interfaceSlice(&password))
return password, err
@ -757,7 +755,7 @@ func GetPostPassword(postID int) (password string, err *gcutil.GcError) {
//UpdatePost updates a post with new information
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func UpdatePost(postID int, email string, subject string, message template.HTML, messageRaw string) *gcutil.GcError {
func UpdatePost(postID int, email string, subject string, message template.HTML, messageRaw string) error {
const sql = `UPDATE DBPREFIXposts SET email = ?, subject = ?, message = ?, message_raw = ? WHERE id = ?`
_, err := ExecSQL(sql, email, subject, string(message), messageRaw)
return err
@ -766,7 +764,7 @@ func UpdatePost(postID int, email string, subject string, message template.HTML,
//DeleteFilesFromPost deletes all files belonging to a given post
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design. Should be implemented to delete files individually
func DeleteFilesFromPost(postID int) *gcutil.GcError {
func DeleteFilesFromPost(postID int) error {
board, err := GetBoardFromPostID(postID)
if err != nil {
return err
@ -781,8 +779,7 @@ func DeleteFilesFromPost(postID int) *gcutil.GcError {
var filenames []string
for rows.Next() {
var filename string
err = gcutil.FromError(rows.Scan(&filename), false)
if err != nil {
if err = rows.Scan(&filename); err != nil {
return err
}
filenames = append(filenames, filename)
@ -808,7 +805,7 @@ func DeleteFilesFromPost(postID int) *gcutil.GcError {
}
//DeletePost deletes a post with a given ID
func DeletePost(postID int, checkIfTopPost bool) *gcutil.GcError {
func DeletePost(postID int, checkIfTopPost bool) error {
if checkIfTopPost {
isTopPost, err := isTopPost(postID)
if err != nil {
@ -829,13 +826,13 @@ func DeletePost(postID int, checkIfTopPost bool) *gcutil.GcError {
return err
}
func isTopPost(postID int) (val bool, err *gcutil.GcError) {
func isTopPost(postID int) (val bool, err error) {
const sql = `SELECT is_top_post FROM DBPREFIXposts WHERE id = ?`
err = QueryRowSQL(sql, interfaceSlice(postID), interfaceSlice(&val))
return val, err
}
func deleteThread(threadID int) *gcutil.GcError {
func deleteThread(threadID int) error {
const sql1 = `UPDATE DBPREFIXthreads SET is_deleted = TRUE, deleted_at = CURRENT_TIMESTAMP WHERE id = ?`
const sql2 = `SELECT id FROM DBPREFIXposts WHERE thread_id = ?`
@ -850,16 +847,14 @@ func deleteThread(threadID int) *gcutil.GcError {
var ids []int
for rows.Next() {
var id int
err = gcutil.FromError(rows.Scan(&id), false)
if err != nil {
if err = rows.Scan(&id); err != nil {
return err
}
ids = append(ids, id)
}
for _, id := range ids {
err = DeletePost(id, false)
if err != nil {
if err = DeletePost(id, false); err != nil {
return err
}
}
@ -867,7 +862,7 @@ func deleteThread(threadID int) *gcutil.GcError {
}
//CreateDefaultBoardIfNoneExist creates a default board if no boards exist yet
func CreateDefaultBoardIfNoneExist() *gcutil.GcError {
func CreateDefaultBoardIfNoneExist() error {
const sqlStr = `SELECT COUNT(id) FROM DBPREFIXboards`
var count int
QueryRowSQL(sqlStr, interfaceSlice(), interfaceSlice(&count))
@ -875,7 +870,7 @@ func CreateDefaultBoardIfNoneExist() *gcutil.GcError {
return nil
}
defaultSectionID, err := GetOrCreateDefaultSectionID()
if err != nil && !gcutil.CompareErrors(err, sql.ErrNoRows) {
if err != nil && err != sql.ErrNoRows {
return err
}
var board = Board{
@ -889,7 +884,7 @@ func CreateDefaultBoardIfNoneExist() *gcutil.GcError {
}
//CreateDefaultAdminIfNoStaff creates a new default admin account if no accounts exist
func CreateDefaultAdminIfNoStaff() *gcutil.GcError {
func CreateDefaultAdminIfNoStaff() error {
const sql = `SELECT COUNT(id) FROM DBPREFIXstaff`
var count int
QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&count))
@ -900,7 +895,7 @@ func CreateDefaultAdminIfNoStaff() *gcutil.GcError {
return err
}
func createUser(username string, passwordEncrypted string, globalRank int) (userID int, err *gcutil.GcError) {
func createUser(username string, passwordEncrypted string, globalRank int) (userID int, err error) {
const sqlInsert = `INSERT INTO DBPREFIXstaff (username, password_checksum, global_rank) VALUES (?,?,?)`
const sqlSelect = `SELECT id FROM DBPREFIXstaff WHERE username = ?`
//Excecuted in two steps this way because last row id functions arent thread safe, username is unique
@ -915,7 +910,7 @@ func createUser(username string, passwordEncrypted string, globalRank int) (user
//UpdateID takes a board struct and sets the database id according to the dir that is already set
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design. (Just bad design in general, try to avoid directly mutating state like this)
func (board *Board) UpdateID() *gcutil.GcError {
func (board *Board) UpdateID() error {
const sql = `SELECT id FROM DBPREFIXboards WHERE dir = ?`
return QueryRowSQL(sql, interfaceSlice(board.Dir), interfaceSlice(&board.ID))
}
@ -923,13 +918,13 @@ func (board *Board) UpdateID() *gcutil.GcError {
// PopulateData gets the board data from the database, according to its id, and sets the respective properties.
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func (board *Board) PopulateData(id int) *gcutil.GcError {
func (board *Board) PopulateData(id int) error {
const sql = "SELECT id, section_id, dir, navbar_position, title, subtitle, description, max_file_size, default_style, locked, created_at, anonymous_name, force_anonymous, autosage_after, no_images_after, max_message_length, allow_embeds, redirect_to_thread, require_file, enable_catalog FROM DBPREFIXboards WHERE id = ?"
return QueryRowSQL(sql, interfaceSlice(id), interfaceSlice(&board.ID, &board.Section, &board.Dir, &board.ListOrder, &board.Title, &board.Subtitle, &board.Description, &board.MaxFilesize, &board.DefaultStyle, &board.Locked, &board.CreatedOn, &board.Anonymous, &board.ForcedAnon, &board.AutosageAfter, &board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed, &board.RedirectToThread, &board.RequireFile, &board.EnableCatalog))
}
//DoesBoardExistByID returns a bool indicating whether a board with a given id exists
func DoesBoardExistByID(ID int) (bool, *gcutil.GcError) {
func DoesBoardExistByID(ID int) (bool, error) {
const sql = `SELECT COUNT(id) FROM DBPREFIXboards WHERE id = ?`
var count int
err := QueryRowSQL(sql, interfaceSlice(ID), interfaceSlice(&count))
@ -939,7 +934,7 @@ func DoesBoardExistByID(ID int) (bool, *gcutil.GcError) {
//GetAllBoards gets a list of all existing boards
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetAllBoards() ([]Board, *gcutil.GcError) {
func GetAllBoards() ([]Board, error) {
const sql = `SELECT id, section_id, dir, navbar_position, title, subtitle, description, max_file_size, default_style, locked, created_at, anonymous_name, force_anonymous, autosage_after, no_images_after, max_message_length, allow_embeds, redirect_to_thread, require_file, enable_catalog FROM DBPREFIXboards
ORDER BY navbar_position ASC, dir ASC`
rows, err := QuerySQL(sql)
@ -949,7 +944,7 @@ func GetAllBoards() ([]Board, *gcutil.GcError) {
var boards []Board
for rows.Next() {
var board Board
err = gcutil.FromError(rows.Scan(&board.ID, &board.Section, &board.Dir, &board.ListOrder, &board.Title, &board.Subtitle, &board.Description, &board.MaxFilesize, &board.DefaultStyle, &board.Locked, &board.CreatedOn, &board.Anonymous, &board.ForcedAnon, &board.AutosageAfter, &board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed, &board.RedirectToThread, &board.RequireFile, &board.EnableCatalog), false)
err = rows.Scan(&board.ID, &board.Section, &board.Dir, &board.ListOrder, &board.Title, &board.Subtitle, &board.Description, &board.MaxFilesize, &board.DefaultStyle, &board.Locked, &board.CreatedOn, &board.Anonymous, &board.ForcedAnon, &board.AutosageAfter, &board.NoImagesAfter, &board.MaxMessageLength, &board.EmbedsAllowed, &board.RedirectToThread, &board.RequireFile, &board.EnableCatalog)
if err != nil {
return nil, err
}
@ -961,20 +956,20 @@ func GetAllBoards() ([]Board, *gcutil.GcError) {
//GetBoardFromID returns the board corresponding to a given id
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
func GetBoardFromID(boardID int) (Board, *gcutil.GcError) {
func GetBoardFromID(boardID int) (Board, error) {
var board Board
err := board.PopulateData(boardID)
return board, err
}
func getBoardIDFromURI(URI string) (id int, err *gcutil.GcError) {
func getBoardIDFromURI(URI string) (id int, err error) {
const sql = `SELECT id FROM DBPREFIXboards WHERE uri = ?`
err = QueryRowSQL(sql, interfaceSlice(URI), interfaceSlice(&id))
return id, err
}
//getDatabaseVersion gets the version of the database, or an error if none or multiple exist
func getDatabaseVersion() (int, *gcutil.GcError) {
func getDatabaseVersion() (int, error) {
const countsql = `SELECT COUNT(version) FROM DBPREFIXdatabase_version`
var count int
err := QueryRowSQL(countsql, interfaceSlice(), interfaceSlice(&count))
@ -990,13 +985,13 @@ func getDatabaseVersion() (int, *gcutil.GcError) {
return version, err
}
func getNextFreeID(tableName string) (ID int, err *gcutil.GcError) {
func getNextFreeID(tableName string) (ID int, err error) {
var sql = `SELECT COALESCE(MAX(id), 0) + 1 FROM ` + tableName
err = QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&ID))
return ID, err
}
func doesTableExist(tableName string) (bool, *gcutil.GcError) {
func doesTableExist(tableName string) (bool, error) {
const mysqlPostgresql = `SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = ?`
@ -1019,14 +1014,14 @@ func doesTableExist(tableName string) (bool, *gcutil.GcError) {
var count int
err := QueryRowSQL(sql, []interface{}{config.Config.DBprefix + tableName}, []interface{}{&count})
if err != nil {
return false, gcutil.FromError(err, false)
return false, err
}
return count == 1, nil
}
//doesGochanPrefixTableExist returns true if any table with a gochan prefix was found.
//Returns false if the prefix is an empty string
func doesGochanPrefixTableExist() (bool, *gcutil.GcError) {
func doesGochanPrefixTableExist() (bool, error) {
if config.Config.DBprefix == "" {
return false, nil
}
@ -1052,18 +1047,18 @@ func doesGochanPrefixTableExist() (bool, *gcutil.GcError) {
var count int
err := QueryRowSQL(sql, []interface{}{}, []interface{}{&count})
if err != nil {
return false, gcutil.FromError(err, false)
return false, err
}
return count > 0, nil
}
func renameTable(tablename string, tableNameNew string) *gcutil.GcError {
func renameTable(tablename string, tableNameNew string) error {
var sql = "ALTER TABLE DBPREFIX" + tablename + " RENAME TO DBPREFIX" + tableNameNew
_, err := ExecSQL(sql)
return err
}
func dropTable(tablename string) *gcutil.GcError {
func dropTable(tablename string) error {
var sql = "DROP TABLE DBPREFIX" + tablename
_, err := ExecSQL(sql)
return err

View file

@ -18,7 +18,7 @@ Before reporting an error, make sure that you are using the up to date version o
Error text: %s`
)
func sqlVersionErr(err error, query *string) *gcutil.GcError {
func sqlVersionErr(err error, query *string) error {
if err == nil {
return nil
}
@ -26,25 +26,25 @@ func sqlVersionErr(err error, query *string) *gcutil.GcError {
switch dbDriver {
case "mysql":
if !strings.Contains(errText, "You have an error in your SQL syntax") {
return gcutil.FromError(err, false)
return err
}
case "postgres":
if !strings.Contains(errText, "syntax error at or near") {
return gcutil.FromError(err, false)
return err
}
case "sqlite3":
if !strings.Contains(errText, "Error: near ") {
return gcutil.FromError(err, false)
return err
}
}
if config.Config.DebugMode {
return gcutil.NewError(fmt.Sprintf(unsupportedSQLVersionMsg+"\nQuery: "+*query, errText), false)
return fmt.Errorf(unsupportedSQLVersionMsg+"\nQuery: "+*query, errText)
}
return gcutil.NewError(fmt.Sprintf(unsupportedSQLVersionMsg, errText), false)
return fmt.Errorf(unsupportedSQLVersionMsg, errText)
}
// PrepareSQL is used for generating a prepared SQL statement formatted according to config.DBtype
func PrepareSQL(query string) (*sql.Stmt, *gcutil.GcError) {
func PrepareSQL(query string) (*sql.Stmt, error) {
var preparedStr string
switch dbDriver {
case "mysql":
@ -84,14 +84,13 @@ Example:
result, err := gcsql.ExecSQL(
"INSERT INTO tablename (intval,stringval) VALUES(?,?)", intVal, stringVal)
*/
func ExecSQL(query string, values ...interface{}) (sql.Result, *gcutil.GcError) {
func ExecSQL(query string, values ...interface{}) (sql.Result, error) {
stmt, gcerr := PrepareSQL(query)
if gcerr != nil {
return nil, gcerr
}
defer stmt.Close()
res, err := stmt.Exec(values...)
return res, gcutil.FromError(err, false)
return stmt.Exec(values...)
}
/*
@ -105,13 +104,13 @@ Example:
[]interface{}{&id},
[]interface{}{&intVal, &stringVal})
*/
func QueryRowSQL(query string, values []interface{}, out []interface{}) *gcutil.GcError {
func QueryRowSQL(query string, values []interface{}, out []interface{}) error {
stmt, err := PrepareSQL(query)
if err != nil {
return err
}
defer stmt.Close()
return gcutil.FromError(stmt.QueryRow(values...).Scan(out...), false)
return stmt.QueryRow(values...).Scan(out...)
}
/*
@ -128,14 +127,13 @@ Example:
}
}
*/
func QuerySQL(query string, a ...interface{}) (*sql.Rows, *gcutil.GcError) {
func QuerySQL(query string, a ...interface{}) (*sql.Rows, error) {
stmt, gcerr := PrepareSQL(query)
if gcerr != nil {
return nil, gcerr
}
defer stmt.Close()
rows, err := stmt.Query(a...)
return rows, gcutil.FromError(err, false)
return stmt.Query(a...)
}
// ResetBoardSectionArrays is run when the board list needs to be changed
@ -156,18 +154,18 @@ func interfaceSlice(args ...interface{}) []interface{} {
return args
}
func errFilterDuplicatePrimaryKey(err *gcutil.GcError) (isPKerror bool, nonPKerror *gcutil.GcError) {
func errFilterDuplicatePrimaryKey(err error) (isPKerror bool, nonPKerror error) {
if err == nil {
return false, nil
}
switch dbDriver {
case "mysql":
if !strings.Contains(err.Message, "Duplicate entry") {
if !strings.Contains(err.Error(), "Duplicate entry") {
return false, err
}
case "postgres":
if !strings.Contains(err.Message, "duplicate key value violates unique constraint") {
if !strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
return false, err
}
case "sqlite3":

View file

@ -19,9 +19,7 @@ import (
const targetDatabaseVersion = 1
var notImplemented = gcutil.NewError("Not implemented", false)
func handleVersioning(dbType string) *gcutil.GcError {
func handleVersioning(dbType string) error {
versionTableExists, err := doesTableExist("database_version")
if err != nil {
return err
@ -59,13 +57,13 @@ func handleVersioning(dbType string) *gcutil.GcError {
}
func buildNewDatabase(dbType string) {
var err *gcutil.GcError
var err error
if err = initDB("initdb_" + dbType + ".sql"); err != nil {
gclog.Print(fatalSQLFlags, "Failed initializing DB: ", err.Error())
}
err = CreateDefaultBoardIfNoneExist()
if err != nil {
gclog.Print(fatalSQLFlags, "Failed creating default board: ", err.Message)
gclog.Print(fatalSQLFlags, "Failed creating default board: ", err.Error())
}
err = CreateDefaultAdminIfNoStaff()
if err != nil {
@ -73,7 +71,7 @@ func buildNewDatabase(dbType string) {
}
}
func versionHandler(foundDatabaseVersion int) *gcutil.GcError {
func versionHandler(foundDatabaseVersion int) error {
if foundDatabaseVersion < targetDatabaseVersion {
for foundDatabaseVersion < targetDatabaseVersion {
gclog.Print(gclog.LStdLog, "Migrating database from version %v to version %v", foundDatabaseVersion, foundDatabaseVersion+1)
@ -96,7 +94,7 @@ func versionHandler(foundDatabaseVersion int) *gcutil.GcError {
}
func migratePreApril2020Database(dbType string) *gcutil.GcError {
func migratePreApril2020Database(dbType string) error {
var tables = []string{"announcements", "appeals", "banlist", "boards", "embeds", "info", "links", "posts", "reports", "sections", "sessions", "staff", "wordfilters"}
for _, i := range tables {
err := renameTable(i, i+"_old")
@ -127,4 +125,4 @@ func migratePreApril2020Database(dbType string) *gcutil.GcError {
return nil
}
var migrations = map[int]func() *gcutil.GcError{}
var migrations = map[int]func() error{}

View file

@ -6,8 +6,6 @@ import (
"os"
"path"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
)
@ -28,7 +26,7 @@ var (
ThreadPage *template.Template
)
func loadTemplate(files ...string) (*template.Template, *gcutil.GcError) {
func loadTemplate(files ...string) (*template.Template, error) {
var templates []string
for i, file := range files {
templates = append(templates, file)
@ -41,21 +39,20 @@ func loadTemplate(files ...string) (*template.Template, *gcutil.GcError) {
}
}
tmpl, err := template.New(templates[0]).Funcs(funcMap).ParseFiles(files...)
return tmpl, gcutil.FromError(err, false)
return template.New(templates[0]).Funcs(funcMap).ParseFiles(files...)
}
func templateError(name string, err error) *gcutil.GcError {
func templateError(name string, err error) error {
if err == nil {
return nil
}
return gcutil.NewError(fmt.Sprintf("Failed loading template '%s/%s': %s",
config.Config.TemplateDir, name, err.Error()), false)
return fmt.Errorf("Failed loading template '%s/%s': %s",
config.Config.TemplateDir, name, err.Error())
}
// InitTemplates loads the given templates by name. If no parameters are given,
// or the first one is "all", all templates are (re)loaded
func InitTemplates(which ...string) *gcutil.GcError {
func InitTemplates(which ...string) error {
gcsql.ResetBoardSectionArrays()
if len(which) == 0 || which[0] == "all" {
return templateLoading("", true)
@ -69,8 +66,8 @@ func InitTemplates(which ...string) *gcutil.GcError {
return nil
}
func templateLoading(t string, buildAll bool) *gcutil.GcError {
var err *gcutil.GcError
func templateLoading(t string, buildAll bool) error {
var err error
if buildAll || t == "banpage" {
Banpage, err = loadTemplate("banpage.html", "page_footer.html")
if err != nil {

View file

@ -1,106 +0,0 @@
package gcutil
import (
"encoding/json"
)
var (
// ErrNotImplemented should be used for unimplemented functionality when necessary
ErrNotImplemented = NewError("Not implemented", true)
)
// GcError is an error type that can be rendered as a regular string or a JSON string
// and can be treated as a regular error if needed
type GcError struct {
Message string `json:"error"`
UserError bool `json:"userError"`
SubErrors []*GcError `json:"childErrors"`
}
// NewError creates a new GcError from a string
func NewError(message string, userCaused bool) *GcError {
if message == "" {
return nil
}
return &GcError{message, userCaused, nil}
}
// FromError creates a new GcError from an error type
func FromError(err error, userCaused bool) *GcError {
if err == nil {
return nil
}
return &GcError{err.Error(), userCaused, nil}
}
// JoinErrors joins multiple GcErrors into a single GcError, with the first one as the parent
func JoinErrors(gce ...*GcError) *GcError {
if len(gce) == 0 {
return nil
}
parent := gce[0]
for e := range gce {
if gce[e] != nil && e > 0 {
parent.SubErrors = append(parent.SubErrors, gce[e])
}
}
return parent
}
func (gce *GcError) addError(user bool, err ...interface{}) {
for _, eI := range err {
if err == nil {
continue
}
eStr, ok := eI.(string)
if ok {
gce.SubErrors = append(gce.SubErrors, &GcError{eStr, user, nil})
continue
}
eErr, ok := eI.(error)
if ok {
gce.SubErrors = append(gce.SubErrors, &GcError{eErr.Error(), user, nil})
}
}
}
// AddChildError creates a new GcError object, adds it to the SubErrors array, and returns it
func (gce *GcError) AddChildError(err error, userCaused bool) *GcError {
if err == nil {
return nil
}
child := FromError(err, userCaused)
gce.SubErrors = append(gce.SubErrors, child)
return child
}
// AddSystemError adds adds the supplied errors (can be strings or errors) as child errors
func (gce *GcError) AddSystemError(err ...interface{}) {
gce.addError(false, err...)
}
// AddUserError adds adds the supplied errors (can be strings or errors) as child errors
func (gce *GcError) AddUserError(err ...interface{}) {
gce.addError(true, err...)
}
func (gce GcError) Error() string {
return gce.Message
}
// JSON returns a JSON string representing the error
func (gce *GcError) JSON() string {
ba, _ := json.Marshal(gce)
return string(ba)
}
// CompareErrors returns true if the given errors have the same error message
func CompareErrors(err1 error, err2 error) bool {
if err1 == nil && err2 == nil {
return true
}
if err1 != nil {
return err1.Error() == err2.Error()
}
return false
}

View file

@ -1,26 +0,0 @@
package gcutil
import (
"io"
"testing"
)
func runErrorTests(name string, err *GcError, t *testing.T) {
t.Log(name, "(pass as interface)", err)
if err != nil {
t.Log(name, ".Error()", err.Error())
t.Log(name, ".JSON()", err.JSON())
}
t.Log()
}
func TestNewError(t *testing.T) {
err := NewError("error message", false)
runErrorTests("NewError", err, t)
wrappedNil := FromError(nil, false)
runErrorTests("Wrapped nil", wrappedNil, t)
wrappedEOF := FromError(io.EOF, false)
runErrorTests("Wrapped EOF", wrappedEOF, t)
joined := JoinErrors(err, wrappedNil, wrappedEOF)
runErrorTests("Joined errors", joined, t)
}

View file

@ -39,25 +39,25 @@ func canMinify(mediaType string) bool {
}
// MinifyTemplate minifies the given template/data (if enabled) and returns any errors
func MinifyTemplate(tmpl *template.Template, data interface{}, writer io.Writer, mediaType string) *GcError {
func MinifyTemplate(tmpl *template.Template, data interface{}, writer io.Writer, mediaType string) error {
if !canMinify(mediaType) {
return FromError(tmpl.Execute(writer, data), false)
return tmpl.Execute(writer, data)
}
minWriter := minifier.Writer(mediaType, writer)
defer minWriter.Close()
return FromError(tmpl.Execute(minWriter, data), false)
return tmpl.Execute(minWriter, data)
}
// MinifyWriter minifies the given writer/data (if enabled) and returns the number of bytes written and any errors
func MinifyWriter(writer io.Writer, data []byte, mediaType string) (int, *GcError) {
func MinifyWriter(writer io.Writer, data []byte, mediaType string) (int, error) {
if !canMinify(mediaType) {
n, err := writer.Write(data)
return n, FromError(err, false)
return n, err
}
minWriter := minifier.Writer(mediaType, writer)
defer minWriter.Close()
n, err := minWriter.Write(data)
return n, FromError(err, false)
return n, err
}

View file

@ -4,6 +4,7 @@ import (
"crypto/md5"
"crypto/sha1"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -22,8 +23,10 @@ import (
)
var (
ErrEmptyDurationString = NewError("Empty Duration string", true)
ErrInvalidDurationString = NewError("Invalid Duration string", true)
// ErrNotImplemented should be used for unimplemented functionality when necessary
ErrNotImplemented = errors.New("Not implemented")
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?)?$`)
)
@ -176,7 +179,7 @@ func MarshalJSON(data interface{}, indent bool) (string, error) {
// ParseDurationString parses the given string into a duration and returns any errors
// based on TinyBoard's parse_time function
func ParseDurationString(str string) (time.Duration, *GcError) {
func ParseDurationString(str string) (time.Duration, error) {
if str == "" {
return 0, ErrEmptyDurationString
}
@ -215,8 +218,8 @@ func ParseDurationString(str string) (time.Duration, *GcError) {
seconds, _ := strconv.Atoi(matches[0][14])
expire += seconds
}
dur, gErr := time.ParseDuration(strconv.Itoa(expire) + "s")
return dur, FromError(gErr, false)
dur, err := time.ParseDuration(strconv.Itoa(expire) + "s")
return dur, err
}
// ParseName takes a name string from a request object and returns the name and tripcode parts

View file

@ -3,6 +3,7 @@ package manage
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"html"
"io/ioutil"
@ -31,30 +32,32 @@ var (
// ManageFunction represents the functions accessed by staff members at /manage?action=<functionname>.
type ManageFunction struct {
Title string
Permissions int // 0 -> non-staff, 1 => janitor, 2 => moderator, 3 => administrator
Callback func(writer http.ResponseWriter, request *http.Request) (string, *gcutil.GcError) `json:"-"` //return string of html output
Permissions int // 0 -> non-staff, 1 => janitor, 2 => moderator, 3 => administrator
Callback func(writer http.ResponseWriter, request *http.Request) (string, error) `json:"-"` //return string of html output
}
var manageFunctions = map[string]ManageFunction{
"cleanup": {
Title: "Cleanup",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
htmlOut = `<h2 class="manage-header">Cleanup</h2><br />`
if request.FormValue("run") == "Run Cleanup" {
htmlOut += "Removing deleted posts from the database.<hr />"
if err = gcsql.PermanentlyRemoveDeletedPosts(); err != nil {
err.Message = gclog.Print(gclog.LErrorLog, "Error removing deleted posts from database: ", err.Message)
return htmlOut + "<tr><td>" + err.Message + "</td></tr></table>", err
err = errors.New(
gclog.Print(gclog.LErrorLog, "Error removing deleted posts from database: ", err.Error()))
return htmlOut + "<tr><td>" + err.Error() + "</td></tr></table>", err
}
// TODO: remove orphaned replies and uploads
htmlOut += "Optimizing all tables in database.<hr />"
err = gcsql.OptimizeDatabase()
if err != nil {
err.Message = gclog.Print(gclog.LErrorLog, "Error optimizing SQL tables: ", err.Error())
return htmlOut + "<tr><td>" + err.Message + "</td></tr></table>", err
err = errors.New(
gclog.Print(gclog.LErrorLog, "Error optimizing SQL tables: ", err.Error()))
return htmlOut + "<tr><td>" + err.Error() + "</td></tr></table>", err
}
htmlOut += "Cleanup finished"
@ -68,7 +71,7 @@ var manageFunctions = map[string]ManageFunction{
"config": {
Title: "Configuration",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
do := request.FormValue("do")
var status string
if do == "save" {
@ -271,12 +274,11 @@ var manageFunctions = map[string]ManageFunction{
}
}
manageConfigBuffer := bytes.NewBufferString("")
if err = gcutil.FromError(gctemplates.ManageConfig.Execute(manageConfigBuffer,
map[string]interface{}{"config": config.Config, "status": status}), false,
); err != nil {
err.Message = gclog.Print(gclog.LErrorLog,
"Error executing config management page: ", err.Message)
return htmlOut + err.Message, err
if err = gctemplates.ManageConfig.Execute(manageConfigBuffer,
map[string]interface{}{"config": config.Config, "status": status}); err != nil {
err = errors.New(gclog.Print(gclog.LErrorLog,
"Error executing config management page: ", err.Error()))
return htmlOut + err.Error(), err
}
htmlOut += manageConfigBuffer.String()
return htmlOut, nil
@ -284,7 +286,7 @@ var manageFunctions = map[string]ManageFunction{
"login": {
Title: "Login",
Permissions: 0,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
if GetStaffRank(request) > 0 {
http.Redirect(writer, request, path.Join(config.Config.SiteWebfolder, "manage"), http.StatusFound)
}
@ -312,7 +314,7 @@ var manageFunctions = map[string]ManageFunction{
"logout": {
Title: "Logout",
Permissions: 1,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
cookie, _ := request.Cookie("sessiondata")
cookie.MaxAge = 0
cookie.Expires = time.Now().Add(-7 * 24 * time.Hour)
@ -322,7 +324,7 @@ var manageFunctions = map[string]ManageFunction{
"announcements": {
Title: "Announcements",
Permissions: 1,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
htmlOut = `<h1 class="manage-header">Announcements</h1><br />`
//get all announcements to announcement list
@ -345,7 +347,7 @@ var manageFunctions = map[string]ManageFunction{
"bans": {
Title: "Bans",
Permissions: 1,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) { //TODO whatever this does idk man
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) { //TODO whatever this does idk man
var post gcsql.Post
if request.FormValue("do") == "add" {
ip := request.FormValue("ip")
@ -357,7 +359,6 @@ var manageFunctions = map[string]ManageFunction{
permaban := (durationForm == "" || durationForm == "0" || durationForm == "forever")
duration, err := gcutil.ParseDurationString(durationForm)
if err != nil {
err.UserError = true
return "", err
}
expires := time.Now().Add(duration)
@ -403,49 +404,48 @@ var manageFunctions = map[string]ManageFunction{
}
if request.FormValue("postid") != "" {
var err *gcutil.GcError
var err error
post, err = gcsql.GetSpecificPostByString(request.FormValue("postid"))
if err != nil {
err.Message = "Error getting post: " + err.Message
err = errors.New("Error getting post: " + err.Error())
return "", err
}
}
banlist, err := gcsql.GetAllBans()
if err != nil {
err.Message = "Error getting ban list: " + err.Message
err = errors.New("Error getting ban list: " + err.Error())
return "", err
}
manageBansBuffer := bytes.NewBufferString("")
if err = gcutil.FromError(gctemplates.ManageBans.Execute(manageBansBuffer,
if err = gctemplates.ManageBans.Execute(manageBansBuffer,
map[string]interface{}{"config": config.Config, "banlist": banlist, "post": post},
), false); err != nil {
err.Message = "Error executing ban management page template: " + err.Message
return "", err
); err != nil {
return "", errors.New("Error executing ban management page template: " + err.Error())
}
htmlOut += manageBansBuffer.String()
return
}},
"getstaffjquery": {
Permissions: 0,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
staff, err := getCurrentFullStaff(request)
if err != nil {
return err.JSON(), err
htmlOut, _ = gcutil.MarshalJSON(err, false)
return htmlOut, nil
}
htmlOut, gErr := gcutil.MarshalJSON(staff, false)
return htmlOut, gcutil.FromError(gErr, false)
return gcutil.MarshalJSON(staff, false)
}},
"boards": {
Title: "Boards",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
do := request.FormValue("do")
var done bool
board := new(gcsql.Board)
var boardCreationStatus string
var gErr error
for !done {
switch {
case do == "add":
@ -456,8 +456,7 @@ var manageFunctions = map[string]ManageFunction{
continue
}
orderStr := request.FormValue("order")
board.ListOrder, gErr = strconv.Atoi(orderStr)
if gErr != nil {
if board.ListOrder, err = strconv.Atoi(orderStr); err != nil {
board.ListOrder = 0
}
board.Title = request.FormValue("title")
@ -474,17 +473,17 @@ var manageFunctions = map[string]ManageFunction{
}
board.CreatedOn = time.Now()
board.Section, gErr = strconv.Atoi(sectionStr)
if gErr != nil {
board.Section, err = strconv.Atoi(sectionStr)
if err != nil {
board.Section = 0
}
board.MaxFilesize, gErr = strconv.Atoi(request.FormValue("maximagesize"))
board.MaxFilesize, err = strconv.Atoi(request.FormValue("maximagesize"))
if err != nil {
board.MaxFilesize = 1024 * 4
}
board.MaxPages, gErr = strconv.Atoi(request.FormValue("maxpages"))
if gErr != nil {
board.MaxPages, err = strconv.Atoi(request.FormValue("maxpages"))
if err != nil {
board.MaxPages = 11
}
@ -497,23 +496,23 @@ var manageFunctions = map[string]ManageFunction{
board.Anonymous = "Anonymous"
}
board.MaxAge, gErr = strconv.Atoi(request.FormValue("maxage"))
if gErr != nil {
board.MaxAge, err = strconv.Atoi(request.FormValue("maxage"))
if err != nil {
board.MaxAge = 0
}
board.AutosageAfter, gErr = strconv.Atoi(request.FormValue("autosageafter"))
if gErr != nil {
board.AutosageAfter, err = strconv.Atoi(request.FormValue("autosageafter"))
if err != nil {
board.AutosageAfter = 200
}
board.NoImagesAfter, gErr = strconv.Atoi(request.FormValue("noimagesafter"))
if gErr != nil {
board.NoImagesAfter, err = strconv.Atoi(request.FormValue("noimagesafter"))
if err != nil {
board.NoImagesAfter = 0
}
board.MaxMessageLength, gErr = strconv.Atoi(request.FormValue("maxmessagelength"))
if gErr != nil {
board.MaxMessageLength, err = strconv.Atoi(request.FormValue("maxmessagelength"))
if err != nil {
board.MaxMessageLength = 1024 * 8
}
@ -523,37 +522,37 @@ var manageFunctions = map[string]ManageFunction{
board.EnableCatalog = (request.FormValue("enablecatalog") == "on")
//actually start generating stuff
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir), 0666); gErr != nil {
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir), 0666); err != nil {
do = ""
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/ already exists.",
config.Config.DocumentRoot, board.Dir)
break
}
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "res"), 0666); gErr != nil {
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "res"), 0666); err != nil {
do = ""
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/res/ already exists.",
config.Config.DocumentRoot, board.Dir)
break
}
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "src"), 0666); gErr != nil {
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "src"), 0666); err != nil {
do = ""
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/src/ already exists.",
config.Config.DocumentRoot, board.Dir)
break
}
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "thumb"), 0666); gErr != nil {
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "thumb"), 0666); err != nil {
do = ""
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/thumb/ already exists.",
config.Config.DocumentRoot, board.Dir)
break
}
if gErr = gcsql.CreateBoard(board); err != nil {
if err = gcsql.CreateBoard(board); err != nil {
do = ""
boardCreationStatus = gclog.Print(gclog.LErrorLog, "Error creating board: ", gErr.Error())
boardCreationStatus = gclog.Print(gclog.LErrorLog, "Error creating board: ", err.Error())
break
} else {
boardCreationStatus = "Board created successfully"
@ -585,8 +584,8 @@ var manageFunctions = map[string]ManageFunction{
var boards []string
boards, err = gcsql.GetBoardUris()
if err != nil {
err.Message = gclog.Print(gclog.LErrorLog,
"Error getting board list: ", err.Message)
err = errors.New(gclog.Print(gclog.LErrorLog,
"Error getting board list: ", err.Error()))
return "", err
}
for _, boardDir := range boards {
@ -599,13 +598,13 @@ var manageFunctions = map[string]ManageFunction{
manageBoardsBuffer := bytes.NewBufferString("")
gcsql.AllSections, _ = gcsql.GetAllSectionsOrCreateDefault()
if err = gcutil.FromError(gctemplates.ManageBoards.Execute(manageBoardsBuffer, map[string]interface{}{
if err = gctemplates.ManageBoards.Execute(manageBoardsBuffer, map[string]interface{}{
"config": config.Config,
"board": board,
"section_arr": gcsql.AllSections,
}), false); err != nil {
err.Message = gclog.Print(gclog.LErrorLog,
"Error executing board management page template: ", err.Message)
}); err != nil {
err = errors.New(gclog.Print(gclog.LErrorLog,
"Error executing board management page template: ", err.Error()))
return "", err
}
htmlOut += manageBoardsBuffer.String()
@ -617,7 +616,7 @@ var manageFunctions = map[string]ManageFunction{
"staffmenu": {
Title: "Staff menu",
Permissions: 1,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
rank := GetStaffRank(request)
htmlOut = `<a href="javascript:void(0)" id="logout" class="staffmenu-item">Log out</a><br />` +
@ -648,7 +647,7 @@ var manageFunctions = map[string]ManageFunction{
"rebuildfront": {
Title: "Rebuild front page",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
if err = gctemplates.InitTemplates(); err != nil {
return "", err
}
@ -657,7 +656,7 @@ var manageFunctions = map[string]ManageFunction{
"rebuildall": {
Title: "Rebuild everything",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
gctemplates.InitTemplates()
gcsql.ResetBoardSectionArrays()
if err = building.BuildFrontPage(); err != nil {
@ -681,7 +680,7 @@ var manageFunctions = map[string]ManageFunction{
"rebuildboards": {
Title: "Rebuild boards",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
if err = gctemplates.InitTemplates(); err != nil {
return "", err
}
@ -690,7 +689,7 @@ var manageFunctions = map[string]ManageFunction{
"reparsehtml": {
Title: "Reparse HTML",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
messages, err := gcsql.GetAllNondeletedMessageRaw()
if err != nil {
return "", err
@ -723,7 +722,7 @@ var manageFunctions = map[string]ManageFunction{
"recentposts": {
Title: "Recent posts",
Permissions: 1,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
limit := request.FormValue("limit")
if limit == "" {
limit = "50"
@ -737,7 +736,7 @@ var manageFunctions = map[string]ManageFunction{
recentposts, err := gcsql.GetRecentPostsGlobal(gcutil.HackyStringToInt(limit), false) //only uses boardname, boardid, postid, parentid, message, ip and timestamp
if err != nil {
err.Message = "Error getting recent posts: " + err.Message
err = errors.New("Error getting recent posts: " + err.Error())
return "", err
}
@ -755,11 +754,12 @@ var manageFunctions = map[string]ManageFunction{
"postinfo": {
Title: "Post info",
Permissions: 2,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
var post gcsql.Post
post, err = gcsql.GetSpecificPost(gcutil.HackyStringToInt(request.FormValue("postid")), false)
if err != nil {
return err.JSON(), nil
htmlOut, _ = gcutil.MarshalJSON(err, false)
return htmlOut, nil
}
jsonStr, _ := gcutil.MarshalJSON(post, false)
return jsonStr, nil
@ -767,7 +767,7 @@ var manageFunctions = map[string]ManageFunction{
"staff": {
Title: "Staff",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
var allStaff []gcsql.Staff
do := request.FormValue("do")
htmlOut = `<h1 class="manage-header">Staff</h1><br />` +
@ -775,7 +775,8 @@ var manageFunctions = map[string]ManageFunction{
"<tr><td><b>Username</b></td><td><b>Rank</b></td><td><b>Boards</b></td><td><b>Added on</b></td><td><b>Action</b></td></tr>"
allStaff, err = gcsql.GetAllStaffNopass()
if err != nil {
err.Message = gclog.Print(gclog.LErrorLog, "Error getting staff list: ", err.Message)
err = errors.New(
gclog.Print(gclog.LErrorLog, "Error getting staff list: ", err.Error()))
return "", err
}
@ -828,7 +829,7 @@ var manageFunctions = map[string]ManageFunction{
"tempposts": {
Title: "Temporary posts lists",
Permissions: 3,
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err error) {
htmlOut += `<h1 class="manage-header">Temporary posts</h1>`
if len(gcsql.TempPosts) == 0 {
htmlOut += "No temporary posts<br />"

View file

@ -7,18 +7,16 @@ import (
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gclog"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
)
// CallManageFunction is called when a user accesses /manage to use manage tools
// or log in to a staff account
func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
var err *gcutil.GcError
var gErr error
if gErr = request.ParseForm(); gErr != nil {
var err error
if err = request.ParseForm(); err != nil {
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog,
"Error parsing form data: ", gErr.Error()))
"Error parsing form data: ", err.Error()))
}
action := request.FormValue("action")
@ -29,9 +27,9 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
} else {
managePageBuffer.WriteString("<!DOCTYPE html><html><head>")
if gErr = gctemplates.ManageHeader.Execute(&managePageBuffer, config.Config); gErr != nil {
if err = gctemplates.ManageHeader.Execute(&managePageBuffer, config.Config); err != nil {
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog|gclog.LStaffLog,
"Error executing manage page header template: ", gErr.Error()))
"Error executing manage page header template: ", err.Error()))
return
}
}

View file

@ -7,7 +7,6 @@ import (
"github.com/gochan-org/gochan/pkg/gclog"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/serverutil"
"golang.org/x/crypto/bcrypt"
)
@ -21,7 +20,7 @@ const (
func createSession(key string, username string, password string, request *http.Request, writer http.ResponseWriter) int {
//returns 0 for successful, 1 for password mismatch, and 2 for other
domain := request.Host
var err *gcutil.GcError
var err error
domain = chopPortNumRegex.Split(domain, -1)[0]
if !serverutil.ValidReferer(request) {
@ -58,22 +57,22 @@ func createSession(key string, username string, password string, request *http.R
return sSuccess
}
func getCurrentStaff(request *http.Request) (string, *gcutil.GcError) { //TODO after refactor, check if still used
func getCurrentStaff(request *http.Request) (string, error) { //TODO after refactor, check if still used
sessionCookie, err := request.Cookie("sessiondata")
if err != nil {
return "", gcutil.FromError(err, true)
return "", err
}
name, err := gcsql.GetStaffName(sessionCookie.Value)
if err == nil {
return "", gcutil.FromError(err, true)
return "", err
}
return name, nil
}
func getCurrentFullStaff(request *http.Request) (*gcsql.Staff, *gcutil.GcError) {
func getCurrentFullStaff(request *http.Request) (*gcsql.Staff, error) {
sessionCookie, err := request.Cookie("sessiondata")
if err != nil {
return nil, gcutil.FromError(err, true)
return nil, err
}
return gcsql.GetStaffBySession(sessionCookie.Value)
}

View file

@ -62,7 +62,7 @@ func BanHandler(writer http.ResponseWriter, request *http.Request) {
// Checks check poster's name/tripcode/file checksum (from Post post) for banned status
// returns ban table if the user is banned or sql.ErrNoRows if they aren't
func getBannedStatus(request *http.Request) (*gcsql.BanInfo, *gcutil.GcError) {
func getBannedStatus(request *http.Request) (*gcsql.BanInfo, error) {
formName := request.FormValue("postname")
var tripcode string
if formName != "" {
@ -76,10 +76,10 @@ func getBannedStatus(request *http.Request) (*gcsql.BanInfo, *gcutil.GcError) {
var filename string
var checksum string
file, fileHandler, gErr := request.FormFile("imagefile")
if gErr == nil {
file, fileHandler, err := request.FormFile("imagefile")
if err == nil {
html.EscapeString(fileHandler.Filename)
if data, gErr2 := ioutil.ReadAll(file); gErr2 == nil {
if data, err2 := ioutil.ReadAll(file); err2 == nil {
checksum = fmt.Sprintf("%x", md5.Sum(data))
}
file.Close()

View file

@ -75,7 +75,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
post.Subject = request.FormValue("postsubject")
post.MessageText = strings.Trim(request.FormValue("postmsg"), "\r\n")
var err *gcutil.GcError
var err error
if maxMessageLength, err = gcsql.GetMaxMessageLength(post.BoardID); err != nil {
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog,
"Error getting board info: ", err.Error()))
@ -127,18 +127,18 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
default:
}
file, handler, gErr := request.FormFile("imagefile")
file, handler, err := request.FormFile("imagefile")
if gErr != nil || handler.Size == 0 {
if err != nil || handler.Size == 0 {
// no file was uploaded
post.Filename = ""
gclog.Printf(gclog.LAccessLog,
"Receiving post from %s, referred from: %s", post.IP, request.Referer())
} else {
data, gErr := ioutil.ReadAll(file)
if gErr != nil {
data, err := ioutil.ReadAll(file)
if err != nil {
serverutil.ServeErrorPage(writer,
gclog.Print(gclog.LErrorLog, "Error while trying to read file: ", gErr.Error()))
gclog.Print(gclog.LErrorLog, "Error while trying to read file: ", err.Error()))
return
}
defer file.Close()
@ -171,8 +171,8 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
thumbPath := path.Join(config.Config.DocumentRoot, "/"+boardDir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "t."+thumbFiletype, -1))
catalogThumbPath := path.Join(config.Config.DocumentRoot, "/"+boardDir+"/thumb/", strings.Replace(post.Filename, "."+filetype, "c."+thumbFiletype, -1))
if gErr = ioutil.WriteFile(filePath, data, 0777); err != nil {
gclog.Printf(gclog.LErrorLog, "Couldn't write file %q: %s", post.Filename, gErr.Error())
if err = ioutil.WriteFile(filePath, data, 0777); err != nil {
gclog.Printf(gclog.LErrorLog, "Couldn't write file %q: %s", post.Filename, err.Error())
serverutil.ServeErrorPage(writer, `Couldn't write file "`+post.FilenameOriginal+`"`)
return
}
@ -335,7 +335,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
}
banStatus, err := getBannedStatus(request)
if err != nil && !gcutil.CompareErrors(err, sql.ErrNoRows) {
if err != nil && err != sql.ErrNoRows {
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog,
"Error getting banned status: ", err.Error()))
return

View file

@ -34,23 +34,22 @@ func tempCleaner() {
}
fileSrc := path.Join(config.Config.DocumentRoot, board.Dir, "src", post.FilenameOriginal)
var gErr error
if gErr = os.Remove(fileSrc); gErr != nil {
if err = os.Remove(fileSrc); err != nil {
gclog.Printf(errStdLogs,
"Error pruning temporary upload for %q: %s", fileSrc, gErr.Error())
"Error pruning temporary upload for %q: %s", fileSrc, err.Error())
}
thumbSrc := gcutil.GetThumbnailPath("thread", fileSrc)
if gErr = os.Remove(thumbSrc); gErr != nil {
if err = os.Remove(thumbSrc); err != nil {
gclog.Printf(errStdLogs,
"Error pruning temporary upload for %q: %s", thumbSrc, gErr.Error())
"Error pruning temporary upload for %q: %s", thumbSrc, err.Error())
}
if post.ParentID == 0 {
catalogSrc := gcutil.GetThumbnailPath("catalog", fileSrc)
if gErr = os.Remove(catalogSrc); gErr != nil {
if err = os.Remove(catalogSrc); err != nil {
gclog.Printf(errStdLogs,
"Error pruning temporary upload for %s: %s", catalogSrc, gErr.Error())
"Error pruning temporary upload for %s: %s", catalogSrc, err.Error())
}
}
}