1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-11 11:46:24 -07:00

Remove file i/o from gcsql package for better organization

This commit is contained in:
Eggbertx 2022-09-03 14:13:49 -07:00
parent 5b5d5ab3ec
commit 9542949413
7 changed files with 86 additions and 50 deletions

View file

@ -407,15 +407,35 @@ func utilHandler(writer http.ResponseWriter, request *http.Request) {
if fileOnly {
fileName := post.Filename
if fileName != "" && fileName != "deleted" {
if err = post.DeleteFiles(true); err != nil {
if wantsJSON {
serverutil.ServeJSON(writer, map[string]interface{}{
"error": err,
var files []string
var errStr string
if files, err = post.GetFilePaths(); err != nil {
errStr = gclog.Print(gclog.LErrorLog, "Error getting file upload info: ", err.Error())
serverutil.ServeError(writer, errStr, wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
}
if err = post.UnlinkUploads(true); err != nil {
gclog.Printf(gclog.LErrorLog,
"Error unlinking post uploads for #%d: %s", post.ID, err.Error())
serverutil.ServeError(writer, err.Error(), wantsJSON, map[string]interface{}{
"postid": post.ID,
})
return
}
for _, filePath := range files {
if err = os.Remove(filePath); err != nil {
fileBase := path.Base(filePath)
errStr = gclog.Printf(gclog.LErrorLog, "Error deleting %s: %s", fileBase, err.Error())
serverutil.ServeError(writer, errStr, wantsJSON, map[string]interface{}{
"postid": post.ID,
"file": fileBase,
})
} else {
serverutil.ServeErrorPage(writer, gclog.Print(gclog.LErrorLog,
"Error deleting files from post: ", err.Error()))
return
}
}
}

View file

@ -3,7 +3,6 @@ package gcsql
import (
"database/sql"
"net/http"
"os"
"strconv"
"github.com/gochan-org/gochan/pkg/gclog"
@ -82,6 +81,8 @@ func (board *Board) PopulateData(id int) error {
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))
}
// Delete deletes the board from the database (if a row with the struct's ID exists) and
// returns any errors. It does not remove the board directory or its files
func (board *Board) Delete() error {
exists := DoesBoardExistByID(board.ID)
if !exists {
@ -92,13 +93,6 @@ func (board *Board) Delete() error {
}
const delSql = `DELETE FROM DBPREFIXboards WHERE id = ?`
_, err := ExecSQL(delSql, board.ID)
if err != nil {
return err
}
absPath := board.AbsolutePath()
gclog.Printf(gclog.LStaffLog,
"Deleting board /%s/, absolute path: %s\n", board.Dir, absPath)
err = os.RemoveAll(absPath)
return err
}

View file

@ -1,8 +1,7 @@
package gcsql
import (
"fmt"
"os"
"database/sql"
"path"
"time"
@ -173,44 +172,47 @@ func GetPostsFromIP(ip string, limit int, onlyNotDeleted bool) ([]Post, error) {
return posts, nil
}
func (p *Post) DeleteFiles(leaveDeletedBox bool) error {
board, boardWasFound, err := GetBoardFromPostID(p.ID)
// GetFilePaths returns an array of absolute paths to uploaded files and thumbnails associated
// with this post, and any errors that occurred
func (p *Post) GetFilePaths() ([]string, error) {
boardDir, err := p.GetBoardDir()
if err != nil {
return err
}
if !boardWasFound {
return fmt.Errorf("could not find board for post %v", p.ID)
return nil, err
}
const filenameSQL = `SELECT filename FROM DBPREFIXfiles WHERE post_id = ?`
rows, err := QuerySQL(filenameSQL, p.ID)
if err != nil {
return err
var paths []string
if err == sql.ErrNoRows {
return paths, nil
} else if err != nil {
return nil, err
}
var filenames []string
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
for rows.Next() {
var filename string
if err = rows.Scan(&filename); err != nil {
return err
return paths, err
}
filenames = append(filenames, filename)
}
systemCriticalCfg := config.GetSystemCriticalConfig()
//Remove files from disk
for _, filename := range filenames {
_, filenameBase, fileExt := gcutil.GetFileParts(filename)
thumbExt := fileExt
if thumbExt == "gif" || thumbExt == "webm" || thumbExt == "mp4" {
thumbExt = "jpg"
}
uploadPath := path.Join(systemCriticalCfg.DocumentRoot, board, "/src/", filenameBase+"."+fileExt)
thumbPath := path.Join(systemCriticalCfg.DocumentRoot, board, "/thumb/", filenameBase+"t."+thumbExt)
catalogThumbPath := path.Join(systemCriticalCfg.DocumentRoot, board, "/thumb/", filenameBase+"c."+thumbExt)
os.Remove(uploadPath)
os.Remove(thumbPath)
os.Remove(catalogThumbPath)
paths = append(paths,
path.Join(documentRoot, boardDir, "/src/", filenameBase+"."+fileExt),
path.Join(documentRoot, boardDir, "/thumb/", filenameBase+"t."+thumbExt), // thumbnail path
)
if p.ParentID == 0 {
paths = append(paths, path.Join(documentRoot, boardDir, "/thumb/", filenameBase+"c."+thumbExt)) // catalog thumbnail path
}
}
return paths, nil
}
// UnlinkUploads disassociates the post with any uploads in DBPREFIXfiles
// that may have been uploaded with it, optionally leaving behind a "File Deleted"
// frame where the thumbnail appeared
func (p *Post) UnlinkUploads(leaveDeletedBox bool) error {
var sqlStr string
if leaveDeletedBox {
// leave a "File Deleted" box
@ -218,6 +220,6 @@ func (p *Post) DeleteFiles(leaveDeletedBox bool) error {
} else {
sqlStr = `DELETE FROM DBPREFIXfiles WHERE post_id = ?`
}
_, err = ExecSQL(sqlStr, p.ID)
_, err := ExecSQL(sqlStr, p.ID)
return err
}

View file

@ -257,14 +257,6 @@ func UpdatePost(postID int, email, subject string, message template.HTML, messag
return err
}
// DeleteFilesFromPost deletes all files belonging to a given post
func DeleteFilesFromPost(postID int, leaveDeletedBox bool) error {
post := &Post{
ID: postID,
}
return post.DeleteFiles(leaveDeletedBox)
}
// DeletePost deletes a post with a given ID
func DeletePost(postID int, checkIfTopPost bool) error {
if checkIfTopPost {
@ -281,7 +273,6 @@ func DeletePost(postID int, checkIfTopPost bool) error {
}
}
DeleteFilesFromPost(postID, false)
const sql = `UPDATE DBPREFIXposts SET is_deleted = TRUE, deleted_at = CURRENT_TIMESTAMP WHERE id = ?`
_, err := ExecSQL(sql, postID)
return err

View file

@ -290,7 +290,7 @@ func (p *Post) GetBoardDir() (string, error) {
SELECT board_id FROM DBPREFIXthreads WHERE id = (
SELECT thread_id FROM DBPREFIXposts WHERE id = ? LIMIT 1) LIMIT 1)`
err := QueryRowSQL(sql, []interface{}{p.ParentID}, interfaceSlice(&p.boardDir))
err := QueryRowSQL(sql, []interface{}{p.ID}, interfaceSlice(&p.boardDir))
return p.boardDir, err
}

View file

@ -8,6 +8,7 @@ import (
"html"
"net"
"net/http"
"os"
"path"
"regexp"
"strconv"
@ -530,6 +531,13 @@ var actions = []Action{
Permissions: AdminPerms,
JSONoutput: NoJSON,
Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
var currentUser string
currentUser, err = getCurrentStaff(request)
if err != nil {
return "", errors.New(gclog.Println(gclog.LErrorLog,
"Error parsing current user:", err.Error()))
}
pageBuffer := bytes.NewBufferString("")
var board gcsql.Board
requestType, boardID, err := boardsRequestType(request)
@ -550,6 +558,13 @@ var actions = []Action{
return "", err
}
err = board.Delete()
if err != nil {
return "", err
}
absPath := board.AbsolutePath()
gclog.Printf(gclog.LStaffLog,
"Board /%s/ deleted by %s, absolute path: %s\n", board.Dir, currentUser, absPath)
err = os.RemoveAll(absPath)
case "edit":
// edit button clicked, fill the input fields with board data to be edited
board, err = gcsql.GetBoardFromID(boardID)

View file

@ -18,6 +18,20 @@ func ServeJSON(writer http.ResponseWriter, data map[string]interface{}) {
MinifyWriter(writer, []byte(jsonStr), "application/json")
}
// ServeError serves the given map as a JSON file (with the error string included) if wantsJSON is true,
// otherwise it serves a regular HTML error page
func ServeError(writer http.ResponseWriter, err string, wantsJSON bool, data map[string]interface{}) {
if wantsJSON {
servedMap := data
if _, ok := servedMap["error"]; !ok {
servedMap["error"] = err
}
ServeJSON(writer, servedMap)
} else {
ServeErrorPage(writer, err)
}
}
// ServeErrorPage shows a general error page if something goes wrong
func ServeErrorPage(writer http.ResponseWriter, err string) {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")