mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-09-05 11:06:23 -07:00
Make thumbnail extension determining more dynamic, move to uploads pkg
This commit is contained in:
parent
b0e81aac99
commit
a0c0466725
16 changed files with 173 additions and 172 deletions
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/manage"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
"github.com/rs/zerolog"
|
||||
|
@ -151,7 +152,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
|
|||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
var uploads []upload
|
||||
var postUploads []upload
|
||||
for rows.Next() {
|
||||
var filename string
|
||||
if err = rows.Scan(&filename); err != nil {
|
||||
|
@ -165,7 +166,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
|
|||
})
|
||||
return
|
||||
}
|
||||
uploads = append(uploads, upload{
|
||||
postUploads = append(postUploads, upload{
|
||||
filename: filename,
|
||||
boardDir: board.Dir,
|
||||
})
|
||||
|
@ -173,7 +174,7 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
|
|||
// done as a goroutine to avoid delays if the thread has a lot of files
|
||||
// the downside is of course that if something goes wrong, deletion errors
|
||||
// won't be seen in the browser
|
||||
go deleteUploads(uploads)
|
||||
go deleteUploads(postUploads)
|
||||
} else if deletePostUpload(post, board, writer, request, errEv) {
|
||||
return
|
||||
}
|
||||
|
@ -222,24 +223,24 @@ func deletePosts(checkedPosts []int, writer http.ResponseWriter, request *http.R
|
|||
}
|
||||
}
|
||||
|
||||
func deleteUploads(uploads []upload) {
|
||||
func deleteUploads(postUploads []upload) {
|
||||
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
|
||||
var filePath, thumbPath, catalogThumbPath string
|
||||
var filePath string
|
||||
var err error
|
||||
for _, upload := range uploads {
|
||||
for _, upload := range postUploads {
|
||||
filePath = path.Join(documentRoot, upload.boardDir, "src", upload.filename)
|
||||
if err = os.Remove(filePath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
gcutil.LogError(err).Caller().
|
||||
Str("filePath", filePath).
|
||||
Int("postid", upload.postID).Send()
|
||||
}
|
||||
thumbPath = path.Join(documentRoot, upload.boardDir, "thumb", gcutil.GetThumbnailPath("reply", upload.filename))
|
||||
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
|
||||
path.Join(documentRoot, upload.boardDir, "thumb", upload.filename))
|
||||
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
gcutil.LogError(err).Caller().
|
||||
Str("thumbPath", thumbPath).
|
||||
Int("postid", upload.postID).Send()
|
||||
}
|
||||
catalogThumbPath = path.Join(documentRoot, upload.boardDir, "thumb", gcutil.GetThumbnailPath("catalog", upload.filename))
|
||||
if err = os.Remove(catalogThumbPath); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
gcutil.LogError(err).Caller().
|
||||
Str("catalogThumbPath", catalogThumbPath).
|
||||
|
@ -272,11 +273,11 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
|
|||
return true
|
||||
}
|
||||
// delete the file's thumbnail
|
||||
thumbPath := path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("thumb"))
|
||||
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(path.Join(documentRoot, board.Dir, "thumb", upload.Filename))
|
||||
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postid", post.ID).
|
||||
Str("thumbnail", upload.ThumbnailPath("thumb")).
|
||||
Str("thumbnail", thumbPath).
|
||||
Msg("Unable to delete thumbnail")
|
||||
server.ServeError(writer, "Unable to delete thumbnail: "+err.Error(),
|
||||
wantsJSON, map[string]interface{}{"postid": post.ID})
|
||||
|
@ -284,11 +285,10 @@ func deletePostUpload(post *gcsql.Post, board *gcsql.Board, writer http.Response
|
|||
}
|
||||
// delete the catalog thumbnail
|
||||
if post.IsTopPost {
|
||||
thumbPath := path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("catalog"))
|
||||
if err = os.Remove(thumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
if err = os.Remove(catalogThumbPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postid", post.ID).
|
||||
Str("catalogThumb", upload.ThumbnailPath("catalog")).
|
||||
Str("catalogThumb", catalogThumbPath).
|
||||
Msg("Unable to delete catalog thumbnail")
|
||||
server.ServeError(writer, "Unable to delete catalog thumbnail: "+err.Error(),
|
||||
wantsJSON, map[string]interface{}{"postid": post.ID})
|
||||
|
|
|
@ -148,9 +148,9 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
|
|||
return
|
||||
}
|
||||
|
||||
upload, gotErr := uploads.AttachUploadFromRequest(request, writer, post, board)
|
||||
if gotErr {
|
||||
// AttachUploadFromRequest handles error serving/logging
|
||||
upload, err := uploads.AttachUploadFromRequest(request, writer, post, board)
|
||||
if err != nil {
|
||||
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
||||
return
|
||||
}
|
||||
if upload == nil {
|
||||
|
@ -161,8 +161,8 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
|
|||
var filePath, thumbPath, catalogThumbPath string
|
||||
if oldUpload != nil {
|
||||
filePath = path.Join(documentRoot, board.Dir, "src", oldUpload.Filename)
|
||||
thumbPath = path.Join(documentRoot, board.Dir, "thumb", oldUpload.ThumbnailPath("thumb"))
|
||||
catalogThumbPath = path.Join(documentRoot, board.Dir, "thumb", oldUpload.ThumbnailPath("catalog"))
|
||||
thumbPath, catalogThumbPath = uploads.GetThumbnailFilenames(
|
||||
path.Join(documentRoot, board.Dir, "thumb", oldUpload.Filename))
|
||||
if err = post.UnlinkUploads(false); err != nil {
|
||||
errEv.Err(err).Caller().Send()
|
||||
server.ServeError(writer, "Error unlinking old upload from post: "+err.Error(), wantsJSON, nil)
|
||||
|
@ -186,8 +186,8 @@ func editPost(checkedPosts []int, editBtn string, doEdit string, writer http.Res
|
|||
"filename": upload.OriginalFilename,
|
||||
})
|
||||
filePath = path.Join(documentRoot, board.Dir, "src", upload.Filename)
|
||||
thumbPath = path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("thumb"))
|
||||
catalogThumbPath = path.Join(documentRoot, board.Dir, "thumb", upload.ThumbnailPath("catalog"))
|
||||
thumbPath, catalogThumbPath = uploads.GetThumbnailFilenames(
|
||||
path.Join(documentRoot, board.Dir, "thumb", upload.Filename))
|
||||
os.Remove(filePath)
|
||||
os.Remove(thumbPath)
|
||||
if post.IsTopPost {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gctemplates"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/manage"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
)
|
||||
|
@ -213,12 +214,13 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
|
|||
}
|
||||
|
||||
// move the upload thumbnail
|
||||
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(upload.Filename)
|
||||
if tmpErr = moveFileIfExists(
|
||||
path.Join(documentRoot, srcBoard.Dir, "thumb", upload.ThumbnailPath("upload")),
|
||||
path.Join(documentRoot, destBoard.Dir, "thumb", upload.ThumbnailPath("upload")),
|
||||
path.Join(documentRoot, srcBoard.Dir, "thumb", thumbnail),
|
||||
path.Join(documentRoot, destBoard.Dir, "thumb", thumbnail),
|
||||
); tmpErr != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Str("thumbnail", upload.ThumbnailPath("upload")).
|
||||
Str("thumbnail", thumbnail).
|
||||
Msg("Unable to move thumbnail from source board to destination board")
|
||||
if err == nil {
|
||||
err = tmpErr
|
||||
|
@ -227,11 +229,11 @@ func moveThread(checkedPosts []int, moveBtn string, doMove string, writer http.R
|
|||
if upload.PostID == post.ID {
|
||||
// move the upload catalog thumbnail
|
||||
if tmpErr = moveFileIfExists(
|
||||
path.Join(documentRoot, srcBoard.Dir, "thumb", upload.ThumbnailPath("catalog")),
|
||||
path.Join(documentRoot, destBoard.Dir, "thumb", upload.ThumbnailPath("catalog")),
|
||||
path.Join(documentRoot, srcBoard.Dir, "thumb", catalogThumbnail),
|
||||
path.Join(documentRoot, destBoard.Dir, "thumb", catalogThumbnail),
|
||||
); tmpErr != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Str("catalogThumbnail", upload.ThumbnailPath("catalog")).
|
||||
Str("catalogThumbnail", catalogThumbnail).
|
||||
Msg("Unable to move catalog thumbnail from source board to destination board")
|
||||
}
|
||||
if err == nil {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gctemplates"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
)
|
||||
|
||||
|
@ -370,19 +371,19 @@ func buildBoard(board *gcsql.Board, force bool) error {
|
|||
Str("upload", filePath).Send()
|
||||
return err
|
||||
}
|
||||
filePath = path.Join(boardDir, "thumb", upload.ThumbnailPath("thumbnail"))
|
||||
if err = os.Remove(filePath); err != nil {
|
||||
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
|
||||
path.Join(boardDir, "thumb", upload.Filename))
|
||||
if err = os.Remove(thumbPath); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", postID).
|
||||
Str("upload", filePath).Send()
|
||||
Str("thumbnail", thumbPath).Send()
|
||||
return err
|
||||
}
|
||||
if post.IsTopPost && board.EnableCatalog {
|
||||
filePath = path.Join(boardDir, "thumb", upload.ThumbnailPath("catalog"))
|
||||
if err = os.Remove(filePath); err != nil {
|
||||
if err = os.Remove(catalogThumbPath); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", postID).
|
||||
Str("upload", filePath).Send()
|
||||
Str("catalogThumbPath", catalogThumbPath).Send()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gctemplates"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
)
|
||||
|
||||
|
@ -63,10 +64,11 @@ func getRecentPosts() ([]recentPost, error) {
|
|||
if len(message) > 40 {
|
||||
message = message[:37] + "..."
|
||||
}
|
||||
thumbnail, _ := uploads.GetThumbnailFilenames(filename)
|
||||
post = recentPost{
|
||||
Board: boardDir,
|
||||
URL: config.WebPath(boardDir, "res", topPostID+".html") + "#" + id,
|
||||
ThumbURL: config.WebPath(boardDir, "thumb", gcutil.GetThumbnailPath("post", filename)),
|
||||
ThumbURL: config.WebPath(boardDir, "thumb", thumbnail),
|
||||
Filename: filename,
|
||||
FileDeleted: filename == "deleted",
|
||||
MessageSample: message,
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -103,7 +103,11 @@ func (p Post) ThumbnailPath() string {
|
|||
if p.Filename == "" {
|
||||
return ""
|
||||
}
|
||||
return config.WebPath(p.BoardDir, "thumb", gcutil.GetThumbnailPath("reply", p.Filename))
|
||||
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(p.Filename)
|
||||
if p.IsTopPost {
|
||||
return config.WebPath(p.BoardDir, "thumb", catalogThumbnail)
|
||||
}
|
||||
return config.WebPath(p.BoardDir, "thumb", thumbnail)
|
||||
}
|
||||
|
||||
func (p Post) UploadPath() string {
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/gctemplates"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/manage"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
|
@ -129,6 +130,34 @@ func registerLuaFunctions() {
|
|||
lState.Register("warn_log", createLuaLogFunc("warn"))
|
||||
lState.Register("error_log", createLuaLogFunc("error"))
|
||||
|
||||
lState.Register("register_upload_handler", func(l *lua.LState) int {
|
||||
ext := l.CheckString(1)
|
||||
handler := l.CheckFunction(2)
|
||||
uploads.RegisterUploadHandler(ext, func(upload *gcsql.Upload, post *gcsql.Post, board, filePath, thumbPath, catalogThumbPath string, infoEv, accessEv, errEv *zerolog.Event) error {
|
||||
l.CallByParam(lua.P{
|
||||
Fn: handler,
|
||||
NRet: 1,
|
||||
// Protect: true,
|
||||
}, luar.New(l, upload), luar.New(l, post), lua.LString(board), lua.LString(filePath), lua.LString(thumbPath), lua.LString(catalogThumbPath))
|
||||
|
||||
errRet := l.CheckAny(-1)
|
||||
fmt.Println("Error:", errRet, errRet == nil)
|
||||
return nil
|
||||
})
|
||||
return 0
|
||||
})
|
||||
lState.Register("get_thumbnail_ext", func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
l.Push(luar.New(l, uploads.GetThumbnailExtension(fileExt)))
|
||||
return 1
|
||||
})
|
||||
lState.Register("set_thumbnail_ext", func(l *lua.LState) int {
|
||||
fileExt := l.CheckString(1)
|
||||
thumbExt := l.CheckString(2)
|
||||
uploads.SetThumbnailExtension(fileExt, thumbExt)
|
||||
return 0
|
||||
})
|
||||
|
||||
lState.Register("system_critical_config", func(l *lua.LState) int {
|
||||
l.Push(luar.New(l, config.GetSystemCriticalConfig()))
|
||||
return 1
|
||||
|
|
|
@ -2,8 +2,6 @@ package gcsql
|
|||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -88,8 +86,3 @@ func (p *Post) AttachFile(upload *Upload) error {
|
|||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// ThumbnailPath returns the thumbnail path of the upload, given an thumbnail type ("thumbnail" or "catalog")
|
||||
func (u *Upload) ThumbnailPath(thumbType string) string {
|
||||
return gcutil.GetThumbnailPath(thumbType, u.Filename)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -197,32 +199,19 @@ var funcMap = template.FuncMap{
|
|||
return ban.IP
|
||||
},
|
||||
"getCatalogThumbnail": func(img string) string {
|
||||
return gcutil.GetThumbnailPath("catalog", img)
|
||||
_, catalogThumb := uploads.GetThumbnailFilenames(img)
|
||||
return catalogThumb
|
||||
},
|
||||
"getTopPostID": func(post *gcsql.Post) int {
|
||||
id, _ := post.TopPostID()
|
||||
return id
|
||||
},
|
||||
"getThreadThumbnail": func(img string) string {
|
||||
return gcutil.GetThumbnailPath("thread", img)
|
||||
thumb, _ := uploads.GetThumbnailFilenames(img)
|
||||
return thumb
|
||||
},
|
||||
"getUploadType": func(name string) string {
|
||||
return gcutil.GetThumbnailExt(name)
|
||||
},
|
||||
"imageToThumbnailPath": func(thumbType string, img string) string {
|
||||
filetype := strings.ToLower(img[strings.LastIndex(img, ".")+1:])
|
||||
if filetype == "gif" || filetype == "webm" || filetype == "mp4" {
|
||||
filetype = "jpg"
|
||||
}
|
||||
index := strings.LastIndex(img, ".")
|
||||
if index < 0 || index > len(img) {
|
||||
return ""
|
||||
}
|
||||
thumbSuffix := "t." + filetype
|
||||
if thumbType == "catalog" {
|
||||
thumbSuffix = "c." + filetype
|
||||
}
|
||||
return img[0:index] + thumbSuffix
|
||||
return uploads.GetThumbnailExtension(path.Ext(name))
|
||||
},
|
||||
"numReplies": func(boardid, opID int) int {
|
||||
num, err := gcsql.GetThreadReplyCountFromOP(opID)
|
||||
|
|
|
@ -138,47 +138,6 @@ func GetRealIP(request *http.Request) string {
|
|||
return remoteHost
|
||||
}
|
||||
|
||||
// GetThumbnailExt returns the extension to be used when creating a thumbnail of img. For non-image files,
|
||||
// it returns an empty string, in which case a generic icon will be (eventually) used
|
||||
func GetThumbnailExt(filename string) string {
|
||||
ext := filepath.Ext(strings.ToLower(filename))
|
||||
switch ext {
|
||||
case ".gif":
|
||||
fallthrough
|
||||
case ".mp4":
|
||||
fallthrough
|
||||
case ".png":
|
||||
fallthrough
|
||||
case ".webm":
|
||||
fallthrough
|
||||
case ".webp":
|
||||
return "png"
|
||||
case ".jfif":
|
||||
fallthrough
|
||||
case ".jpg":
|
||||
fallthrough
|
||||
case ".jpeg":
|
||||
return "jpg"
|
||||
default:
|
||||
// invalid file format
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// GetThumbnailPath returns the thumbnail path of the given filename
|
||||
func GetThumbnailPath(thumbType string, img string) string {
|
||||
ext := GetThumbnailExt(img)
|
||||
index := strings.LastIndex(img, ".")
|
||||
if index < 0 || index > len(img) {
|
||||
return ""
|
||||
}
|
||||
thumbSuffix := "t." + ext
|
||||
if thumbType == "catalog" {
|
||||
thumbSuffix = "c." + ext
|
||||
}
|
||||
return img[0:index] + thumbSuffix
|
||||
}
|
||||
|
||||
// HackyStringToInt parses a string to an int, or 0 if error
|
||||
func HackyStringToInt(text string) int {
|
||||
value, _ := strconv.Atoi(text)
|
||||
|
|
|
@ -291,18 +291,18 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
upload, gotErr := uploads.AttachUploadFromRequest(request, writer, post, postBoard)
|
||||
if gotErr {
|
||||
// got an error receiving the upload, stop here (assuming an error page was actually shown)
|
||||
upload, err := uploads.AttachUploadFromRequest(request, writer, post, postBoard)
|
||||
if err != nil {
|
||||
// got an error receiving the upload or the upload was rejected
|
||||
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
||||
return
|
||||
}
|
||||
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
|
||||
var filePath, thumbPath, catalogThumbPath string
|
||||
if upload != nil {
|
||||
filePath = path.Join(documentRoot, postBoard.Dir, "src", upload.Filename)
|
||||
thumbPath = path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("thumb"))
|
||||
catalogThumbPath = path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("catalog"))
|
||||
_, err, recovered = events.TriggerEvent("incoming-upload", upload)
|
||||
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
|
||||
path.Join(documentRoot, postBoard.Dir, "thumb", upload.Filename))
|
||||
if recovered {
|
||||
os.Remove(filePath)
|
||||
os.Remove(thumbPath)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
)
|
||||
|
||||
func tempCleaner() {
|
||||
|
@ -41,19 +42,19 @@ func tempCleaner() {
|
|||
Str("filePath", fileSrc).Send()
|
||||
}
|
||||
|
||||
thumbSrc := upload.ThumbnailPath("thread")
|
||||
if err = os.Remove(thumbSrc); err != nil {
|
||||
thumbnail, catalogThumbnail := uploads.GetThumbnailFilenames(
|
||||
path.Join(systemCritical.DocumentRoot, board.Dir, "thumb", upload.Filename))
|
||||
if err = os.Remove(thumbnail); err != nil {
|
||||
gcutil.LogError(err).
|
||||
Str("subject", "tempUpload").
|
||||
Str("filePath", thumbSrc).Send()
|
||||
Str("filePath", thumbnail).Send()
|
||||
}
|
||||
|
||||
if post.IsTopPost {
|
||||
catalogSrc := upload.ThumbnailPath("catalog")
|
||||
if err = os.Remove(catalogSrc); err != nil {
|
||||
if err = os.Remove(catalogThumbnail); err != nil {
|
||||
gcutil.LogError(err).
|
||||
Str("subject", "tempUpload").
|
||||
Str("filePath", catalogSrc).Send()
|
||||
Str("filePath", catalogThumbnail).Send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/events"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/server"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
|
@ -49,7 +47,7 @@ func init() {
|
|||
// AttachUploadFromRequest reads an incoming HTTP request and processes any incoming files.
|
||||
// It returns the upload (if there was one) and whether or not any errors were served (meaning
|
||||
// that it should stop processing the post
|
||||
func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter, post *gcsql.Post, postBoard *gcsql.Board) (*gcsql.Upload, bool) {
|
||||
func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter, post *gcsql.Post, postBoard *gcsql.Board) (*gcsql.Upload, error) {
|
||||
errEv := gcutil.LogError(nil).
|
||||
Str("IP", post.IP)
|
||||
infoEv := gcutil.LogInfo().
|
||||
|
@ -58,16 +56,14 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
|
|||
infoEv.Discard()
|
||||
errEv.Discard()
|
||||
}()
|
||||
wantsJSON := serverutil.IsRequestingJSON(request)
|
||||
file, handler, err := request.FormFile("imagefile")
|
||||
if errors.Is(err, http.ErrMissingFile) {
|
||||
// no file was submitted with the form
|
||||
return nil, false
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().Send()
|
||||
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
||||
return nil, true
|
||||
return nil, err
|
||||
}
|
||||
upload := &gcsql.Upload{
|
||||
OriginalFilename: html.EscapeString(handler.Filename),
|
||||
|
@ -78,47 +74,37 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
|
|||
boardConfig := config.GetBoardConfig(postBoard.Dir)
|
||||
if !boardConfig.AcceptedExtension(upload.OriginalFilename) {
|
||||
errEv.Caller().Msg("Upload filetype not supported")
|
||||
server.ServeError(writer, "Upload filetype not supported", wantsJSON, map[string]interface{}{
|
||||
"filename": upload.OriginalFilename,
|
||||
})
|
||||
return nil, true
|
||||
return nil, ErrUnsupportedFileExt
|
||||
}
|
||||
|
||||
if IsFilenameBanned(upload, post, postBoard, writer, request) {
|
||||
if err = CheckFilenameBan(upload, post, postBoard, writer, request); err != nil {
|
||||
// If checkFilenameBan returns true, an error occured or the file was
|
||||
// rejected for having a banned filename, and the incident was logged either way
|
||||
return nil, true
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().Send()
|
||||
server.ServeError(writer, "Error while trying to read file: "+err.Error(), wantsJSON, map[string]interface{}{
|
||||
"filename": upload.OriginalFilename,
|
||||
})
|
||||
return nil, true
|
||||
return nil, errors.New("Error while trying to read file: " + err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Calculate image checksum
|
||||
upload.Checksum = fmt.Sprintf("%x", md5.Sum(data)) // skipcq: GSC-G401
|
||||
if IsChecksumBanned(upload, post, postBoard, writer, request) {
|
||||
// If checkChecksumBan returns true, an error occured or the file was
|
||||
if err = CheckFileChecksumBan(upload, post, postBoard, writer, request); err != nil {
|
||||
// If CheckFileChecksumBan returns a non-nil error, an error occured or the file was
|
||||
// rejected for having a banned checksum, and the incident was logged either way
|
||||
return nil, true
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ext := strings.ToLower(filepath.Ext(upload.OriginalFilename))
|
||||
upload.Filename = getNewFilename() + ext
|
||||
errorMap := map[string]any{
|
||||
"filename": upload.Filename,
|
||||
"originalFilename": upload.OriginalFilename,
|
||||
}
|
||||
|
||||
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
|
||||
filePath := path.Join(documentRoot, postBoard.Dir, "src", upload.Filename)
|
||||
thumbPath := path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("thumb"))
|
||||
catalogThumbPath := path.Join(documentRoot, postBoard.Dir, "thumb", upload.ThumbnailPath("catalog"))
|
||||
thumbPath, catalogThumbPath := GetThumbnailFilenames(
|
||||
path.Join(documentRoot, postBoard.Dir, "thumb", upload.Filename))
|
||||
|
||||
errEv.
|
||||
Str("originalFilename", upload.OriginalFilename).
|
||||
|
@ -129,28 +115,17 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
|
|||
|
||||
if err = os.WriteFile(filePath, data, config.GC_FILE_MODE); err != nil {
|
||||
errEv.Err(err).Caller().Send()
|
||||
server.ServeError(writer, fmt.Sprintf("Couldn't write file %q", upload.OriginalFilename), wantsJSON, errorMap)
|
||||
return nil, true
|
||||
}
|
||||
|
||||
gcutil.LogStr("stripImageMetadata", boardConfig.StripImageMetadata, errEv, infoEv)
|
||||
if err = stripImageMetadata(filePath, boardConfig); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Unable to strip metadata")
|
||||
server.ServeError(writer, "Unable to strip metadata from image", wantsJSON, errorMap)
|
||||
return nil, true
|
||||
return nil, fmt.Errorf("couldn't write file %q", upload.OriginalFilename)
|
||||
}
|
||||
|
||||
// event triggered after the file is successfully written but be
|
||||
_, err, recovered := events.TriggerEvent("upload-saved", filePath)
|
||||
if recovered {
|
||||
writer.WriteHeader(http.StatusInternalServerError)
|
||||
server.ServeError(writer, "Unable to save upload (recovered from a panic in event handler)", wantsJSON,
|
||||
map[string]interface{}{"event": "upload-saved"})
|
||||
return nil, true
|
||||
return nil, errors.New("unable to save upload (recovered from a panic in event handler)")
|
||||
}
|
||||
if err != nil {
|
||||
server.ServeError(writer, err.Error(), wantsJSON, errorMap)
|
||||
return nil, true
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infoEv.Str("referer", request.Referer()).Str("filename", handler.Filename).Send()
|
||||
|
@ -168,13 +143,10 @@ func AttachUploadFromRequest(request *http.Request, writer http.ResponseWriter,
|
|||
}
|
||||
|
||||
if err = uploadHandler(upload, post, postBoard.Dir, filePath, thumbPath, catalogThumbPath, infoEv, accessEv, errEv); err != nil {
|
||||
server.ServeError(writer, "Error processing upload: "+err.Error(), wantsJSON, map[string]interface{}{
|
||||
"filename": upload.OriginalFilename,
|
||||
})
|
||||
return nil, true
|
||||
return nil, errors.New("error processing upload:" + err.Error())
|
||||
}
|
||||
accessEv.Send()
|
||||
return upload, false
|
||||
return upload, nil
|
||||
}
|
||||
|
||||
func getNewFilename() string {
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
package uploads
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/server"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
)
|
||||
|
||||
func IsFilenameBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) bool {
|
||||
var (
|
||||
ErrFilenameNotAllowed = errors.New("filename not allowed")
|
||||
ErrCheckingFileBan = errors.New("unable to check file ban info")
|
||||
ErrFileNotAllowed = errors.New("uploaded file not allowed")
|
||||
)
|
||||
|
||||
func CheckFilenameBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) error {
|
||||
filenameBan, err := gcsql.CheckFilenameBan(upload.OriginalFilename, postBoard.ID)
|
||||
if err != nil {
|
||||
gcutil.LogError(err).
|
||||
|
@ -17,20 +22,18 @@ func IsFilenameBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
|
|||
Str("filename", upload.OriginalFilename).
|
||||
Str("boardDir", postBoard.Dir).
|
||||
Msg("Error getting name banned status")
|
||||
server.ServeErrorPage(writer, "Error getting filename ban info")
|
||||
return true
|
||||
return ErrCheckingFileBan
|
||||
}
|
||||
if filenameBan == nil {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
server.ServeError(writer, "Filename not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
|
||||
gcutil.LogWarning().
|
||||
Str("originalFilename", upload.OriginalFilename).
|
||||
Msg("File rejected for having a banned filename")
|
||||
return true
|
||||
return ErrFilenameNotAllowed
|
||||
}
|
||||
|
||||
func IsChecksumBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) bool {
|
||||
func CheckFileChecksumBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) error {
|
||||
fileBan, err := gcsql.CheckFileChecksumBan(upload.Checksum, postBoard.ID)
|
||||
if err != nil {
|
||||
gcutil.LogError(err).
|
||||
|
@ -38,16 +41,14 @@ func IsChecksumBanned(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
|
|||
Str("boardDir", postBoard.Dir).
|
||||
Str("checksum", upload.Checksum).
|
||||
Msg("Error getting file checksum ban status")
|
||||
server.ServeErrorPage(writer, "Error processing file: "+err.Error())
|
||||
return true
|
||||
return ErrCheckingFileBan
|
||||
}
|
||||
if fileBan == nil {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
server.ServeError(writer, "File not allowed", serverutil.IsRequestingJSON(request), map[string]interface{}{})
|
||||
gcutil.LogWarning().
|
||||
Str("originalFilename", upload.OriginalFilename).
|
||||
Str("checksum", upload.Checksum).
|
||||
Msg("File rejected for having a banned checksum")
|
||||
return true
|
||||
return ErrFileNotAllowed
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package uploads
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/gif"
|
||||
"os"
|
||||
|
@ -11,9 +12,14 @@ import (
|
|||
"github.com/disintegration/imaging"
|
||||
"github.com/gochan-org/gochan/pkg/config"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrStripMetadata = errors.New("unable to strip image metadata")
|
||||
)
|
||||
|
||||
func stripImageMetadata(filePath string, boardConfig *config.BoardConfig) (err error) {
|
||||
var stripFlag string
|
||||
switch boardConfig.StripImageMetadata {
|
||||
|
@ -47,6 +53,14 @@ func numImageFrames(imgPath string) (int, error) {
|
|||
}
|
||||
|
||||
func processImage(upload *gcsql.Upload, post *gcsql.Post, board string, filePath string, thumbPath string, catalogThumbPath string, infoEv *zerolog.Event, accessEv *zerolog.Event, errEv *zerolog.Event) error {
|
||||
boardConfig := config.GetBoardConfig(board)
|
||||
gcutil.LogStr("stripImageMetadata", boardConfig.StripImageMetadata, errEv, infoEv)
|
||||
|
||||
err := stripImageMetadata(filePath, boardConfig)
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().Msg("Unable to strip metadata")
|
||||
return ErrStripMetadata
|
||||
}
|
||||
img, err := imaging.Open(filePath)
|
||||
if err != nil {
|
||||
os.Remove(filePath)
|
||||
|
|
|
@ -23,6 +23,40 @@ const (
|
|||
ThumbnailCatalog
|
||||
)
|
||||
|
||||
var (
|
||||
thumbnailExtensions = map[string]string{
|
||||
".gif": ".png",
|
||||
".mp4": ".png",
|
||||
".webm": ".png",
|
||||
".webp": ".png",
|
||||
".jfif": ".jpg",
|
||||
".jpeg": ".jpg",
|
||||
}
|
||||
)
|
||||
|
||||
func GetThumbnailExtension(fileExt string) string {
|
||||
thumbExt, ok := thumbnailExtensions[fileExt]
|
||||
if !ok {
|
||||
return fileExt
|
||||
}
|
||||
return thumbExt
|
||||
}
|
||||
|
||||
func SetThumbnailExtension(fileExt, thumbExt string) {
|
||||
thumbnailExtensions[fileExt] = thumbExt
|
||||
}
|
||||
|
||||
// GetThumbnailFilenames returns the regular thumbnail and the catalog thumbnail filenames of the given upload
|
||||
// filename. It does not check if the catalog actually exists (for example, if it's a reply)
|
||||
func GetThumbnailFilenames(img string) (string, string) {
|
||||
ext := GetThumbnailExtension(path.Ext(img))
|
||||
index := strings.LastIndex(img, ".")
|
||||
if index < 0 || index > len(img) {
|
||||
return "", ""
|
||||
}
|
||||
return img[:index] + "t" + ext, img[:index] + "c" + ext
|
||||
}
|
||||
|
||||
func createImageThumbnail(imageObj image.Image, boardDir string, thumbType ThumbnailCategory) image.Image {
|
||||
thumbWidth, thumbHeight := getBoardThumbnailSize(boardDir, thumbType)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue