mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-17 10:56:24 -07:00
replace (most) uses of builtin error with *gcutil.GcError
This commit is contained in:
parent
6d61137f9e
commit
feec3d87e8
17 changed files with 577 additions and 468 deletions
|
@ -2,7 +2,6 @@ package building
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -22,13 +21,18 @@ const (
|
|||
pathExistsStr = `unable to create "%s", path already exists`
|
||||
)
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
// 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) (html string) {
|
||||
func BuildBoardPages(board *gcsql.Board) *gcutil.GcError {
|
||||
err := gctemplates.InitTemplates("boardpage")
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
return err
|
||||
}
|
||||
var currentPageFile *os.File
|
||||
var threads []interface{}
|
||||
|
@ -39,8 +43,8 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
|
||||
// Get all top level posts for the board.
|
||||
if opPosts, err = gcsql.GetTopPosts(board.ID); err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
"Error getting OP posts for /%s/: %s", board.Dir, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error getting OP posts for /%s/: %s", board.Dir, err.Error()), false)
|
||||
}
|
||||
|
||||
// For each top level post, start building a Thread struct
|
||||
|
@ -50,17 +54,17 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
|
||||
var replyCount, err = gcsql.GetReplyCount(op.ID)
|
||||
if err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error getting replies to /%s/%d: %s",
|
||||
board.Dir, op.ID, err.Error()) + "<br />"
|
||||
board.Dir, op.ID, err.Error()), false)
|
||||
}
|
||||
thread.NumReplies = replyCount
|
||||
|
||||
fileCount, err := gcsql.GetReplyFileCount(op.ID)
|
||||
if err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error getting file count to /%s/%d: %s",
|
||||
board.Dir, op.ID, err.Error()) + "<br />"
|
||||
board.Dir, op.ID, err.Error()), false)
|
||||
}
|
||||
thread.NumImages = fileCount
|
||||
|
||||
|
@ -79,9 +83,9 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
|
||||
postsInThread, err = gcsql.GetExistingRepliesLimitedRev(op.ID, numRepliesOnBoardPage)
|
||||
if err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error getting posts in /%s/%d: %s",
|
||||
board.Dir, op.ID, err.Error()) + "<br />"
|
||||
board.Dir, op.ID, err.Error()), false)
|
||||
}
|
||||
|
||||
var reversedPosts []gcsql.Post
|
||||
|
@ -120,12 +124,13 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
// If there are no posts on the board
|
||||
if len(threads) == 0 {
|
||||
board.CurrentPage = 1
|
||||
|
||||
// Open 1.html for writing to the first page.
|
||||
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 html + gclog.Printf(gclog.LErrorLog,
|
||||
"Failed opening /%s/1.html: %s",
|
||||
board.Dir, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Failed opening /%s/board.html: %s",
|
||||
board.Dir, err.Error()), false)
|
||||
}
|
||||
|
||||
// Render board page template to the file,
|
||||
|
@ -137,12 +142,11 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
"threads": threads,
|
||||
"board": board,
|
||||
}, boardPageFile, "text/html"); err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Failed building /%s/: %s",
|
||||
board.Dir, err.Error()) + "<br />"
|
||||
board.Dir, err.Error()), false)
|
||||
}
|
||||
html += "/" + board.Dir + "/ built successfully.\n"
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the archive pages.
|
||||
|
@ -152,10 +156,10 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
// Create array of page wrapper objects, and open the file.
|
||||
pagesArr := make([]map[string]interface{}, board.NumPages)
|
||||
|
||||
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 gclog.Printf(gclog.LErrorLog,
|
||||
"Failed opening /%s/catalog.json: %s", board.Dir, err.Error()) + "<br />"
|
||||
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)
|
||||
}
|
||||
defer catalogJSONFile.Close()
|
||||
|
||||
|
@ -165,10 +169,10 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
var currentPageFilepath string
|
||||
pageFilename := strconv.Itoa(board.CurrentPage) + ".html"
|
||||
currentPageFilepath = path.Join(config.Config.DocumentRoot, board.Dir, pageFilename)
|
||||
currentPageFile, err = os.OpenFile(currentPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
html += gclog.Printf(gclog.LErrorLog, "Failed opening /%s/%s: %s",
|
||||
board.Dir, pageFilename, err.Error()) + "<br />"
|
||||
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()))
|
||||
continue
|
||||
}
|
||||
defer currentPageFile.Close()
|
||||
|
@ -184,8 +188,8 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
gcsql.Post{BoardID: board.ID},
|
||||
},
|
||||
}, currentPageFile, "text/html"); err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
"Failed building /%s/ boardpage: %s", board.Dir, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Failed building /%s/ boardpage: %s", board.Dir, err.Error()), false)
|
||||
}
|
||||
|
||||
// Collect up threads for this page.
|
||||
|
@ -196,45 +200,47 @@ func BuildBoardPages(board *gcsql.Board) (html string) {
|
|||
}
|
||||
board.CurrentPage = currentBoardPage
|
||||
|
||||
catalogJSON, err := json.Marshal(pagesArr)
|
||||
if err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog, "Failed to marshal to JSON: ", err.Error()) + "<br />"
|
||||
catalogJSON, gErr := json.Marshal(pagesArr)
|
||||
if gErr != nil {
|
||||
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
|
||||
"Failed to marshal to JSON: ", gErr.Error()), false)
|
||||
}
|
||||
if _, err = catalogJSONFile.Write(catalogJSON); err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog,
|
||||
"Failed writing /%s/catalog.json: %s", board.Dir, err.Error()) + "<br />"
|
||||
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)
|
||||
}
|
||||
html += "/" + board.Dir + "/ built successfully."
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildBoards builds the specified board IDs, or all boards if no arguments are passed
|
||||
// The return value is a string of HTML with debug information produced by the build process.
|
||||
func BuildBoards(which ...int) (html string) {
|
||||
func BuildBoards(which ...int) *gcutil.GcError {
|
||||
var boards []gcsql.Board
|
||||
var err error
|
||||
var err *gcutil.GcError
|
||||
|
||||
if which == nil {
|
||||
boards = gcsql.AllBoards
|
||||
} else {
|
||||
for b, id := range which {
|
||||
boards = append(boards, gcsql.Board{})
|
||||
if err = boards[b].PopulateData(id); err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog, "Error getting board information (ID: %d)", id)
|
||||
err.Message = gclog.Printf(gclog.LErrorLog, "Error getting board information (ID: %d): %s", id, err.Message)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(boards) == 0 {
|
||||
return "No boards to build."
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, board := range boards {
|
||||
if err = buildBoard(&board, false, true); err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog,
|
||||
"Error building /%s/: %s", board.Dir, err.Error()) + "<br />"
|
||||
err.Message = gclog.Printf(gclog.LErrorLog,
|
||||
"Error building /%s/: %s", board.Dir, err.Error())
|
||||
return err
|
||||
}
|
||||
html += "Built /" + board.Dir + "/ successfully."
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
//BuildCatalog builds the catalog for a board with a given id
|
||||
|
@ -250,10 +256,10 @@ func BuildCatalog(boardID int) string {
|
|||
}
|
||||
|
||||
catalogPath := path.Join(config.Config.DocumentRoot, board.Dir, "catalog.html")
|
||||
catalogFile, err := os.OpenFile(catalogPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
catalogFile, gErr := os.OpenFile(catalogPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if gErr != nil {
|
||||
return gclog.Printf(gclog.LErrorLog,
|
||||
"Failed opening /%s/catalog.html: %s", board.Dir, err.Error()) + "<br />"
|
||||
"Failed opening /%s/catalog.html: %s", board.Dir, gErr.Error()) + "<br />"
|
||||
}
|
||||
|
||||
threadOPs, err := gcsql.GetTopPosts(boardID)
|
||||
|
@ -288,13 +294,13 @@ 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) error {
|
||||
var err error
|
||||
func buildBoard(board *gcsql.Board, newBoard bool, force bool) *gcutil.GcError {
|
||||
var err *gcutil.GcError
|
||||
if board.Dir == "" {
|
||||
return errors.New("board must have a directory before it is built")
|
||||
return ErrNoBoardDir
|
||||
}
|
||||
if board.Title == "" {
|
||||
return errors.New("board must have a title before it is built")
|
||||
return ErrNoBoardTitle
|
||||
}
|
||||
|
||||
dirPath := board.AbsolutePath()
|
||||
|
@ -307,53 +313,65 @@ func buildBoard(board *gcsql.Board, newBoard bool, force bool) error {
|
|||
thumbInfo, _ := os.Stat(thumbPath)
|
||||
if dirInfo != nil {
|
||||
if !force {
|
||||
return fmt.Errorf(pathExistsStr, dirPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
pathExistsStr, dirPath), false)
|
||||
}
|
||||
if !dirInfo.IsDir() {
|
||||
return fmt.Errorf(dirIsAFileStr, dirPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
dirIsAFileStr, dirPath), false)
|
||||
}
|
||||
} else {
|
||||
if err = os.Mkdir(dirPath, 0666); err != nil {
|
||||
return fmt.Errorf(genericErrStr, dirPath, err.Error())
|
||||
if err = gcutil.FromError(os.Mkdir(dirPath, 0666), false); err != nil {
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
genericErrStr, dirPath, err.Error()), false)
|
||||
}
|
||||
}
|
||||
|
||||
if resInfo != nil {
|
||||
if !force {
|
||||
return fmt.Errorf(pathExistsStr, resPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
pathExistsStr, resPath), false)
|
||||
}
|
||||
if !resInfo.IsDir() {
|
||||
return fmt.Errorf(dirIsAFileStr, resPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
dirIsAFileStr, resPath), false)
|
||||
}
|
||||
} else {
|
||||
if err = os.Mkdir(resPath, 0666); err != nil {
|
||||
return fmt.Errorf(genericErrStr, resPath, err.Error())
|
||||
if err = gcutil.FromError(os.Mkdir(resPath, 0666), false); err != nil {
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
genericErrStr, resPath, err.Error()), false)
|
||||
}
|
||||
}
|
||||
|
||||
if srcInfo != nil {
|
||||
if !force {
|
||||
return fmt.Errorf(pathExistsStr, srcPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
pathExistsStr, srcPath), false)
|
||||
}
|
||||
if !srcInfo.IsDir() {
|
||||
return fmt.Errorf(dirIsAFileStr, srcPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
dirIsAFileStr, srcPath), false)
|
||||
}
|
||||
} else {
|
||||
if err = os.Mkdir(srcPath, 0666); err != nil {
|
||||
return fmt.Errorf(genericErrStr, srcPath, err.Error())
|
||||
if err = gcutil.FromError(os.Mkdir(srcPath, 0666), false); err != nil {
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
genericErrStr, srcPath, err.Error()), false)
|
||||
}
|
||||
}
|
||||
|
||||
if thumbInfo != nil {
|
||||
if !force {
|
||||
return fmt.Errorf(pathExistsStr, thumbPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
pathExistsStr, thumbPath), false)
|
||||
}
|
||||
if !thumbInfo.IsDir() {
|
||||
return fmt.Errorf(dirIsAFileStr, thumbPath)
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
dirIsAFileStr, thumbPath), false)
|
||||
}
|
||||
} else {
|
||||
if err = os.Mkdir(thumbPath, 0666); err != nil {
|
||||
return fmt.Errorf(genericErrStr, thumbPath, err.Error())
|
||||
if err = gcutil.FromError(os.Mkdir(thumbPath, 0666), false); err != nil {
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
genericErrStr, thumbPath, err.Error()), false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,22 +14,26 @@ import (
|
|||
)
|
||||
|
||||
// BuildFrontPage builds the front page using templates/front.html
|
||||
func BuildFrontPage() string {
|
||||
func BuildFrontPage() *gcutil.GcError {
|
||||
err := gctemplates.InitTemplates("front")
|
||||
if err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Error loading front page template: ", err.Error())
|
||||
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
|
||||
"Error loading front page template: ", err.Error()), false)
|
||||
}
|
||||
os.Remove(path.Join(config.Config.DocumentRoot, "index.html"))
|
||||
frontFile, err := os.OpenFile(path.Join(config.Config.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Failed opening front page for writing: ", err.Error()) + "<br />"
|
||||
frontFile, gErr := 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)
|
||||
}
|
||||
defer frontFile.Close()
|
||||
|
||||
var recentPostsArr []gcsql.RecentPost
|
||||
recentPostsArr, err = gcsql.GetRecentPostsGlobal(config.Config.MaxRecentPosts, !config.Config.RecentPostsWithNoFile)
|
||||
if err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Failed loading recent posts: "+err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
|
||||
"Failed loading recent posts: "+err.Error()), false)
|
||||
}
|
||||
|
||||
for b := range gcsql.AllBoards {
|
||||
|
@ -44,16 +48,18 @@ func BuildFrontPage() string {
|
|||
"boards": gcsql.AllBoards,
|
||||
"recent_posts": recentPostsArr,
|
||||
}, frontFile, "text/html"); err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Failed executing front page template: "+err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Print(gclog.LErrorLog,
|
||||
"Failed executing front page template: "+err.Error()), false)
|
||||
}
|
||||
return "Front page rebuilt successfully."
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildBoardListJSON generates a JSON file with info about the boards
|
||||
func BuildBoardListJSON() (html string) {
|
||||
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 gclog.Print(gclog.LErrorLog, "Failed opening boards.json for writing: ", err.Error()) + "<br />"
|
||||
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)
|
||||
}
|
||||
defer boardListFile.Close()
|
||||
|
||||
|
@ -72,58 +78,61 @@ func BuildBoardListJSON() (html string) {
|
|||
boardsMap["boards"] = append(boardsMap["boards"], gcsql.AllBoards[b])
|
||||
}
|
||||
|
||||
boardJSON, err := json.Marshal(boardsMap)
|
||||
if err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Failed to create boards.json: ", err.Error()) + "<br />"
|
||||
boardJSON, gErr := json.Marshal(boardsMap)
|
||||
if gErr != nil {
|
||||
return gcutil.NewError(gclog.Print(gclog.LErrorLog, "Failed to create boards.json: ", gErr.Error()), false)
|
||||
}
|
||||
|
||||
if _, err = gcutil.MinifyWriter(boardListFile, boardJSON, "application/json"); err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Failed writing boards.json file: ", err.Error()) + "<br />"
|
||||
_, 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
|
||||
}
|
||||
return "Board list JSON rebuilt successfully.<br />"
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildJS minifies (if enabled) gochan.js and consts.js (the latter is built from a template)
|
||||
func BuildJS() string {
|
||||
func BuildJS() *gcutil.GcError {
|
||||
// minify gochan.js (if enabled)
|
||||
gochanMinJSPath := path.Join(config.Config.DocumentRoot, "javascript", "gochan.min.js")
|
||||
gochanMinJSFile, err := os.OpenFile(gochanMinJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog, "Error opening %q for writing: %s",
|
||||
gochanMinJSPath, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error opening %q for writing: %s", gochanMinJSPath, err.Error()), false)
|
||||
}
|
||||
defer gochanMinJSFile.Close()
|
||||
|
||||
gochanJSPath := path.Join(config.Config.DocumentRoot, "javascript", "gochan.js")
|
||||
gochanJSBytes, err := ioutil.ReadFile(gochanJSPath)
|
||||
if err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog, "Error opening %q for writing: %s",
|
||||
gochanJSPath, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error opening %q for writing: %s", gochanJSPath, err.Error()), false)
|
||||
}
|
||||
if _, err := gcutil.MinifyWriter(gochanMinJSFile, gochanJSBytes, "text/javascript"); err != nil {
|
||||
config.Config.UseMinifiedGochanJS = false
|
||||
return gclog.Printf(gclog.LErrorLog, "Error minifying %q: %s:",
|
||||
gochanMinJSPath, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error minifying %q: %s:", gochanMinJSPath, err.Error()), false)
|
||||
}
|
||||
config.Config.UseMinifiedGochanJS = true
|
||||
|
||||
// build consts.js from template
|
||||
if err = gctemplates.InitTemplates("js"); err != nil {
|
||||
return gclog.Print(gclog.LErrorLog, "Error loading consts.js template: ", err.Error())
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error loading consts.js template: ", err.Error()), false)
|
||||
}
|
||||
constsJSPath := path.Join(config.Config.DocumentRoot, "javascript", "consts.js")
|
||||
constsJSFile, err := os.OpenFile(constsJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog, "Error opening %q for writing: %s",
|
||||
constsJSPath, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error opening %q for writing: %s", constsJSPath, err.Error()), false)
|
||||
}
|
||||
defer constsJSFile.Close()
|
||||
|
||||
if err = gcutil.MinifyTemplate(gctemplates.JsConsts, config.Config, constsJSFile, "text/javascript"); err != nil {
|
||||
return gclog.Printf(gclog.LErrorLog, "Error building %q: %s",
|
||||
constsJSPath, err.Error()) + "<br />"
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error building %q: %s", constsJSPath, err.Error()), true)
|
||||
}
|
||||
return "Built gochan.min.js and consts.js successfully.<br />"
|
||||
return nil
|
||||
}
|
||||
|
||||
// paginate returns a 2d array of a specified interface from a 1d array passed in,
|
||||
|
|
|
@ -2,12 +2,12 @@ package building
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gclog"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gctemplates"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
|
@ -39,7 +39,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) error {
|
||||
func BuildThreadPages(op *gcsql.Post) *gcutil.GcError {
|
||||
err := gctemplates.InitTemplates("threadpage")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -54,7 +54,8 @@ func BuildThreadPages(op *gcsql.Post) error {
|
|||
|
||||
replies, err = gcsql.GetExistingReplies(op.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error building thread %d: %s", op.ID, err.Error())
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Error building thread %d: %s", op.ID, err.Error()), false)
|
||||
}
|
||||
os.Remove(path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html"))
|
||||
|
||||
|
@ -64,9 +65,10 @@ func BuildThreadPages(op *gcsql.Post) error {
|
|||
}
|
||||
|
||||
threadPageFilepath := path.Join(config.Config.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
|
||||
threadPageFile, err = os.OpenFile(threadPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed opening /%s/res/%d.html: %s", board.Dir, op.ID, err.Error())
|
||||
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)
|
||||
}
|
||||
|
||||
// render thread page
|
||||
|
@ -78,13 +80,15 @@ func BuildThreadPages(op *gcsql.Post) error {
|
|||
"posts": replies,
|
||||
"op": op,
|
||||
}, threadPageFile, "text/html"); err != nil {
|
||||
return fmt.Errorf("Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error())
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error()), false)
|
||||
}
|
||||
|
||||
// Put together the thread JSON
|
||||
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 fmt.Errorf("Failed opening /%s/res/%d.json: %s", board.Dir, op.ID, err.Error())
|
||||
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)
|
||||
}
|
||||
defer threadJSONFile.Close()
|
||||
|
||||
|
@ -95,13 +99,15 @@ func BuildThreadPages(op *gcsql.Post) error {
|
|||
|
||||
// Iterate through each reply, which are of type Post
|
||||
threadMap["posts"] = append(threadMap["posts"], replies...)
|
||||
threadJSON, err := json.Marshal(threadMap)
|
||||
threadJSON, gErr := json.Marshal(threadMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to marshal to JSON: %s", err.Error())
|
||||
return gcutil.NewError(gclog.Printf(gclog.LErrorLog,
|
||||
"Failed to marshal to JSON: %s", gErr.Error()), false)
|
||||
}
|
||||
|
||||
if _, err = threadJSONFile.Write(threadJSON); err != nil {
|
||||
return fmt.Errorf("Failed writing /%s/res/%d.json: %s", board.Dir, op.ID, 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)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -22,7 +22,6 @@ var (
|
|||
|
||||
// ConnectToDB initializes the database connection and exits if there are any errors
|
||||
func ConnectToDB(host string, dbType string, dbName string, username string, password string, prefix string) {
|
||||
var err error
|
||||
var connStr string
|
||||
sqlReplacer = strings.NewReplacer(
|
||||
"DBNAME", dbName,
|
||||
|
@ -32,7 +31,7 @@ func ConnectToDB(host string, dbType string, dbName string, username string, pas
|
|||
|
||||
switch dbType {
|
||||
case "mysql":
|
||||
connStr = fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci",
|
||||
connStr = fmt.Sprintf("%s:%s@%s/%s?parseTime=true&collation=utf8mb4_unicode_ci",
|
||||
username, password, host, dbName)
|
||||
nilTimestamp = "0000-00-00 00:00:00"
|
||||
case "postgres":
|
||||
|
@ -49,11 +48,12 @@ 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
|
||||
if db, err = sql.Open(dbType, connStr); err != nil {
|
||||
gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", err.Error())
|
||||
var gErr error
|
||||
if db, gErr = sql.Open(dbType, connStr); gErr != nil {
|
||||
gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", gErr.Error())
|
||||
}
|
||||
|
||||
err = handleVersioning(dbType)
|
||||
err := handleVersioning(dbType)
|
||||
if err != nil {
|
||||
gclog.Print(fatalSQLFlags, "Failed to initialise database: ", err.Error())
|
||||
}
|
||||
|
@ -61,18 +61,18 @@ func ConnectToDB(host string, dbType string, dbName string, username string, pas
|
|||
gclog.Print(gclog.LStdLog|gclog.LErrorLog, "Finished initializing server...")
|
||||
}
|
||||
|
||||
func initDB(initFile string) error {
|
||||
var err error
|
||||
func initDB(initFile string) *gcutil.GcError {
|
||||
filePath := gcutil.FindResource(initFile,
|
||||
"/usr/local/share/gochan/"+initFile,
|
||||
"/usr/share/gochan/"+initFile)
|
||||
if filePath == "" {
|
||||
return fmt.Errorf("SQL database initialization file (%s) missing. Please reinstall gochan", initFile)
|
||||
return gcutil.NewError(fmt.Sprintf(
|
||||
"SQL database initialization file (%s) missing. Please reinstall gochan", initFile), false)
|
||||
}
|
||||
|
||||
sqlBytes, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
return gcutil.FromError(err, false)
|
||||
}
|
||||
|
||||
sqlStr := regexp.MustCompile("--.*\n?").ReplaceAllString(string(sqlBytes), " ")
|
||||
|
@ -89,7 +89,7 @@ func initDB(initFile string) error {
|
|||
println(statement)
|
||||
fmt.Printf("%08b", []byte(statement))
|
||||
}
|
||||
return err
|
||||
return gcutil.FromError(err, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@ package gcsql
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"html/template"
|
||||
"strconv"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
)
|
||||
|
||||
var abstractSelectPosts = `
|
||||
|
@ -84,7 +85,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, error) {
|
||||
func getPostsExcecution(sql string, arguments ...interface{}) ([]Post, *gcutil.GcError) {
|
||||
rows, err := QuerySQL(sql, arguments...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -93,10 +94,10 @@ func getPostsExcecution(sql string, arguments ...interface{}) ([]Post, error) {
|
|||
for rows.Next() {
|
||||
post := new(Post)
|
||||
var messageHTML string
|
||||
err = rows.Scan(&post.ID, &post.ParentID, &post.BoardID, &post.Name, &post.Tripcode, &post.Email,
|
||||
err = gcutil.FromError(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)
|
||||
&post.ThumbW, &post.ThumbH, &post.IP, &post.Timestamp, &post.Autosage, &post.Bumped, &post.Stickied, &post.Locked), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -114,7 +115,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 error) {
|
||||
func GetTopPostsNoSort(boardID int) (posts []Post, err *gcutil.GcError) {
|
||||
return getPostsExcecution(onlyTopPosts, boardID)
|
||||
}
|
||||
|
||||
|
@ -122,7 +123,7 @@ func GetTopPostsNoSort(boardID int) (posts []Post, err error) {
|
|||
// 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 error) {
|
||||
func GetTopPosts(boardID int) (posts []Post, err *gcutil.GcError) {
|
||||
return getPostsExcecution(sortedTopPosts, boardID)
|
||||
}
|
||||
|
||||
|
@ -133,14 +134,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 error) {
|
||||
func GetExistingReplies(topPost int) (posts []Post, err *gcutil.GcError) {
|
||||
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 error) {
|
||||
func GetExistingRepliesLimitedRev(topPost int, limit int) (posts []Post, err *gcutil.GcError) {
|
||||
return getPostsExcecution(newestFirstLimited, topPost, limit)
|
||||
}
|
||||
|
||||
|
@ -149,7 +150,7 @@ func GetExistingRepliesLimitedRev(topPost int, limit int) (posts []Post, err err
|
|||
// 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, error) {
|
||||
func GetSpecificTopPost(ID int) (Post, *gcutil.GcError) {
|
||||
const topPostIDQuery = `SELECT posts.id from DBPREFIXposts as posts
|
||||
JOIN (
|
||||
SELECT threads.id from DBPREFIXthreads as threads
|
||||
|
@ -171,7 +172,7 @@ func GetSpecificTopPost(ID int) (Post, error) {
|
|||
// 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 error) {
|
||||
func GetSpecificPostByString(ID string) (post Post, err *gcutil.GcError) {
|
||||
return getSpecificPostStringDecorated(ID, false)
|
||||
}
|
||||
|
||||
|
@ -179,14 +180,14 @@ func GetSpecificPostByString(ID string) (post Post, err error) {
|
|||
// 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 error) {
|
||||
func GetSpecificPost(ID int, onlyNotDeleted bool) (post Post, err *gcutil.GcError) {
|
||||
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, error) {
|
||||
func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, *gcutil.GcError) {
|
||||
var sql string
|
||||
if onlyNotDeleted {
|
||||
sql = specificPostSQL
|
||||
|
@ -198,7 +199,7 @@ func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, error
|
|||
return Post{}, err
|
||||
}
|
||||
if len(posts) == 0 {
|
||||
return Post{}, errors.New("Could not find a post with the ID: " + ID)
|
||||
return Post{}, gcutil.NewError("Could not find a post with the ID: "+ID, false)
|
||||
}
|
||||
return posts[0], nil
|
||||
}
|
||||
|
@ -206,7 +207,7 @@ func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, error
|
|||
// 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, error) {
|
||||
func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecificBoard bool) ([]RecentPost, *gcutil.GcError) {
|
||||
//TODO: rework so it uses all features/better sql
|
||||
//get recent posts
|
||||
recentQueryStr := `
|
||||
|
@ -266,7 +267,7 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
|
|||
|
||||
ON recentposts.selfid = singlefiles.post_id`
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
var err *gcutil.GcError
|
||||
|
||||
if onlyWithFile && onSpecificBoard {
|
||||
recentQueryStr += "\n" + `WHERE singlefiles.filename IS NOT NULL AND recentposts.boardid = ?
|
||||
|
@ -297,9 +298,9 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
|
|||
for rows.Next() {
|
||||
recentPost := new(RecentPost)
|
||||
var formattedHTML template.HTML
|
||||
if err = rows.Scan(
|
||||
if err = gcutil.FromError(rows.Scan(
|
||||
&recentPost.PostID, &recentPost.ParentID, &recentPost.BoardName, &recentPost.BoardID,
|
||||
&recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH,
|
||||
&recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH), false,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -313,6 +314,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, error) {
|
||||
func GetRecentPostsGlobal(amount int, onlyWithFile bool) ([]RecentPost, *gcutil.GcError) {
|
||||
return getRecentPostsInternal(amount, onlyWithFile, 0, false)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package gcsql
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"html/template"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -13,8 +12,13 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMultipleDBVersions = gcutil.NewError("More than one version in database", false)
|
||||
ErrNilBoard = gcutil.NewError("Board is nil", true)
|
||||
)
|
||||
|
||||
// GetAllNondeletedMessageRaw gets all the raw message texts from the database, saved per id
|
||||
func GetAllNondeletedMessageRaw() ([]MessagePostContainer, error) {
|
||||
func GetAllNondeletedMessageRaw() ([]MessagePostContainer, *gcutil.GcError) {
|
||||
const sql = `select posts.id, posts.message, posts.message_raw from DBPREFIXposts as posts
|
||||
WHERE posts.is_deleted = FALSE`
|
||||
rows, err := QuerySQL(sql)
|
||||
|
@ -25,7 +29,7 @@ func GetAllNondeletedMessageRaw() ([]MessagePostContainer, error) {
|
|||
for rows.Next() {
|
||||
var message MessagePostContainer
|
||||
var formattedHTML template.HTML
|
||||
err = rows.Scan(&message.ID, &formattedHTML, &message.MessageRaw)
|
||||
err = gcutil.FromError(rows.Scan(&message.ID, &formattedHTML, &message.MessageRaw), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -36,7 +40,7 @@ func GetAllNondeletedMessageRaw() ([]MessagePostContainer, error) {
|
|||
}
|
||||
|
||||
// SetFormattedInDatabase sets all the non-raw text for a given array of items.
|
||||
func SetFormattedInDatabase(messages []MessagePostContainer) error {
|
||||
func SetFormattedInDatabase(messages []MessagePostContainer) *gcutil.GcError {
|
||||
const sql = `UPDATE DBPREFIXposts
|
||||
SET message = ?
|
||||
WHERE id = ?`
|
||||
|
@ -46,16 +50,16 @@ func SetFormattedInDatabase(messages []MessagePostContainer) error {
|
|||
return err
|
||||
}
|
||||
for _, message := range messages {
|
||||
_, err = stmt.Exec(string(message.Message), message.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
_, gErr := stmt.Exec(string(message.Message), message.ID)
|
||||
if gErr != nil {
|
||||
return gcutil.FromError(gErr, false)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetReplyCount gets the total amount non-deleted of replies in a thread
|
||||
func GetReplyCount(postID int) (int, error) {
|
||||
func GetReplyCount(postID int) (int, *gcutil.GcError) {
|
||||
const sql = `SELECT COUNT(posts.id) FROM DBPREFIXposts as posts
|
||||
JOIN (
|
||||
SELECT threads.id FROM DBPREFIXthreads as threads
|
||||
|
@ -71,7 +75,7 @@ func GetReplyCount(postID int) (int, error) {
|
|||
}
|
||||
|
||||
// GetReplyFileCount gets the amount of files non-deleted posted in total in a thread
|
||||
func GetReplyFileCount(postID int) (int, error) {
|
||||
func GetReplyFileCount(postID int) (int, *gcutil.GcError) {
|
||||
const sql = `SELECT COUNT(files.id) from DBPREFIXfiles as files
|
||||
JOIN (SELECT posts.id FROM DBPREFIXposts as posts
|
||||
JOIN (
|
||||
|
@ -89,7 +93,7 @@ func GetReplyFileCount(postID int) (int, error) {
|
|||
}
|
||||
|
||||
// GetStaffName returns the name associated with a session
|
||||
func GetStaffName(session string) (string, error) {
|
||||
func GetStaffName(session string) (string, *gcutil.GcError) {
|
||||
const sql = `SELECT staff.username from DBPREFIXstaff as staff
|
||||
JOIN DBPREFIXsessions as sessions
|
||||
ON sessions.staff_id = staff.id
|
||||
|
@ -102,7 +106,7 @@ func GetStaffName(session string) (string, error) {
|
|||
// 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, error) {
|
||||
func GetStaffBySession(session string) (*Staff, *gcutil.GcError) {
|
||||
const sql = `SELECT
|
||||
staff.id,
|
||||
staff.username,
|
||||
|
@ -122,7 +126,7 @@ func GetStaffBySession(session string) (*Staff, error) {
|
|||
// 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, error) {
|
||||
func GetStaffByName(name string) (*Staff, *gcutil.GcError) {
|
||||
const sql = `SELECT
|
||||
staff.id,
|
||||
staff.username,
|
||||
|
@ -137,7 +141,7 @@ func GetStaffByName(name string) (*Staff, error) {
|
|||
return staff, err
|
||||
}
|
||||
|
||||
func getStaffByID(id int) (*Staff, error) {
|
||||
func getStaffByID(id int) (*Staff, *gcutil.GcError) {
|
||||
const sql = `SELECT
|
||||
staff.id,
|
||||
staff.username,
|
||||
|
@ -153,7 +157,7 @@ func getStaffByID(id int) (*Staff, error) {
|
|||
}
|
||||
|
||||
// NewStaff creates a new staff account from a given username, password and rank
|
||||
func NewStaff(username string, password string, rank int) error {
|
||||
func NewStaff(username string, password string, rank int) *gcutil.GcError {
|
||||
const sql = `INSERT INTO DBPREFIXstaff (username, password_checksum, global_rank)
|
||||
VALUES (?, ?, ?)`
|
||||
_, err := ExecSQL(sql, username, gcutil.BcryptSum(password), rank)
|
||||
|
@ -162,13 +166,13 @@ func NewStaff(username string, password string, rank int) error {
|
|||
|
||||
// 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) error {
|
||||
func DeleteStaff(username string) *gcutil.GcError {
|
||||
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, error) {
|
||||
func getStaffID(username string) (int, *gcutil.GcError) {
|
||||
staff, err := GetStaffByName(username)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
|
@ -177,7 +181,7 @@ func getStaffID(username string) (int, error) {
|
|||
}
|
||||
|
||||
// CreateSession inserts a session for a given key and username into the database
|
||||
func CreateSession(key string, username string) error {
|
||||
func CreateSession(key string, username string) *gcutil.GcError {
|
||||
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)
|
||||
|
@ -193,7 +197,7 @@ func CreateSession(key string, username string) error {
|
|||
}
|
||||
|
||||
// PermanentlyRemoveDeletedPosts removes all posts and files marked as deleted from the database
|
||||
func PermanentlyRemoveDeletedPosts() error {
|
||||
func PermanentlyRemoveDeletedPosts() *gcutil.GcError {
|
||||
const sql1 = `DELETE FROM DBPREFIXposts WHERE is_deleted`
|
||||
const sql2 = `DELETE FROM DBPREFIXthreads WHERE is_deleted`
|
||||
_, err := ExecSQL(sql1)
|
||||
|
@ -205,7 +209,7 @@ func PermanentlyRemoveDeletedPosts() error {
|
|||
}
|
||||
|
||||
// OptimizeDatabase peforms a database optimisation
|
||||
func OptimizeDatabase() error {
|
||||
func OptimizeDatabase() *gcutil.GcError {
|
||||
tableRows, tablesErr := QuerySQL("SHOW TABLES")
|
||||
if tablesErr != nil {
|
||||
return tablesErr
|
||||
|
@ -229,7 +233,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) error {
|
||||
func CreateFileBan(fileChecksum string, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
|
||||
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 {
|
||||
|
@ -241,7 +245,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) error {
|
||||
func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
|
||||
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 {
|
||||
|
@ -253,7 +257,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) error {
|
||||
func CreateUserNameBan(userName string, isRegex bool, staffName string, permaban bool, staffNote string, boardURI string) *gcutil.GcError {
|
||||
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 {
|
||||
|
@ -268,7 +272,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) error {
|
||||
staffNote string, message string, canAppeal bool, appealAt time.Time) *gcutil.GcError {
|
||||
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)
|
||||
|
@ -283,7 +287,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, error) {
|
||||
func GetAllAccouncements() ([]Announcement, *gcutil.GcError) {
|
||||
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
|
||||
|
@ -295,7 +299,7 @@ func GetAllAccouncements() ([]Announcement, error) {
|
|||
var announcements []Announcement
|
||||
for rows.Next() {
|
||||
var announcement Announcement
|
||||
err = rows.Scan(&announcement.Poster, &announcement.Timestamp, &announcement.Subject, &announcement.Message)
|
||||
err = gcutil.FromError(rows.Scan(&announcement.Poster, &announcement.Timestamp, &announcement.Subject, &announcement.Message), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -307,7 +311,7 @@ func GetAllAccouncements() ([]Announcement, error) {
|
|||
//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) error {
|
||||
func CreateBoard(values *Board) *gcutil.GcError {
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
|
@ -315,7 +319,7 @@ func CreateBoard(values *Board) error {
|
|||
//Excecuted in two steps this way because last row id functions arent thread safe, dir and uri is unique
|
||||
|
||||
if values == nil {
|
||||
return errors.New("Board is nil")
|
||||
return ErrNilBoard
|
||||
}
|
||||
_, err := ExecSQL(sqlINSERT, values.ListOrder, values.Dir, values.Dir, values.Title, values.Subtitle, values.Description, values.MaxFilesize, maxThreads, values.DefaultStyle, values.Locked, values.Anonymous, values.ForcedAnon, values.AutosageAfter, values.NoImagesAfter, values.MaxMessageLength, 1, values.EmbedsAllowed, values.RedirectToThread, values.RequireFile, values.EnableCatalog, values.Section)
|
||||
if err != nil {
|
||||
|
@ -325,7 +329,7 @@ func CreateBoard(values *Board) error {
|
|||
}
|
||||
|
||||
//GetBoardUris gets a list of all existing board URIs
|
||||
func GetBoardUris() (URIS []string, err error) {
|
||||
func GetBoardUris() (URIS []string, err *gcutil.GcError) {
|
||||
const sql = `SELECT uri FROM DBPREFIXboards`
|
||||
rows, err := QuerySQL(sql)
|
||||
if err != nil {
|
||||
|
@ -334,7 +338,7 @@ func GetBoardUris() (URIS []string, err error) {
|
|||
var uris []string
|
||||
for rows.Next() {
|
||||
var uri string
|
||||
err = rows.Scan(&uri)
|
||||
err = gcutil.FromError(rows.Scan(&uri), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -344,7 +348,7 @@ func GetBoardUris() (URIS []string, err error) {
|
|||
}
|
||||
|
||||
//GetAllSections gets a list of all existing sections
|
||||
func GetAllSections() ([]BoardSection, error) {
|
||||
func GetAllSections() ([]BoardSection, *gcutil.GcError) {
|
||||
const sql = `SELECT id, name, abbreviation, position, hidden FROM DBPREFIXsections`
|
||||
rows, err := QuerySQL(sql)
|
||||
if err != nil {
|
||||
|
@ -353,7 +357,7 @@ func GetAllSections() ([]BoardSection, error) {
|
|||
var sections []BoardSection
|
||||
for rows.Next() {
|
||||
var section BoardSection
|
||||
err = rows.Scan(§ion.ID, §ion.Name, §ion.Abbreviation, §ion.ListOrder, §ion.Hidden)
|
||||
err = gcutil.FromError(rows.Scan(§ion.ID, §ion.Name, §ion.Abbreviation, §ion.ListOrder, §ion.Hidden), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -365,7 +369,7 @@ func GetAllSections() ([]BoardSection, error) {
|
|||
// 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, error) {
|
||||
func GetAllSectionsOrCreateDefault() ([]BoardSection, *gcutil.GcError) {
|
||||
_, err := GetOrCreateDefaultSectionID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -373,7 +377,7 @@ func GetAllSectionsOrCreateDefault() ([]BoardSection, error) {
|
|||
return GetAllSections()
|
||||
}
|
||||
|
||||
func getNextSectionListOrder() (int, error) {
|
||||
func getNextSectionListOrder() (int, *gcutil.GcError) {
|
||||
const sql = `SELECT COALESCE(MAX(position) + 1, 0) FROM DBPREFIXsections`
|
||||
var ID int
|
||||
err := QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&ID))
|
||||
|
@ -381,11 +385,11 @@ func getNextSectionListOrder() (int, error) {
|
|||
}
|
||||
|
||||
//GetOrCreateDefaultSectionID creates the default section if it does not exist yet, returns default section ID if it exists
|
||||
func GetOrCreateDefaultSectionID() (sectionID int, err error) {
|
||||
func GetOrCreateDefaultSectionID() (sectionID int, err *gcutil.GcError) {
|
||||
const SQL = `SELECT id FROM DBPREFIXsections WHERE name = 'Main'`
|
||||
var ID int
|
||||
err = QueryRowSQL(SQL, interfaceSlice(), interfaceSlice(&ID))
|
||||
if err == sql.ErrNoRows {
|
||||
if gcutil.CompareErrors(err, sql.ErrNoRows) {
|
||||
//create it
|
||||
ID, err := getNextSectionListOrder()
|
||||
if err != nil {
|
||||
|
@ -402,7 +406,7 @@ func GetOrCreateDefaultSectionID() (sectionID int, err error) {
|
|||
}
|
||||
|
||||
//CreateSection creates a section, setting the newly created id in the given struct
|
||||
func CreateSection(section *BoardSection) error {
|
||||
func CreateSection(section *BoardSection) *gcutil.GcError {
|
||||
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
|
||||
|
@ -419,7 +423,7 @@ func CreateSection(section *BoardSection) error {
|
|||
//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, error) {
|
||||
func GetAllStaffNopass() ([]Staff, *gcutil.GcError) {
|
||||
const sql = `SELECT id, username, global_rank, added_on, last_login FROM DBPREFIXstaff`
|
||||
rows, err := QuerySQL(sql)
|
||||
if err != nil {
|
||||
|
@ -428,7 +432,7 @@ func GetAllStaffNopass() ([]Staff, error) {
|
|||
var staffs []Staff
|
||||
for rows.Next() {
|
||||
var staff Staff
|
||||
err = rows.Scan(&staff.ID, &staff.Username, &staff.Rank, &staff.AddedOn, &staff.LastActive)
|
||||
err = gcutil.FromError(rows.Scan(&staff.ID, &staff.Username, &staff.Rank, &staff.AddedOn, &staff.LastActive), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -441,7 +445,7 @@ func GetAllStaffNopass() ([]Staff, error) {
|
|||
//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, error) {
|
||||
func GetAllBans() ([]BanInfo, *gcutil.GcError) {
|
||||
const sql = `SELECT
|
||||
ban.id,
|
||||
ban.ip,
|
||||
|
@ -466,7 +470,7 @@ ON ban.board_id = board.id`
|
|||
var bans []BanInfo
|
||||
for rows.Next() {
|
||||
var ban BanInfo
|
||||
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)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -479,26 +483,31 @@ 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, error) {
|
||||
func CheckBan(ip string, name string, filename string, checksum string) (*BanInfo, *gcutil.GcError) {
|
||||
ban := new(BanInfo)
|
||||
ipban, err1 := checkIPBan(ip)
|
||||
err1NoRows := gcutil.CompareErrors(err1, sql.ErrNoRows)
|
||||
_, err2 := checkFileBan(checksum)
|
||||
err2NoRows := gcutil.CompareErrors(err2, sql.ErrNoRows)
|
||||
_, err3 := checkFilenameBan(filename)
|
||||
err3NoRows := gcutil.CompareErrors(err3, sql.ErrNoRows)
|
||||
_, err4 := checkUsernameBan(name)
|
||||
err4NoRows := gcutil.CompareErrors(err4, sql.ErrNoRows)
|
||||
|
||||
if err1 == sql.ErrNoRows && err2 == sql.ErrNoRows && err3 == sql.ErrNoRows && err4 == sql.ErrNoRows {
|
||||
return nil, sql.ErrNoRows
|
||||
if err1NoRows && err2NoRows && err3NoRows && err4NoRows {
|
||||
return nil, gcutil.FromError(sql.ErrNoRows, false)
|
||||
}
|
||||
if err1 != nil && err1 != sql.ErrNoRows {
|
||||
|
||||
if err1NoRows {
|
||||
return nil, err1
|
||||
}
|
||||
if err2 != nil && err2 != sql.ErrNoRows {
|
||||
if err2NoRows {
|
||||
return nil, err2
|
||||
}
|
||||
if err3 != nil && err3 != sql.ErrNoRows {
|
||||
if err3NoRows {
|
||||
return nil, err3
|
||||
}
|
||||
if err4 != nil && err4 != sql.ErrNoRows {
|
||||
if err4NoRows {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
|
@ -518,10 +527,10 @@ func CheckBan(ip string, name string, filename string, checksum string) (*BanInf
|
|||
}
|
||||
|
||||
//TODO implement other types of bans or refactor banning code
|
||||
return nil, errors.New("Not implemented")
|
||||
return nil, gcutil.ErrNotImplemented
|
||||
}
|
||||
|
||||
func checkIPBan(ip string) (*IPBan, error) {
|
||||
func checkIPBan(ip string) (*IPBan, *gcutil.GcError) {
|
||||
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)
|
||||
|
@ -531,7 +540,7 @@ func checkIPBan(ip string) (*IPBan, error) {
|
|||
return ban, err
|
||||
}
|
||||
|
||||
func checkUsernameBan(name string) (*UsernameBan, error) {
|
||||
func checkUsernameBan(name string) (*UsernameBan, *gcutil.GcError) {
|
||||
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, username, is_regex
|
||||
FROM DBPREFIXusername_ban WHERE username = ?`
|
||||
var ban = new(UsernameBan)
|
||||
|
@ -539,7 +548,7 @@ func checkUsernameBan(name string) (*UsernameBan, error) {
|
|||
return ban, err
|
||||
}
|
||||
|
||||
func checkFilenameBan(filename string) (*FilenameBan, error) {
|
||||
func checkFilenameBan(filename string) (*FilenameBan, *gcutil.GcError) {
|
||||
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, filename, is_regex
|
||||
FROM DBPREFIXfilename_ban WHERE filename = ?`
|
||||
var ban = new(FilenameBan)
|
||||
|
@ -547,7 +556,7 @@ func checkFilenameBan(filename string) (*FilenameBan, error) {
|
|||
return ban, err
|
||||
}
|
||||
|
||||
func checkFileBan(checksum string) (*FileBan, error) {
|
||||
func checkFileBan(checksum string) (*FileBan, *gcutil.GcError) {
|
||||
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, checksum
|
||||
FROM DBPREFIXfile_ban WHERE checksum = ?`
|
||||
var ban = new(FileBan)
|
||||
|
@ -558,7 +567,7 @@ func checkFileBan(checksum string) (*FileBan, error) {
|
|||
//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, error) {
|
||||
func SinceLastPost(postID int) (int, *gcutil.GcError) {
|
||||
const sql = `SELECT MAX(created_on) FROM DBPREFIXposts as posts
|
||||
JOIN (SELECT ip FROM DBPREFIXposts as sp
|
||||
WHERE sp.id = ?) as ip
|
||||
|
@ -574,12 +583,12 @@ func SinceLastPost(postID int) (int, error) {
|
|||
// 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) error {
|
||||
func InsertPost(post *Post, bump bool) *gcutil.GcError {
|
||||
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 error
|
||||
var err *gcutil.GcError
|
||||
if isNewThread {
|
||||
threadID, err = createThread(post.BoardID, post.Locked, post.Stickied, post.Autosage, false)
|
||||
} else {
|
||||
|
@ -620,7 +629,7 @@ func InsertPost(post *Post, bump bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclical bool) (threadID int, err error) {
|
||||
func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclical bool) (threadID int, err *gcutil.GcError) {
|
||||
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
|
||||
|
@ -640,7 +649,7 @@ func createThread(boardID int, locked bool, stickied bool, anchored bool, cyclic
|
|||
return threadID, nil
|
||||
}
|
||||
|
||||
func bumpThreadOfPost(postID int) error {
|
||||
func bumpThreadOfPost(postID int) *gcutil.GcError {
|
||||
id, err := getThreadID(postID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -648,13 +657,13 @@ func bumpThreadOfPost(postID int) error {
|
|||
return bumpThread(id)
|
||||
}
|
||||
|
||||
func bumpThread(threadID int) error {
|
||||
func bumpThread(threadID int) *gcutil.GcError {
|
||||
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) error {
|
||||
func appendFile(postID int, originalFilename string, filename string, checksum string, fileSize int, isSpoilered bool, width int, height int, thumbnailWidth int, thumbnailHeight int) *gcutil.GcError {
|
||||
const nextIDSQL = `SELECT COALESCE(MAX(file_order) + 1, 0) FROM DBPREFIXfiles WHERE post_id = ?`
|
||||
var nextID int
|
||||
err := QueryRowSQL(nextIDSQL, interfaceSlice(postID), interfaceSlice(&nextID))
|
||||
|
@ -668,7 +677,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 error) {
|
||||
func GetMaxMessageLength(boardID int) (length int, err *gcutil.GcError) {
|
||||
const sql = `SELECT max_message_length FROM DBPREFIXboards
|
||||
WHERE id = ?`
|
||||
err = QueryRowSQL(sql, interfaceSlice(boardID), interfaceSlice(&length))
|
||||
|
@ -676,7 +685,7 @@ func GetMaxMessageLength(boardID int) (length int, err error) {
|
|||
}
|
||||
|
||||
//GetEmbedsAllowed returns if embeds are allowed on a given board
|
||||
func GetEmbedsAllowed(boardID int) (allowed bool, err error) {
|
||||
func GetEmbedsAllowed(boardID int) (allowed bool, err *gcutil.GcError) {
|
||||
const sql = `SELECT allow_embeds FROM DBPREFIXboards
|
||||
WHERE id = ?`
|
||||
err = QueryRowSQL(sql, interfaceSlice(boardID), interfaceSlice(&allowed))
|
||||
|
@ -684,7 +693,7 @@ func GetEmbedsAllowed(boardID int) (allowed bool, err error) {
|
|||
}
|
||||
|
||||
//GetBoardFromPostID gets the boardURI that a given postid exists on
|
||||
func GetBoardFromPostID(postID int) (boardURI string, err error) {
|
||||
func GetBoardFromPostID(postID int) (boardURI string, err *gcutil.GcError) {
|
||||
const sql = `SELECT board.uri FROM DBPREFIXboards as board
|
||||
JOIN (
|
||||
SELECT threads.board_id FROM DBPREFIXthreads as threads
|
||||
|
@ -698,7 +707,7 @@ func GetBoardFromPostID(postID int) (boardURI string, err error) {
|
|||
//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 error) {
|
||||
func GetThreadIDZeroIfTopPost(postID int) (ID int, err *gcutil.GcError) {
|
||||
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`
|
||||
|
@ -712,14 +721,14 @@ func GetThreadIDZeroIfTopPost(postID int) (ID int, err error) {
|
|||
return ID, nil
|
||||
}
|
||||
|
||||
func getThreadID(postID int) (ID int, err error) {
|
||||
func getThreadID(postID int) (ID int, err *gcutil.GcError) {
|
||||
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) error {
|
||||
func AddBanAppeal(banID uint, message string) *gcutil.GcError {
|
||||
const sql1 = `
|
||||
/*copy old to audit*/
|
||||
INSERT INTO DBPREFIXip_ban_appeals_audit (appeal_id, staff_id, appeal_text, staff_response, is_denied)
|
||||
|
@ -739,7 +748,7 @@ func AddBanAppeal(banID uint, message string) error {
|
|||
}
|
||||
|
||||
//GetPostPassword gets the password associated with a given post
|
||||
func GetPostPassword(postID int) (password string, err error) {
|
||||
func GetPostPassword(postID int) (password string, err *gcutil.GcError) {
|
||||
const sql = `SELECT password_checksum FROM DBPREFIXposts WHERE id = ?`
|
||||
err = QueryRowSQL(sql, interfaceSlice(postID), interfaceSlice(&password))
|
||||
return password, err
|
||||
|
@ -748,7 +757,7 @@ func GetPostPassword(postID int) (password string, err error) {
|
|||
//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) error {
|
||||
func UpdatePost(postID int, email string, subject string, message template.HTML, messageRaw string) *gcutil.GcError {
|
||||
const sql = `UPDATE DBPREFIXposts SET email = ?, subject = ?, message = ?, message_raw = ? WHERE id = ?`
|
||||
_, err := ExecSQL(sql, email, subject, string(message), messageRaw)
|
||||
return err
|
||||
|
@ -757,7 +766,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) error {
|
||||
func DeleteFilesFromPost(postID int) *gcutil.GcError {
|
||||
board, err := GetBoardFromPostID(postID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -772,7 +781,7 @@ func DeleteFilesFromPost(postID int) error {
|
|||
var filenames []string
|
||||
for rows.Next() {
|
||||
var filename string
|
||||
err = rows.Scan(&filename)
|
||||
err = gcutil.FromError(rows.Scan(&filename), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -799,7 +808,7 @@ func DeleteFilesFromPost(postID int) error {
|
|||
}
|
||||
|
||||
//DeletePost deletes a post with a given ID
|
||||
func DeletePost(postID int, checkIfTopPost bool) error {
|
||||
func DeletePost(postID int, checkIfTopPost bool) *gcutil.GcError {
|
||||
if checkIfTopPost {
|
||||
isTopPost, err := isTopPost(postID)
|
||||
if err != nil {
|
||||
|
@ -820,13 +829,13 @@ func DeletePost(postID int, checkIfTopPost bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func isTopPost(postID int) (val bool, err error) {
|
||||
func isTopPost(postID int) (val bool, err *gcutil.GcError) {
|
||||
const sql = `SELECT is_top_post FROM DBPREFIXposts WHERE id = ?`
|
||||
err = QueryRowSQL(sql, interfaceSlice(postID), interfaceSlice(&val))
|
||||
return val, err
|
||||
}
|
||||
|
||||
func deleteThread(threadID int) error {
|
||||
func deleteThread(threadID int) *gcutil.GcError {
|
||||
const sql1 = `UPDATE DBPREFIXthreads SET is_deleted = TRUE, deleted_at = CURRENT_TIMESTAMP WHERE id = ?`
|
||||
const sql2 = `SELECT id FROM DBPREFIXposts WHERE thread_id = ?`
|
||||
|
||||
|
@ -841,7 +850,7 @@ func deleteThread(threadID int) error {
|
|||
var ids []int
|
||||
for rows.Next() {
|
||||
var id int
|
||||
err = rows.Scan(&id)
|
||||
err = gcutil.FromError(rows.Scan(&id), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -858,15 +867,15 @@ func deleteThread(threadID int) error {
|
|||
}
|
||||
|
||||
//CreateDefaultBoardIfNoneExist creates a default board if no boards exist yet
|
||||
func CreateDefaultBoardIfNoneExist() error {
|
||||
const sql = `SELECT COUNT(id) FROM DBPREFIXboards`
|
||||
func CreateDefaultBoardIfNoneExist() *gcutil.GcError {
|
||||
const sqlStr = `SELECT COUNT(id) FROM DBPREFIXboards`
|
||||
var count int
|
||||
QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&count))
|
||||
QueryRowSQL(sqlStr, interfaceSlice(), interfaceSlice(&count))
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
defaultSectionID, err := GetOrCreateDefaultSectionID()
|
||||
if err != nil {
|
||||
if err != nil && !gcutil.CompareErrors(err, sql.ErrNoRows) {
|
||||
return err
|
||||
}
|
||||
var board = Board{
|
||||
|
@ -880,7 +889,7 @@ func CreateDefaultBoardIfNoneExist() error {
|
|||
}
|
||||
|
||||
//CreateDefaultAdminIfNoStaff creates a new default admin account if no accounts exist
|
||||
func CreateDefaultAdminIfNoStaff() error {
|
||||
func CreateDefaultAdminIfNoStaff() *gcutil.GcError {
|
||||
const sql = `SELECT COUNT(id) FROM DBPREFIXstaff`
|
||||
var count int
|
||||
QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&count))
|
||||
|
@ -891,7 +900,7 @@ func CreateDefaultAdminIfNoStaff() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func createUser(username string, passwordEncrypted string, globalRank int) (userID int, err error) {
|
||||
func createUser(username string, passwordEncrypted string, globalRank int) (userID int, err *gcutil.GcError) {
|
||||
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
|
||||
|
@ -906,7 +915,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() error {
|
||||
func (board *Board) UpdateID() *gcutil.GcError {
|
||||
const sql = `SELECT id FROM DBPREFIXboards WHERE dir = ?`
|
||||
return QueryRowSQL(sql, interfaceSlice(board.Dir), interfaceSlice(&board.ID))
|
||||
}
|
||||
|
@ -914,13 +923,13 @@ func (board *Board) UpdateID() error {
|
|||
// 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) error {
|
||||
func (board *Board) PopulateData(id int) *gcutil.GcError {
|
||||
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, error) {
|
||||
func DoesBoardExistByID(ID int) (bool, *gcutil.GcError) {
|
||||
const sql = `SELECT COUNT(id) FROM DBPREFIXboards WHERE id = ?`
|
||||
var count int
|
||||
err := QueryRowSQL(sql, interfaceSlice(ID), interfaceSlice(&count))
|
||||
|
@ -930,7 +939,7 @@ func DoesBoardExistByID(ID int) (bool, error) {
|
|||
//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, error) {
|
||||
func GetAllBoards() ([]Board, *gcutil.GcError) {
|
||||
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)
|
||||
|
@ -940,7 +949,7 @@ func GetAllBoards() ([]Board, error) {
|
|||
var boards []Board
|
||||
for rows.Next() {
|
||||
var board Board
|
||||
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)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -952,13 +961,13 @@ func GetAllBoards() ([]Board, error) {
|
|||
//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, error) {
|
||||
func GetBoardFromID(boardID int) (Board, *gcutil.GcError) {
|
||||
var board Board
|
||||
err := board.PopulateData(boardID)
|
||||
return board, err
|
||||
}
|
||||
|
||||
func getBoardIDFromURI(URI string) (id int, err error) {
|
||||
func getBoardIDFromURI(URI string) (id int, err *gcutil.GcError) {
|
||||
const sql = `SELECT id FROM DBPREFIXboards WHERE uri = ?`
|
||||
err = QueryRowSQL(sql, interfaceSlice(URI), interfaceSlice(&id))
|
||||
return id, err
|
||||
|
@ -970,18 +979,18 @@ func getDatabaseVersion() (int, *gcutil.GcError) {
|
|||
var count int
|
||||
err := QueryRowSQL(countsql, interfaceSlice(), interfaceSlice(&count))
|
||||
if err != nil {
|
||||
return 0, gcutil.FromError(err, false)
|
||||
return 0, err
|
||||
}
|
||||
if count > 1 {
|
||||
return 0, gcutil.NewError("More than one version in database", false)
|
||||
return 0, ErrMultipleDBVersions
|
||||
}
|
||||
const sql = `SELECT version FROM DBPREFIXdatabase_version`
|
||||
var version int
|
||||
err = QueryRowSQL(countsql, interfaceSlice(), interfaceSlice(&version))
|
||||
return version, gcutil.FromError(err, false)
|
||||
return version, err
|
||||
}
|
||||
|
||||
func getNextFreeID(tableName string) (ID int, err error) {
|
||||
func getNextFreeID(tableName string) (ID int, err *gcutil.GcError) {
|
||||
var sql = `SELECT COALESCE(MAX(id), 0) + 1 FROM ` + tableName
|
||||
err = QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&ID))
|
||||
return ID, err
|
||||
|
|
|
@ -2,12 +2,12 @@ package gcsql
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gclog"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -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) error {
|
||||
func sqlVersionErr(err error, query *string) *gcutil.GcError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -26,25 +26,25 @@ func sqlVersionErr(err error, query *string) error {
|
|||
switch dbDriver {
|
||||
case "mysql":
|
||||
if !strings.Contains(errText, "You have an error in your SQL syntax") {
|
||||
return err
|
||||
return gcutil.FromError(err, false)
|
||||
}
|
||||
case "postgres":
|
||||
if !strings.Contains(errText, "syntax error at or near") {
|
||||
return err
|
||||
return gcutil.FromError(err, false)
|
||||
}
|
||||
case "sqlite3":
|
||||
if !strings.Contains(errText, "Error: near ") {
|
||||
return err
|
||||
return gcutil.FromError(err, false)
|
||||
}
|
||||
}
|
||||
if config.Config.DebugMode {
|
||||
return fmt.Errorf(unsupportedSQLVersionMsg+"\nQuery: "+*query, errText)
|
||||
return gcutil.NewError(fmt.Sprintf(unsupportedSQLVersionMsg+"\nQuery: "+*query, errText), false)
|
||||
}
|
||||
return fmt.Errorf(unsupportedSQLVersionMsg, errText)
|
||||
return gcutil.NewError(fmt.Sprintf(unsupportedSQLVersionMsg, errText), false)
|
||||
}
|
||||
|
||||
// PrepareSQL is used for generating a prepared SQL statement formatted according to config.DBtype
|
||||
func PrepareSQL(query string) (*sql.Stmt, error) {
|
||||
func PrepareSQL(query string) (*sql.Stmt, *gcutil.GcError) {
|
||||
var preparedStr string
|
||||
switch dbDriver {
|
||||
case "mysql":
|
||||
|
@ -84,13 +84,14 @@ Example:
|
|||
result, err := gcsql.ExecSQL(
|
||||
"INSERT INTO tablename (intval,stringval) VALUES(?,?)", intVal, stringVal)
|
||||
*/
|
||||
func ExecSQL(query string, values ...interface{}) (sql.Result, error) {
|
||||
stmt, err := PrepareSQL(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func ExecSQL(query string, values ...interface{}) (sql.Result, *gcutil.GcError) {
|
||||
stmt, gcerr := PrepareSQL(query)
|
||||
if gcerr != nil {
|
||||
return nil, gcerr
|
||||
}
|
||||
defer stmt.Close()
|
||||
return stmt.Exec(values...)
|
||||
res, err := stmt.Exec(values...)
|
||||
return res, gcutil.FromError(err, false)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -104,13 +105,13 @@ Example:
|
|||
[]interface{}{&id},
|
||||
[]interface{}{&intVal, &stringVal})
|
||||
*/
|
||||
func QueryRowSQL(query string, values []interface{}, out []interface{}) error {
|
||||
func QueryRowSQL(query string, values []interface{}, out []interface{}) *gcutil.GcError {
|
||||
stmt, err := PrepareSQL(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
return stmt.QueryRow(values...).Scan(out...)
|
||||
return gcutil.FromError(stmt.QueryRow(values...).Scan(out...), false)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -127,13 +128,14 @@ Example:
|
|||
}
|
||||
}
|
||||
*/
|
||||
func QuerySQL(query string, a ...interface{}) (*sql.Rows, error) {
|
||||
stmt, err := PrepareSQL(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func QuerySQL(query string, a ...interface{}) (*sql.Rows, *gcutil.GcError) {
|
||||
stmt, gcerr := PrepareSQL(query)
|
||||
if gcerr != nil {
|
||||
return nil, gcerr
|
||||
}
|
||||
defer stmt.Close()
|
||||
return stmt.Query(a...)
|
||||
rows, err := stmt.Query(a...)
|
||||
return rows, gcutil.FromError(err, false)
|
||||
}
|
||||
|
||||
// ResetBoardSectionArrays is run when the board list needs to be changed
|
||||
|
@ -154,23 +156,23 @@ func interfaceSlice(args ...interface{}) []interface{} {
|
|||
return args
|
||||
}
|
||||
|
||||
func errFilterDuplicatePrimaryKey(err error) (isPKerror bool, nonPKerror error) {
|
||||
func errFilterDuplicatePrimaryKey(err *gcutil.GcError) (isPKerror bool, nonPKerror *gcutil.GcError) {
|
||||
if err == nil {
|
||||
return false, nil
|
||||
}
|
||||
errText := err.Error()
|
||||
|
||||
switch dbDriver {
|
||||
case "mysql":
|
||||
if !strings.Contains(errText, "Duplicate entry") {
|
||||
if !strings.Contains(err.Message, "Duplicate entry") {
|
||||
return false, err
|
||||
}
|
||||
case "postgres":
|
||||
if !strings.Contains(errText, "duplicate key value violates unique constraint") {
|
||||
if !strings.Contains(err.Message, "duplicate key value violates unique constraint") {
|
||||
return false, err
|
||||
}
|
||||
case "sqlite3":
|
||||
return false, errors.New("Not implemented")
|
||||
// if !strings.Contains(errText, "Error: near ") {//TODO fill in correct error string
|
||||
return false, gcutil.ErrNotImplemented
|
||||
// if !strings.Contains(err.Error(), "Error: near ") {//TODO fill in correct error string
|
||||
// return false, err
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -59,13 +59,13 @@ func handleVersioning(dbType string) *gcutil.GcError {
|
|||
}
|
||||
|
||||
func buildNewDatabase(dbType string) {
|
||||
var err error
|
||||
var err *gcutil.GcError
|
||||
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.Error())
|
||||
gclog.Print(fatalSQLFlags, "Failed creating default board: ", err.Message)
|
||||
}
|
||||
err = CreateDefaultAdminIfNoStaff()
|
||||
if err != nil {
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
)
|
||||
|
@ -26,7 +28,7 @@ var (
|
|||
ThreadPage *template.Template
|
||||
)
|
||||
|
||||
func loadTemplate(files ...string) (*template.Template, error) {
|
||||
func loadTemplate(files ...string) (*template.Template, *gcutil.GcError) {
|
||||
var templates []string
|
||||
for i, file := range files {
|
||||
templates = append(templates, file)
|
||||
|
@ -39,20 +41,21 @@ func loadTemplate(files ...string) (*template.Template, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return template.New(templates[0]).Funcs(funcMap).ParseFiles(files...)
|
||||
tmpl, err := template.New(templates[0]).Funcs(funcMap).ParseFiles(files...)
|
||||
return tmpl, gcutil.FromError(err, false)
|
||||
}
|
||||
|
||||
func templateError(name string, err error) error {
|
||||
func templateError(name string, err error) *gcutil.GcError {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Failed loading template '%s/%s': %s",
|
||||
config.Config.TemplateDir, name, err.Error())
|
||||
return gcutil.NewError(fmt.Sprintf("Failed loading template '%s/%s': %s",
|
||||
config.Config.TemplateDir, name, err.Error()), false)
|
||||
}
|
||||
|
||||
// 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) error {
|
||||
func InitTemplates(which ...string) *gcutil.GcError {
|
||||
gcsql.ResetBoardSectionArrays()
|
||||
if len(which) == 0 || which[0] == "all" {
|
||||
return templateLoading("", true)
|
||||
|
@ -66,8 +69,8 @@ func InitTemplates(which ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func templateLoading(t string, buildAll bool) error {
|
||||
var err error
|
||||
func templateLoading(t string, buildAll bool) *gcutil.GcError {
|
||||
var err *gcutil.GcError
|
||||
if buildAll || t == "banpage" {
|
||||
Banpage, err = loadTemplate("banpage.html", "page_footer.html")
|
||||
if err != nil {
|
||||
|
|
|
@ -4,6 +4,11 @@ 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 {
|
||||
|
@ -60,8 +65,11 @@ func (gce *GcError) addError(user bool, err ...interface{}) {
|
|||
}
|
||||
|
||||
// AddChildError creates a new GcError object, adds it to the SubErrors array, and returns it
|
||||
func (gce *GcError) AddChildError(message string, userCaused bool) *GcError {
|
||||
child := NewError(message, userCaused)
|
||||
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
|
||||
}
|
||||
|
@ -85,3 +93,14 @@ 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
|
||||
}
|
||||
|
|
|
@ -39,23 +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) error {
|
||||
func MinifyTemplate(tmpl *template.Template, data interface{}, writer io.Writer, mediaType string) *GcError {
|
||||
if !canMinify(mediaType) {
|
||||
return tmpl.Execute(writer, data)
|
||||
return FromError(tmpl.Execute(writer, data), false)
|
||||
}
|
||||
|
||||
minWriter := minifier.Writer(mediaType, writer)
|
||||
defer minWriter.Close()
|
||||
return tmpl.Execute(minWriter, data)
|
||||
return FromError(tmpl.Execute(minWriter, data), false)
|
||||
}
|
||||
|
||||
// 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, error) {
|
||||
func MinifyWriter(writer io.Writer, data []byte, mediaType string) (int, *GcError) {
|
||||
if !canMinify(mediaType) {
|
||||
return writer.Write(data)
|
||||
n, err := writer.Write(data)
|
||||
return n, FromError(err, false)
|
||||
}
|
||||
|
||||
minWriter := minifier.Writer(mediaType, writer)
|
||||
defer minWriter.Close()
|
||||
return minWriter.Write(data)
|
||||
n, err := minWriter.Write(data)
|
||||
return n, FromError(err, false)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -23,8 +22,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrEmptyDurationString = errors.New("Empty Duration string")
|
||||
ErrInvalidDurationString = errors.New("Invalid Duration string")
|
||||
ErrEmptyDurationString = NewError("Empty Duration string", true)
|
||||
ErrInvalidDurationString = NewError("Invalid Duration string", true)
|
||||
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?)?$`)
|
||||
)
|
||||
|
||||
|
@ -177,7 +176,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, error) {
|
||||
func ParseDurationString(str string) (time.Duration, *GcError) {
|
||||
if str == "" {
|
||||
return 0, ErrEmptyDurationString
|
||||
}
|
||||
|
@ -216,7 +215,8 @@ func ParseDurationString(str string) (time.Duration, error) {
|
|||
seconds, _ := strconv.Atoi(matches[0][14])
|
||||
expire += seconds
|
||||
}
|
||||
return time.ParseDuration(strconv.Itoa(expire) + "s")
|
||||
dur, gErr := time.ParseDuration(strconv.Itoa(expire) + "s")
|
||||
return dur, FromError(gErr, false)
|
||||
}
|
||||
|
||||
// ParseName takes a name string from a request object and returns the name and tripcode parts
|
||||
|
|
|
@ -31,46 +31,44 @@ 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 `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, *gcutil.GcError) `json:"-"` //return string of html output
|
||||
}
|
||||
|
||||
var manageFunctions = map[string]ManageFunction{
|
||||
"cleanup": {
|
||||
Title: "Cleanup",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = `<h2 class="manage-header">Cleanup</h2><br />`
|
||||
var err error
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
htmlOut = `<h2 class="manage-header">Cleanup</h2><br />`
|
||||
|
||||
if request.FormValue("run") == "Run Cleanup" {
|
||||
html += "Removing deleted posts from the database.<hr />"
|
||||
htmlOut += "Removing deleted posts from the database.<hr />"
|
||||
if err = gcsql.PermanentlyRemoveDeletedPosts(); err != nil {
|
||||
return html + "<tr><td>" +
|
||||
gclog.Print(gclog.LErrorLog, "Error removing deleted posts from database: ", err.Error()) +
|
||||
"</td></tr></table>"
|
||||
err.Message = gclog.Print(gclog.LErrorLog, "Error removing deleted posts from database: ", err.Message)
|
||||
return htmlOut + "<tr><td>" + err.Message + "</td></tr></table>", err
|
||||
}
|
||||
// TODO: remove orphaned replies and uploads
|
||||
|
||||
html += "Optimizing all tables in database.<hr />"
|
||||
htmlOut += "Optimizing all tables in database.<hr />"
|
||||
err = gcsql.OptimizeDatabase()
|
||||
if err != nil {
|
||||
return html + "<tr><td>" +
|
||||
gclog.Print(gclog.LErrorLog, "Error optimizing SQL tables: ", err.Error()) +
|
||||
"</td></tr></table>"
|
||||
err.Message = gclog.Print(gclog.LErrorLog, "Error optimizing SQL tables: ", err.Error())
|
||||
return htmlOut + "<tr><td>" + err.Message + "</td></tr></table>", err
|
||||
}
|
||||
|
||||
html += "Cleanup finished"
|
||||
htmlOut += "Cleanup finished"
|
||||
} else {
|
||||
html += `<form action="/manage?action=cleanup" method="post">` +
|
||||
htmlOut += `<form action="/manage?action=cleanup" method="post">` +
|
||||
`<input name="run" id="run" type="submit" value="Run Cleanup" />` +
|
||||
`</form>`
|
||||
}
|
||||
return
|
||||
return htmlOut, nil
|
||||
}},
|
||||
"config": {
|
||||
Title: "Configuration",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
do := request.FormValue("do")
|
||||
var status string
|
||||
if do == "save" {
|
||||
|
@ -273,18 +271,20 @@ var manageFunctions = map[string]ManageFunction{
|
|||
}
|
||||
}
|
||||
manageConfigBuffer := bytes.NewBufferString("")
|
||||
if err := gctemplates.ManageConfig.Execute(manageConfigBuffer,
|
||||
map[string]interface{}{"config": config.Config, "status": status},
|
||||
if err = gcutil.FromError(gctemplates.ManageConfig.Execute(manageConfigBuffer,
|
||||
map[string]interface{}{"config": config.Config, "status": status}), false,
|
||||
); err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog, "Error executing config management page: ", err.Error())
|
||||
err.Message = gclog.Print(gclog.LErrorLog,
|
||||
"Error executing config management page: ", err.Message)
|
||||
return htmlOut + err.Message, err
|
||||
}
|
||||
html += manageConfigBuffer.String()
|
||||
return
|
||||
htmlOut += manageConfigBuffer.String()
|
||||
return htmlOut, nil
|
||||
}},
|
||||
"login": {
|
||||
Title: "Login",
|
||||
Permissions: 0,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
if GetStaffRank(request) > 0 {
|
||||
http.Redirect(writer, request, path.Join(config.Config.SiteWebfolder, "manage"), http.StatusFound)
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ var manageFunctions = map[string]ManageFunction{
|
|||
}
|
||||
if username == "" || password == "" {
|
||||
//assume that they haven't logged in
|
||||
html = `<form method="POST" action="` + config.Config.SiteWebfolder + `manage?action=login" id="login-box" class="staff-form">` +
|
||||
htmlOut = `<form method="POST" action="` + config.Config.SiteWebfolder + `manage?action=login" id="login-box" class="staff-form">` +
|
||||
`<input type="hidden" name="redirect" value="` + redirectAction + `" />` +
|
||||
`<input type="text" name="username" class="logindata" /><br />` +
|
||||
`<input type="password" name="password" class="logindata" /><br />` +
|
||||
|
@ -312,40 +312,40 @@ var manageFunctions = map[string]ManageFunction{
|
|||
"logout": {
|
||||
Title: "Logout",
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
cookie, _ := request.Cookie("sessiondata")
|
||||
cookie.MaxAge = 0
|
||||
cookie.Expires = time.Now().Add(-7 * 24 * time.Hour)
|
||||
http.SetCookie(writer, cookie)
|
||||
return "Logged out successfully"
|
||||
return "Logged out successfully", nil
|
||||
}},
|
||||
"announcements": {
|
||||
Title: "Announcements",
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html = `<h1 class="manage-header">Announcements</h1><br />`
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
htmlOut = `<h1 class="manage-header">Announcements</h1><br />`
|
||||
|
||||
//get all announcements to announcement list
|
||||
//loop to html if exist, no announcement if empty
|
||||
announcements, err := gcsql.GetAllAccouncements()
|
||||
if err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog, "Error getting announcements: ", err.Error())
|
||||
return "", err
|
||||
}
|
||||
if len(announcements) == 0 {
|
||||
html += "No announcements"
|
||||
htmlOut += "No announcements"
|
||||
} else {
|
||||
for _, announcement := range announcements {
|
||||
html += `<div class="section-block">` +
|
||||
htmlOut += `<div class="section-block">` +
|
||||
`<div class="section-title-block"><b>` + announcement.Subject + `</b> by ` + announcement.Poster + ` at ` + announcement.Timestamp.Format(config.Config.DateTimeFormat) + `</div>` +
|
||||
`<div class="section-body">` + announcement.Message + `</div></div>`
|
||||
}
|
||||
}
|
||||
return html
|
||||
return htmlOut, nil
|
||||
}},
|
||||
"bans": {
|
||||
Title: "Bans",
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (pageHTML string) { //TODO whatever this does idk man
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) { //TODO whatever this does idk man
|
||||
var post gcsql.Post
|
||||
if request.FormValue("do") == "add" {
|
||||
ip := request.FormValue("ip")
|
||||
|
@ -357,7 +357,8 @@ var manageFunctions = map[string]ManageFunction{
|
|||
permaban := (durationForm == "" || durationForm == "0" || durationForm == "forever")
|
||||
duration, err := gcutil.ParseDurationString(durationForm)
|
||||
if err != nil {
|
||||
serverutil.ServeErrorPage(writer, err.Error())
|
||||
err.UserError = true
|
||||
return "", err
|
||||
}
|
||||
expires := time.Now().Add(duration)
|
||||
|
||||
|
@ -366,88 +367,85 @@ var manageFunctions = map[string]ManageFunction{
|
|||
staffNote := html.EscapeString(request.FormValue("staffnote"))
|
||||
currentStaff, _ := getCurrentStaff(request)
|
||||
|
||||
err = nil
|
||||
if filename != "" {
|
||||
err = gcsql.CreateFileNameBan(filename, nameIsRegex, currentStaff, permaban, staffNote, boards)
|
||||
}
|
||||
if err != nil {
|
||||
pageHTML += err.Error()
|
||||
htmlOut += err.Error()
|
||||
err = nil
|
||||
}
|
||||
if name != "" {
|
||||
err = gcsql.CreateUserNameBan(name, nameIsRegex, currentStaff, permaban, staffNote, boards)
|
||||
}
|
||||
if err != nil {
|
||||
pageHTML += err.Error()
|
||||
err = nil
|
||||
if err = gcsql.CreateUserNameBan(name, nameIsRegex, currentStaff, permaban, staffNote, boards); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if request.FormValue("fullban") == "on" {
|
||||
err = gcsql.CreateUserBan(ip, false, currentStaff, boards, expires, permaban, staffNote, reason, true, time.Now())
|
||||
if err != nil {
|
||||
pageHTML += err.Error()
|
||||
err = nil
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
if request.FormValue("threadban") == "on" {
|
||||
err = gcsql.CreateUserBan(ip, true, currentStaff, boards, expires, permaban, staffNote, reason, true, time.Now())
|
||||
if err != nil {
|
||||
pageHTML += err.Error()
|
||||
err = nil
|
||||
return "", err
|
||||
|
||||
}
|
||||
}
|
||||
if request.FormValue("imageban") == "on" {
|
||||
err = gcsql.CreateFileBan(checksum, currentStaff, permaban, staffNote, boards)
|
||||
if err != nil {
|
||||
pageHTML += err.Error()
|
||||
err = nil
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if request.FormValue("postid") != "" {
|
||||
var err error
|
||||
var err *gcutil.GcError
|
||||
post, err = gcsql.GetSpecificPostByString(request.FormValue("postid"))
|
||||
if err != nil {
|
||||
return pageHTML + gclog.Print(gclog.LErrorLog, "Error getting post: ", err.Error())
|
||||
err.Message = "Error getting post: " + err.Message
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
banlist, err := gcsql.GetAllBans()
|
||||
if err != nil {
|
||||
return pageHTML + gclog.Print(gclog.LErrorLog, "Error getting ban list: ", err.Error())
|
||||
err.Message = "Error getting ban list: " + err.Message
|
||||
return "", err
|
||||
}
|
||||
manageBansBuffer := bytes.NewBufferString("")
|
||||
|
||||
if err := gctemplates.ManageBans.Execute(manageBansBuffer,
|
||||
if err = gcutil.FromError(gctemplates.ManageBans.Execute(manageBansBuffer,
|
||||
map[string]interface{}{"config": config.Config, "banlist": banlist, "post": post},
|
||||
); err != nil {
|
||||
return pageHTML + gclog.Print(gclog.LErrorLog, "Error executing ban management page template: ", err.Error())
|
||||
), false); err != nil {
|
||||
err.Message = "Error executing ban management page template: " + err.Message
|
||||
return "", err
|
||||
}
|
||||
pageHTML += manageBansBuffer.String()
|
||||
htmlOut += manageBansBuffer.String()
|
||||
return
|
||||
}},
|
||||
"getstaffjquery": {
|
||||
Permissions: 0,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
staff, err := getCurrentFullStaff(request)
|
||||
if err != nil {
|
||||
html = "nobody;0;"
|
||||
return
|
||||
return err.JSON(), err
|
||||
}
|
||||
html = staff.Username + ";" + strconv.Itoa(staff.Rank)
|
||||
return
|
||||
htmlOut, gErr := gcutil.MarshalJSON(staff, false)
|
||||
return htmlOut, gcutil.FromError(gErr, false)
|
||||
}},
|
||||
"boards": {
|
||||
Title: "Boards",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
do := request.FormValue("do")
|
||||
var done bool
|
||||
board := new(gcsql.Board)
|
||||
var boardCreationStatus string
|
||||
var err error
|
||||
var gErr error
|
||||
for !done {
|
||||
switch {
|
||||
case do == "add":
|
||||
|
@ -458,8 +456,8 @@ var manageFunctions = map[string]ManageFunction{
|
|||
continue
|
||||
}
|
||||
orderStr := request.FormValue("order")
|
||||
board.ListOrder, err = strconv.Atoi(orderStr)
|
||||
if err != nil {
|
||||
board.ListOrder, gErr = strconv.Atoi(orderStr)
|
||||
if gErr != nil {
|
||||
board.ListOrder = 0
|
||||
}
|
||||
board.Title = request.FormValue("title")
|
||||
|
@ -476,17 +474,17 @@ var manageFunctions = map[string]ManageFunction{
|
|||
}
|
||||
|
||||
board.CreatedOn = time.Now()
|
||||
board.Section, err = strconv.Atoi(sectionStr)
|
||||
if err != nil {
|
||||
board.Section, gErr = strconv.Atoi(sectionStr)
|
||||
if gErr != nil {
|
||||
board.Section = 0
|
||||
}
|
||||
board.MaxFilesize, err = strconv.Atoi(request.FormValue("maximagesize"))
|
||||
board.MaxFilesize, gErr = strconv.Atoi(request.FormValue("maximagesize"))
|
||||
if err != nil {
|
||||
board.MaxFilesize = 1024 * 4
|
||||
}
|
||||
|
||||
board.MaxPages, err = strconv.Atoi(request.FormValue("maxpages"))
|
||||
if err != nil {
|
||||
board.MaxPages, gErr = strconv.Atoi(request.FormValue("maxpages"))
|
||||
if gErr != nil {
|
||||
board.MaxPages = 11
|
||||
}
|
||||
|
||||
|
@ -499,23 +497,23 @@ var manageFunctions = map[string]ManageFunction{
|
|||
board.Anonymous = "Anonymous"
|
||||
}
|
||||
|
||||
board.MaxAge, err = strconv.Atoi(request.FormValue("maxage"))
|
||||
if err != nil {
|
||||
board.MaxAge, gErr = strconv.Atoi(request.FormValue("maxage"))
|
||||
if gErr != nil {
|
||||
board.MaxAge = 0
|
||||
}
|
||||
|
||||
board.AutosageAfter, err = strconv.Atoi(request.FormValue("autosageafter"))
|
||||
if err != nil {
|
||||
board.AutosageAfter, gErr = strconv.Atoi(request.FormValue("autosageafter"))
|
||||
if gErr != nil {
|
||||
board.AutosageAfter = 200
|
||||
}
|
||||
|
||||
board.NoImagesAfter, err = strconv.Atoi(request.FormValue("noimagesafter"))
|
||||
if err != nil {
|
||||
board.NoImagesAfter, gErr = strconv.Atoi(request.FormValue("noimagesafter"))
|
||||
if gErr != nil {
|
||||
board.NoImagesAfter = 0
|
||||
}
|
||||
|
||||
board.MaxMessageLength, err = strconv.Atoi(request.FormValue("maxmessagelength"))
|
||||
if err != nil {
|
||||
board.MaxMessageLength, gErr = strconv.Atoi(request.FormValue("maxmessagelength"))
|
||||
if gErr != nil {
|
||||
board.MaxMessageLength = 1024 * 8
|
||||
}
|
||||
|
||||
|
@ -525,37 +523,37 @@ var manageFunctions = map[string]ManageFunction{
|
|||
board.EnableCatalog = (request.FormValue("enablecatalog") == "on")
|
||||
|
||||
//actually start generating stuff
|
||||
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir), 0666); err != nil {
|
||||
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir), 0666); gErr != nil {
|
||||
do = ""
|
||||
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/ already exists.",
|
||||
config.Config.DocumentRoot, board.Dir)
|
||||
break
|
||||
}
|
||||
|
||||
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "res"), 0666); err != nil {
|
||||
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "res"), 0666); gErr != nil {
|
||||
do = ""
|
||||
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/res/ already exists.",
|
||||
config.Config.DocumentRoot, board.Dir)
|
||||
break
|
||||
}
|
||||
|
||||
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "src"), 0666); err != nil {
|
||||
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "src"), 0666); gErr != nil {
|
||||
do = ""
|
||||
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/src/ already exists.",
|
||||
config.Config.DocumentRoot, board.Dir)
|
||||
break
|
||||
}
|
||||
|
||||
if err = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "thumb"), 0666); err != nil {
|
||||
if gErr = os.Mkdir(path.Join(config.Config.DocumentRoot, board.Dir, "thumb"), 0666); gErr != nil {
|
||||
do = ""
|
||||
boardCreationStatus = gclog.Printf(gclog.LStaffLog|gclog.LErrorLog, "Directory %s/%s/thumb/ already exists.",
|
||||
config.Config.DocumentRoot, board.Dir)
|
||||
break
|
||||
}
|
||||
|
||||
if err := gcsql.CreateBoard(board); err != nil {
|
||||
if gErr = gcsql.CreateBoard(board); err != nil {
|
||||
do = ""
|
||||
boardCreationStatus = gclog.Print(gclog.LErrorLog, "Error creating board: ", err.Error())
|
||||
boardCreationStatus = gclog.Print(gclog.LErrorLog, "Error creating board: ", gErr.Error())
|
||||
break
|
||||
} else {
|
||||
boardCreationStatus = "Board created successfully"
|
||||
|
@ -583,30 +581,34 @@ var manageFunctions = map[string]ManageFunction{
|
|||
board.ThreadsPerPage = config.Config.ThreadsPerPage
|
||||
}
|
||||
|
||||
html = `<h1 class="manage-header">Manage boards</h1><form action="/manage?action=boards" method="POST"><input type="hidden" name="do" value="existing" /><select name="boardselect"><option>Select board...</option>`
|
||||
boards, err := gcsql.GetBoardUris()
|
||||
htmlOut = `<h1 class="manage-header">Manage boards</h1><form action="/manage?action=boards" method="POST"><input type="hidden" name="do" value="existing" /><select name="boardselect"><option>Select board...</option>`
|
||||
var boards []string
|
||||
boards, err = gcsql.GetBoardUris()
|
||||
if err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog, "Error getting board list: ", err.Error())
|
||||
err.Message = gclog.Print(gclog.LErrorLog,
|
||||
"Error getting board list: ", err.Message)
|
||||
return "", err
|
||||
}
|
||||
for _, boardDir := range boards {
|
||||
html += "<option>" + boardDir + "</option>"
|
||||
htmlOut += "<option>" + boardDir + "</option>"
|
||||
}
|
||||
|
||||
html += `</select><input type="submit" value="Edit" /><input type="submit" value="Delete" /></form><hr />` +
|
||||
htmlOut += `</select><input type="submit" value="Edit" /><input type="submit" value="Delete" /></form><hr />` +
|
||||
`<h2 class="manage-header">Create new board</h2><span id="board-creation-message">` + boardCreationStatus + `</span><br />`
|
||||
|
||||
manageBoardsBuffer := bytes.NewBufferString("")
|
||||
gcsql.AllSections, _ = gcsql.GetAllSectionsOrCreateDefault()
|
||||
|
||||
if err := gctemplates.ManageBoards.Execute(manageBoardsBuffer, map[string]interface{}{
|
||||
if err = gcutil.FromError(gctemplates.ManageBoards.Execute(manageBoardsBuffer, map[string]interface{}{
|
||||
"config": config.Config,
|
||||
"board": board,
|
||||
"section_arr": gcsql.AllSections,
|
||||
}); err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog,
|
||||
"Error executing board management page template: ", err.Error())
|
||||
}), false); err != nil {
|
||||
err.Message = gclog.Print(gclog.LErrorLog,
|
||||
"Error executing board management page template: ", err.Message)
|
||||
return "", err
|
||||
}
|
||||
html += manageBoardsBuffer.String()
|
||||
htmlOut += manageBoardsBuffer.String()
|
||||
return
|
||||
}
|
||||
gcsql.ResetBoardSectionArrays()
|
||||
|
@ -615,13 +617,13 @@ var manageFunctions = map[string]ManageFunction{
|
|||
"staffmenu": {
|
||||
Title: "Staff menu",
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
rank := GetStaffRank(request)
|
||||
|
||||
html = `<a href="javascript:void(0)" id="logout" class="staffmenu-item">Log out</a><br />` +
|
||||
htmlOut = `<a href="javascript:void(0)" id="logout" class="staffmenu-item">Log out</a><br />` +
|
||||
`<a href="javascript:void(0)" id="announcements" class="staffmenu-item">Announcements</a><br />`
|
||||
if rank == 3 {
|
||||
html += `<b>Admin stuff</b><br /><a href="javascript:void(0)" id="staff" class="staffmenu-item">Manage staff</a><br />` +
|
||||
htmlOut += `<b>Admin stuff</b><br /><a href="javascript:void(0)" id="staff" class="staffmenu-item">Manage staff</a><br />` +
|
||||
//`<a href="javascript:void(0)" id="purgeeverything" class="staffmenu-item">Purge everything!</a><br />` +
|
||||
`<a href="javascript:void(0)" id="executesql" class="staffmenu-item">Execute SQL statement(s)</a><br />` +
|
||||
`<a href="javascript:void(0)" id="cleanup" class="staffmenu-item">Run cleanup</a><br />` +
|
||||
|
@ -632,12 +634,12 @@ var manageFunctions = map[string]ManageFunction{
|
|||
`<a href="javascript:void(0)" id="boards" class="staffmenu-item">Add/edit/delete boards</a><br />`
|
||||
}
|
||||
if rank >= 2 {
|
||||
html += `<b>Mod stuff</b><br />` +
|
||||
htmlOut += `<b>Mod stuff</b><br />` +
|
||||
`<a href="javascript:void(0)" id="bans" class="staffmenu-item">Ban User(s)</a><br />`
|
||||
}
|
||||
|
||||
if rank >= 1 {
|
||||
html += `<a href="javascript:void(0)" id="recentimages" class="staffmenu-item">Recently uploaded images</a><br />` +
|
||||
htmlOut += `<a href="javascript:void(0)" id="recentimages" class="staffmenu-item">Recently uploaded images</a><br />` +
|
||||
`<a href="javascript:void(0)" id="recentposts" class="staffmenu-item">Recent posts</a><br />` +
|
||||
`<a href="javascript:void(0)" id="searchip" class="staffmenu-item">Search posts by IP</a><br />`
|
||||
}
|
||||
|
@ -646,61 +648,87 @@ var manageFunctions = map[string]ManageFunction{
|
|||
"rebuildfront": {
|
||||
Title: "Rebuild front page",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
gctemplates.InitTemplates()
|
||||
return building.BuildFrontPage()
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
if err = gctemplates.InitTemplates(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Built front page successfully", building.BuildFrontPage()
|
||||
}},
|
||||
"rebuildall": {
|
||||
Title: "Rebuild everything",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
gctemplates.InitTemplates()
|
||||
gcsql.ResetBoardSectionArrays()
|
||||
return building.BuildFrontPage() + "<hr />" +
|
||||
building.BuildBoardListJSON() + "<hr />" +
|
||||
building.BuildBoards() + "<hr />" +
|
||||
building.BuildJS() + "<hr />"
|
||||
if err = building.BuildFrontPage(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = building.BuildBoardListJSON(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = building.BuildBoards(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = building.BuildJS(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}},
|
||||
"rebuildboards": {
|
||||
Title: "Rebuild boards",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
gctemplates.InitTemplates()
|
||||
return building.BuildBoards()
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
if err = gctemplates.InitTemplates(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "Boards built successfully", building.BuildBoards()
|
||||
}},
|
||||
"reparsehtml": {
|
||||
Title: "Reparse HTML",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
messages, err := gcsql.GetAllNondeletedMessageRaw()
|
||||
if err != nil {
|
||||
html += err.Error() + "<br />"
|
||||
return
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, message := range messages {
|
||||
message.Message = posting.FormatMessage(message.MessageRaw)
|
||||
}
|
||||
err = gcsql.SetFormattedInDatabase(messages)
|
||||
|
||||
if err != nil {
|
||||
return html + gclog.Printf(gclog.LErrorLog, err.Error())
|
||||
if err = gcsql.SetFormattedInDatabase(messages); err != nil {
|
||||
return "", err
|
||||
}
|
||||
html += "Done reparsing HTML<hr />" +
|
||||
building.BuildFrontPage() + "<hr />" +
|
||||
building.BuildBoardListJSON() + "<hr />" +
|
||||
building.BuildBoards() + "<hr />"
|
||||
htmlOut += "Done reparsing HTML<hr />"
|
||||
|
||||
if err = building.BuildFrontPage(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
htmlOut += "Done building front page<hr />"
|
||||
|
||||
if err = building.BuildBoardListJSON(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
htmlOut += "Done building board list JSON<hr />"
|
||||
|
||||
if err = building.BuildBoards(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
htmlOut += "Done building boards<hr />"
|
||||
return
|
||||
}},
|
||||
"recentposts": {
|
||||
Title: "Recent posts",
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
limit := request.FormValue("limit")
|
||||
if limit == "" {
|
||||
limit = "50"
|
||||
}
|
||||
html = `<h1 class="manage-header">Recent posts</h1>` +
|
||||
htmlOut = `<h1 class="manage-header">Recent posts</h1>` +
|
||||
`Limit by: <select id="limit">` +
|
||||
`<option>25</option><option>50</option><option>100</option><option>200</option>` +
|
||||
`</select><br /><table width="100%%d" border="1">` +
|
||||
|
@ -709,49 +737,46 @@ 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 {
|
||||
return html + "<tr><td>" + gclog.Print(gclog.LErrorLog, "Error getting recent posts: ",
|
||||
err.Error()) + "</td></tr></table>"
|
||||
err.Message = "Error getting recent posts: " + err.Message
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, recentpost := range recentposts {
|
||||
html += fmt.Sprintf(
|
||||
htmlOut += fmt.Sprintf(
|
||||
`<tr><td><b>Post:</b> <a href="%s">%s/%d</a><br /><b>IP:</b> %s</td><td>%s</td><td>%s</td></tr>`,
|
||||
path.Join(config.Config.SiteWebfolder, recentpost.BoardName, "/res/", strconv.Itoa(recentpost.ParentID)+".html#"+strconv.Itoa(recentpost.PostID)),
|
||||
recentpost.BoardName, recentpost.PostID, recentpost.IP, string(recentpost.Message),
|
||||
recentpost.Timestamp.Format("01/02/06, 15:04"),
|
||||
)
|
||||
}
|
||||
html += "</table>"
|
||||
htmlOut += "</table>"
|
||||
return
|
||||
}},
|
||||
"postinfo": {
|
||||
Title: "Post info",
|
||||
Permissions: 2,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
errMap := map[string]interface{}{
|
||||
"action": "postInfo",
|
||||
"success": false,
|
||||
}
|
||||
post, err := gcsql.GetSpecificPost(gcutil.HackyStringToInt(request.FormValue("postid")), false)
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
var post gcsql.Post
|
||||
post, err = gcsql.GetSpecificPost(gcutil.HackyStringToInt(request.FormValue("postid")), false)
|
||||
if err != nil {
|
||||
errMap["message"] = err.Error()
|
||||
jsonErr, _ := gcutil.MarshalJSON(errMap, false)
|
||||
return jsonErr
|
||||
return err.JSON(), nil
|
||||
}
|
||||
jsonStr, _ := gcutil.MarshalJSON(post, false)
|
||||
return jsonStr
|
||||
return jsonStr, nil
|
||||
}},
|
||||
"staff": {
|
||||
Title: "Staff",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
var allStaff []gcsql.Staff
|
||||
do := request.FormValue("do")
|
||||
html = `<h1 class="manage-header">Staff</h1><br />` +
|
||||
htmlOut = `<h1 class="manage-header">Staff</h1><br />` +
|
||||
`<table id="stafftable" border="1">` +
|
||||
"<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()
|
||||
allStaff, err = gcsql.GetAllStaffNopass()
|
||||
if err != nil {
|
||||
return html + gclog.Print(gclog.LErrorLog, "Error getting staff list: ", err.Error())
|
||||
err.Message = gclog.Print(gclog.LErrorLog, "Error getting staff list: ", err.Message)
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, staff := range allStaff {
|
||||
|
@ -760,7 +785,7 @@ var manageFunctions = map[string]ManageFunction{
|
|||
rank := request.FormValue("rank")
|
||||
rankI, _ := strconv.Atoi(rank)
|
||||
if do == "add" {
|
||||
if err := gcsql.NewStaff(username, password, rankI); err != nil {
|
||||
if err = gcsql.NewStaff(username, password, rankI); err != nil {
|
||||
serverutil.ServeErrorPage(writer, gclog.Printf(gclog.LErrorLog,
|
||||
"Error creating new staff account %q: %s", username, err.Error()))
|
||||
return
|
||||
|
@ -781,12 +806,12 @@ var manageFunctions = map[string]ManageFunction{
|
|||
case staff.Rank == 1:
|
||||
rank = "janitor"
|
||||
}
|
||||
html += fmt.Sprintf(
|
||||
htmlOut += fmt.Sprintf(
|
||||
`<tr><td>%s</td><td>%s</td><td>%s</td><td><a href="/manage?action=staff&do=del&username=%s" style="float:right;color:red;">X</a></td></tr>`,
|
||||
staff.Username, rank, staff.AddedOn.Format(config.Config.DateTimeFormat), staff.Username)
|
||||
|
||||
}
|
||||
html += `</table><hr /><h2 class="manage-header">Add new staff</h2>` +
|
||||
htmlOut += `</table><hr /><h2 class="manage-header">Add new staff</h2>` +
|
||||
`<form action="/manage?action=staff" onsubmit="return makeNewStaff();" method="POST">` +
|
||||
`<input type="hidden" name="do" value="add" />` +
|
||||
`Username: <input id="username" name="username" type="text" /><br />` +
|
||||
|
@ -803,14 +828,14 @@ var manageFunctions = map[string]ManageFunction{
|
|||
"tempposts": {
|
||||
Title: "Temporary posts lists",
|
||||
Permissions: 3,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
html += `<h1 class="manage-header">Temporary posts</h1>`
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (htmlOut string, err *gcutil.GcError) {
|
||||
htmlOut += `<h1 class="manage-header">Temporary posts</h1>`
|
||||
if len(gcsql.TempPosts) == 0 {
|
||||
html += "No temporary posts<br />"
|
||||
htmlOut += "No temporary posts<br />"
|
||||
return
|
||||
}
|
||||
for p, post := range gcsql.TempPosts {
|
||||
html += fmt.Sprintf("Post[%d]: %#v<br />", p, post)
|
||||
htmlOut += fmt.Sprintf("Post[%d]: %#v<br />", p, post)
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
|
|
@ -7,54 +7,68 @@ 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 error
|
||||
if err = request.ParseForm(); err != nil {
|
||||
var err *gcutil.GcError
|
||||
var gErr error
|
||||
if gErr = request.ParseForm(); gErr != nil {
|
||||
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog,
|
||||
"Error parsing form data: ", err.Error()))
|
||||
"Error parsing form data: ", gErr.Error()))
|
||||
}
|
||||
|
||||
action := request.FormValue("action")
|
||||
staffRank := GetStaffRank(request)
|
||||
var managePageBuffer bytes.Buffer
|
||||
if action == "postinfo" {
|
||||
if action == "postinfo" || action == "getstaffjquery" {
|
||||
writer.Header().Add("Content-Type", "application/json")
|
||||
writer.Header().Add("Cache-Control", "max-age=5, must-revalidate")
|
||||
}
|
||||
|
||||
if action != "getstaffjquery" && action != "postinfo" {
|
||||
} else {
|
||||
managePageBuffer.WriteString("<!DOCTYPE html><html><head>")
|
||||
if err = gctemplates.ManageHeader.Execute(&managePageBuffer, config.Config); err != nil {
|
||||
if gErr = gctemplates.ManageHeader.Execute(&managePageBuffer, config.Config); gErr != nil {
|
||||
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog|gclog.LStaffLog,
|
||||
"Error executing manage page header template: ", err.Error()))
|
||||
"Error executing manage page header template: ", gErr.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if action == "" {
|
||||
managePageBuffer.Write([]byte(actionHTMLLinker(manageFunctions)))
|
||||
managePageBuffer.WriteString(actionHTMLLinker(manageFunctions))
|
||||
} else {
|
||||
if _, ok := manageFunctions[action]; ok {
|
||||
if staffRank >= manageFunctions[action].Permissions {
|
||||
managePageBuffer.Write([]byte(manageFunctions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 && manageFunctions[action].Permissions == 0 {
|
||||
managePageBuffer.Write([]byte(manageFunctions[action].Callback(writer, request)))
|
||||
} else if staffRank == 0 {
|
||||
managePageBuffer.Write([]byte(manageFunctions["login"].Callback(writer, request)))
|
||||
} else {
|
||||
managePageBuffer.Write([]byte(action + " is undefined."))
|
||||
}
|
||||
} else {
|
||||
managePageBuffer.Write([]byte(action + " is undefined."))
|
||||
handler, ok := manageFunctions[action]
|
||||
var htmlOut string
|
||||
|
||||
if !ok {
|
||||
serverutil.ServeNotFound(writer, request)
|
||||
return
|
||||
}
|
||||
if staffRank == 0 && handler.Permissions > 0 {
|
||||
handler = manageFunctions["login"]
|
||||
} else if staffRank < handler.Permissions {
|
||||
writer.WriteHeader(403)
|
||||
serverutil.ServeErrorPage(writer, "You don't have permission to access this page.")
|
||||
staffName, _ := getCurrentStaff(request)
|
||||
gclog.Printf(gclog.LStaffLog,
|
||||
"Rejected request to manage page %s from %s (insufficient permissions)", action, staffName)
|
||||
return
|
||||
}
|
||||
htmlOut, err = handler.Callback(writer, request)
|
||||
if err != nil {
|
||||
staffName, _ := getCurrentStaff(request)
|
||||
// writer.WriteHeader(500)
|
||||
serverutil.ServeErrorPage(writer, err.Error())
|
||||
gclog.Printf(gclog.LStaffLog|gclog.LErrorLog,
|
||||
"Error accessing manage page %s by %s: %s", action, staffName, err.Error())
|
||||
return
|
||||
}
|
||||
managePageBuffer.WriteString(htmlOut)
|
||||
}
|
||||
if action != "getstaffjquery" && action != "postinfo" {
|
||||
managePageBuffer.Write([]byte("</body></html>"))
|
||||
managePageBuffer.WriteString("</body></html>")
|
||||
}
|
||||
|
||||
writer.Write(managePageBuffer.Bytes())
|
||||
|
|
|
@ -7,13 +7,13 @@ 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"
|
||||
)
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
sSuccess
|
||||
sSuccess = iota
|
||||
sInvalidPassword
|
||||
sOtherError
|
||||
)
|
||||
|
@ -21,24 +21,24 @@ 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 error
|
||||
var err *gcutil.GcError
|
||||
domain = chopPortNumRegex.Split(domain, -1)[0]
|
||||
|
||||
if !serverutil.ValidReferer(request) {
|
||||
gclog.Print(gclog.LStaffLog, "Rejected login from possible spambot @ "+request.RemoteAddr)
|
||||
return 2
|
||||
return sOtherError
|
||||
}
|
||||
staff, err := gcsql.GetStaffByName(username)
|
||||
if err != nil {
|
||||
gclog.Print(gclog.LErrorLog, err.Error())
|
||||
return 1
|
||||
return sInvalidPassword
|
||||
}
|
||||
|
||||
success := bcrypt.CompareHashAndPassword([]byte(staff.PasswordChecksum), []byte(password))
|
||||
if success == bcrypt.ErrMismatchedHashAndPassword {
|
||||
// password mismatch
|
||||
gclog.Print(gclog.LStaffLog, "Failed login (password mismatch) from "+request.RemoteAddr+" at "+time.Now().Format(gcsql.MySQLDatetimeFormat))
|
||||
return 1
|
||||
return sInvalidPassword
|
||||
}
|
||||
|
||||
// successful login, add cookie that expires in one month
|
||||
|
@ -52,28 +52,28 @@ func createSession(key string, username string, password string, request *http.R
|
|||
|
||||
if err = gcsql.CreateSession(key, username); err != nil {
|
||||
gclog.Print(gclog.LErrorLog, "Error creating new staff session: ", err.Error())
|
||||
return 2
|
||||
return sOtherError
|
||||
}
|
||||
|
||||
return 0
|
||||
return sSuccess
|
||||
}
|
||||
|
||||
func getCurrentStaff(request *http.Request) (string, error) { //TODO after refactor, check if still used
|
||||
func getCurrentStaff(request *http.Request) (string, *gcutil.GcError) { //TODO after refactor, check if still used
|
||||
sessionCookie, err := request.Cookie("sessiondata")
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", gcutil.FromError(err, true)
|
||||
}
|
||||
name, err := gcsql.GetStaffName(sessionCookie.Value)
|
||||
if err == nil {
|
||||
return "", err
|
||||
return "", gcutil.FromError(err, true)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func getCurrentFullStaff(request *http.Request) (*gcsql.Staff, error) {
|
||||
func getCurrentFullStaff(request *http.Request) (*gcsql.Staff, *gcutil.GcError) {
|
||||
sessionCookie, err := request.Cookie("sessiondata")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, gcutil.FromError(err, true)
|
||||
}
|
||||
return gcsql.GetStaffBySession(sessionCookie.Value)
|
||||
}
|
||||
|
|
|
@ -34,22 +34,23 @@ func tempCleaner() {
|
|||
}
|
||||
|
||||
fileSrc := path.Join(config.Config.DocumentRoot, board.Dir, "src", post.FilenameOriginal)
|
||||
if err = os.Remove(fileSrc); err != nil {
|
||||
var gErr error
|
||||
if gErr = os.Remove(fileSrc); gErr != nil {
|
||||
gclog.Printf(errStdLogs,
|
||||
"Error pruning temporary upload for %q: %s", fileSrc, err.Error())
|
||||
"Error pruning temporary upload for %q: %s", fileSrc, gErr.Error())
|
||||
}
|
||||
|
||||
thumbSrc := gcutil.GetThumbnailPath("thread", fileSrc)
|
||||
if err = os.Remove(thumbSrc); err != nil {
|
||||
if gErr = os.Remove(thumbSrc); gErr != nil {
|
||||
gclog.Printf(errStdLogs,
|
||||
"Error pruning temporary upload for %q: %s", thumbSrc, err.Error())
|
||||
"Error pruning temporary upload for %q: %s", thumbSrc, gErr.Error())
|
||||
}
|
||||
|
||||
if post.ParentID == 0 {
|
||||
catalogSrc := gcutil.GetThumbnailPath("catalog", fileSrc)
|
||||
if err = os.Remove(catalogSrc); err != nil {
|
||||
if gErr = os.Remove(catalogSrc); gErr != nil {
|
||||
gclog.Printf(errStdLogs,
|
||||
"Error pruning temporary upload for %s: %s", catalogSrc, err.Error())
|
||||
"Error pruning temporary upload for %s: %s", catalogSrc, gErr.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,5 +94,5 @@ func ValidReferer(request *http.Request) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
return rURL.Host == config.Config.SiteDomain && strings.Index(rURL.Path, config.Config.SiteWebfolder) == 0
|
||||
return strings.Index(rURL.Path, config.Config.SiteWebfolder) == 0
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue