2020-04-29 17:44:29 -07:00
|
|
|
package posting
|
|
|
|
|
|
|
|
import (
|
2023-06-16 12:06:26 -07:00
|
|
|
"encoding/json"
|
2022-11-07 12:56:51 -08:00
|
|
|
"errors"
|
2023-06-15 11:41:19 -07:00
|
|
|
"fmt"
|
2020-04-29 17:44:29 -07:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path"
|
2023-05-02 14:39:31 -07:00
|
|
|
"runtime/debug"
|
2020-04-29 17:44:29 -07:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gochan-org/gochan/pkg/building"
|
|
|
|
"github.com/gochan-org/gochan/pkg/config"
|
2023-06-09 15:16:34 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/events"
|
2020-04-29 17:44:29 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/gcsql"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
2024-01-20 22:41:40 -08:00
|
|
|
"github.com/gochan-org/gochan/pkg/posting/geoip"
|
2023-07-12 14:20:41 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
2023-01-06 14:38:35 -08:00
|
|
|
"github.com/gochan-org/gochan/pkg/server"
|
|
|
|
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
2024-03-13 13:58:36 -07:00
|
|
|
"github.com/rs/zerolog"
|
2020-04-29 17:44:29 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
yearInSeconds = 31536000
|
2022-11-23 10:12:28 -08:00
|
|
|
maxFormBytes = 50000000
|
2020-04-29 17:44:29 -07:00
|
|
|
)
|
|
|
|
|
2022-11-07 12:56:51 -08:00
|
|
|
var (
|
|
|
|
ErrorPostTooLong = errors.New("post is too long")
|
2024-01-21 17:16:27 -08:00
|
|
|
ErrInvalidFlag = errors.New("invalid selected flag")
|
2022-11-07 12:56:51 -08:00
|
|
|
)
|
|
|
|
|
2024-03-13 13:58:36 -07:00
|
|
|
func attachFlag(request *http.Request, post *gcsql.Post, board string, errEv *zerolog.Event) error {
|
|
|
|
boardConfig := config.GetBoardConfig(board)
|
|
|
|
flag := request.PostFormValue("post-flag")
|
|
|
|
if flag != "" {
|
|
|
|
errEv.Str("flag", flag)
|
|
|
|
}
|
|
|
|
var err error
|
|
|
|
switch flag {
|
|
|
|
case "geoip":
|
|
|
|
if boardConfig.EnableGeoIP {
|
|
|
|
geoipInfo, err := geoip.GetCountry(request, board, errEv)
|
|
|
|
if err != nil {
|
|
|
|
// GetCountry logs the error
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
post.Country = geoipInfo.Name
|
|
|
|
post.Flag = strings.ToLower(geoipInfo.Flag)
|
|
|
|
} else {
|
|
|
|
err = ErrInvalidFlag
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Msg("User selected 'geoip' on a non-geoip board")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "":
|
|
|
|
// "No flag"
|
|
|
|
if !boardConfig.EnableNoFlag {
|
|
|
|
err = ErrInvalidFlag
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Msg("User submitted 'No flag' on a board without it enabled")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// custom flag
|
|
|
|
var validFlag bool
|
|
|
|
post.Country, validFlag = boardConfig.CheckCustomFlag(flag)
|
|
|
|
if !validFlag {
|
|
|
|
err = ErrInvalidFlag
|
|
|
|
errEv.Caller().Msg("User submitted invalid custom flag")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
post.Flag = flag
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-03-18 12:41:03 -07:00
|
|
|
func handleRecover(writer http.ResponseWriter, wantsJSON bool, infoEv *zerolog.Event, errEv *zerolog.Event) {
|
|
|
|
if a := recover(); a != nil {
|
|
|
|
if writer != nil {
|
|
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
|
|
|
server.ServeError(writer, "Internal server error", wantsJSON, nil)
|
|
|
|
}
|
|
|
|
errEv.Caller().
|
|
|
|
Str("recover", fmt.Sprintf("%v", a)).
|
|
|
|
Bytes("stack", debug.Stack()).
|
|
|
|
Msg("Recovered from panic")
|
|
|
|
debug.PrintStack()
|
|
|
|
}
|
|
|
|
errEv.Discard()
|
|
|
|
infoEv.Discard()
|
|
|
|
}
|
|
|
|
|
2020-04-29 17:44:29 -07:00
|
|
|
// MakePost is called when a user accesses /post. Parse form data, then insert and build
|
|
|
|
func MakePost(writer http.ResponseWriter, request *http.Request) {
|
2022-11-23 10:12:28 -08:00
|
|
|
request.ParseMultipartForm(maxFormBytes)
|
2023-05-02 14:39:31 -07:00
|
|
|
wantsJSON := serverutil.IsRequestingJSON(request)
|
|
|
|
|
2024-04-19 13:45:57 -07:00
|
|
|
infoEv, errEv := gcutil.LogRequest(request)
|
2024-03-18 12:41:03 -07:00
|
|
|
defer handleRecover(writer, wantsJSON, infoEv, errEv)
|
2023-06-14 13:31:29 -07:00
|
|
|
|
2020-04-29 17:44:29 -07:00
|
|
|
var formName string
|
|
|
|
var formEmail string
|
|
|
|
|
2021-07-11 11:51:29 -07:00
|
|
|
systemCritical := config.GetSystemCriticalConfig()
|
|
|
|
|
2020-04-29 17:44:29 -07:00
|
|
|
if request.Method == "GET" {
|
2022-11-23 10:12:28 -08:00
|
|
|
infoEv.Msg("Invalid request (expected POST, not GET)")
|
2021-07-11 11:51:29 -07:00
|
|
|
http.Redirect(writer, request, systemCritical.WebRoot, http.StatusFound)
|
2020-04-29 17:44:29 -07:00
|
|
|
return
|
|
|
|
}
|
2022-11-29 13:10:40 -08:00
|
|
|
|
|
|
|
if request.FormValue("doappeal") != "" {
|
2023-12-28 23:06:44 -08:00
|
|
|
handleAppeal(writer, request, infoEv, errEv)
|
2022-11-29 13:10:40 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-19 13:45:57 -07:00
|
|
|
post := &gcsql.Post{IP: gcutil.GetRealIP(request)}
|
2022-11-07 12:56:51 -08:00
|
|
|
var err error
|
|
|
|
threadidStr := request.FormValue("threadid")
|
2022-11-28 17:04:41 -08:00
|
|
|
// to avoid potential hiccups, we'll just treat the "threadid" form field as the OP ID and convert it internally
|
|
|
|
// to the real thread ID
|
|
|
|
var opID int
|
2022-11-07 12:56:51 -08:00
|
|
|
if threadidStr != "" {
|
|
|
|
// post is a reply
|
2022-11-28 17:04:41 -08:00
|
|
|
if opID, err = strconv.Atoi(threadidStr); err != nil {
|
2024-03-18 12:41:03 -07:00
|
|
|
errEv.Err(err).Caller().
|
2022-11-28 17:04:41 -08:00
|
|
|
Str("opIDstr", threadidStr).
|
2024-03-18 12:41:03 -07:00
|
|
|
Msg("Invalid threadid value")
|
|
|
|
server.ServeError(writer, "Invalid form data (invalid threadid)", wantsJSON, map[string]any{
|
2022-11-23 10:12:28 -08:00
|
|
|
"threadid": threadidStr,
|
|
|
|
})
|
2022-11-07 12:56:51 -08:00
|
|
|
return
|
|
|
|
}
|
2022-11-28 17:04:41 -08:00
|
|
|
if opID > 0 {
|
|
|
|
if post.ThreadID, err = gcsql.GetTopPostThreadID(opID); err != nil {
|
2024-03-18 12:41:03 -07:00
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Int("opID", opID).Send()
|
|
|
|
server.ServeError(writer, err.Error(), wantsJSON, map[string]any{
|
2022-11-28 17:04:41 -08:00
|
|
|
"opID": opID,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-11-07 12:56:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
boardidStr := request.FormValue("boardid")
|
|
|
|
boardID, err := strconv.Atoi(boardidStr)
|
2022-07-25 09:29:00 -07:00
|
|
|
if err != nil {
|
2022-11-23 10:12:28 -08:00
|
|
|
errEv.Str("boardid", boardidStr).Caller().Msg("Invalid boardid value")
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Invalid form data (invalid boardid)", wantsJSON, map[string]any{
|
2022-11-23 10:12:28 -08:00
|
|
|
"boardid": boardidStr,
|
|
|
|
})
|
2022-11-07 12:56:51 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
postBoard, err := gcsql.GetBoardFromID(boardID)
|
|
|
|
if err != nil {
|
2022-11-23 10:12:28 -08:00
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Int("boardid", boardID).
|
|
|
|
Msg("Unable to get board info")
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Unable to get board info", wantsJSON, map[string]any{
|
2022-11-07 12:56:51 -08:00
|
|
|
"boardid": boardID,
|
2022-11-23 10:12:28 -08:00
|
|
|
})
|
2022-07-25 09:29:00 -07:00
|
|
|
return
|
|
|
|
}
|
2022-11-28 12:29:15 -08:00
|
|
|
boardConfig := config.GetBoardConfig(postBoard.Dir)
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
var emailCommand string
|
|
|
|
formName = request.FormValue("postname")
|
2023-04-26 13:10:38 -07:00
|
|
|
post.Name, post.Tripcode = gcutil.ParseName(formName)
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
formEmail = request.FormValue("postemail")
|
|
|
|
|
2021-03-26 11:10:05 -07:00
|
|
|
http.SetCookie(writer, &http.Cookie{
|
|
|
|
Name: "email",
|
2022-12-20 10:30:20 -08:00
|
|
|
Value: url.QueryEscape(formEmail),
|
2021-03-26 11:10:05 -07:00
|
|
|
MaxAge: yearInSeconds,
|
|
|
|
})
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
if !strings.Contains(formEmail, "noko") && !strings.Contains(formEmail, "sage") {
|
|
|
|
post.Email = formEmail
|
|
|
|
} else if strings.Index(formEmail, "#") > 1 {
|
|
|
|
formEmailArr := strings.SplitN(formEmail, "#", 2)
|
|
|
|
post.Email = formEmailArr[0]
|
|
|
|
emailCommand = formEmailArr[1]
|
|
|
|
} else if formEmail == "noko" || formEmail == "sage" {
|
|
|
|
emailCommand = formEmail
|
|
|
|
post.Email = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
post.Subject = request.FormValue("postsubject")
|
2022-11-07 12:56:51 -08:00
|
|
|
post.MessageRaw = strings.TrimSpace(request.FormValue("postmsg"))
|
|
|
|
if len(post.MessageRaw) > postBoard.MaxMessageLength {
|
2022-11-23 10:12:28 -08:00
|
|
|
errEv.
|
|
|
|
Int("messageLength", len(post.MessageRaw)).
|
|
|
|
Int("maxMessageLength", postBoard.MaxMessageLength).Send()
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Message is too long", wantsJSON, map[string]any{
|
2022-11-07 12:56:51 -08:00
|
|
|
"messageLength": len(post.MessageRaw),
|
|
|
|
"boardid": boardID,
|
2022-11-23 10:12:28 -08:00
|
|
|
})
|
2022-07-25 10:12:01 -07:00
|
|
|
return
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2022-11-07 12:56:51 -08:00
|
|
|
if post.MessageRaw, err = ApplyWordFilters(post.MessageRaw, postBoard.Dir); err != nil {
|
2022-11-23 10:12:28 -08:00
|
|
|
errEv.Err(err).Caller().Msg("Error formatting post")
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Error formatting post: "+err.Error(), wantsJSON, map[string]any{
|
2022-11-07 12:56:51 -08:00
|
|
|
"boardDir": postBoard.Dir,
|
2022-11-23 10:12:28 -08:00
|
|
|
})
|
2020-04-29 17:44:29 -07:00
|
|
|
return
|
|
|
|
}
|
2022-07-25 09:29:00 -07:00
|
|
|
|
2023-10-20 16:49:46 -07:00
|
|
|
_, err, recovered := events.TriggerEvent("message-pre-format", post, request)
|
2023-06-09 15:16:34 -07:00
|
|
|
if recovered {
|
2023-06-12 08:50:45 -07:00
|
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
2023-06-09 15:16:34 -07:00
|
|
|
server.ServeError(writer, "Recovered from a panic in an event handler (message-pre-format)", wantsJSON, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
errEv.Err(err).Caller().
|
2023-06-12 08:50:45 -07:00
|
|
|
Str("event", "message-pre-format").
|
2023-06-09 15:16:34 -07:00
|
|
|
Send()
|
|
|
|
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:56:51 -08:00
|
|
|
post.Message = FormatMessage(post.MessageRaw, postBoard.Dir)
|
2022-12-24 16:15:09 -08:00
|
|
|
password := request.FormValue("postpassword")
|
2020-04-29 17:44:29 -07:00
|
|
|
if password == "" {
|
|
|
|
password = gcutil.RandomString(8)
|
|
|
|
}
|
|
|
|
post.Password = gcutil.Md5Sum(password)
|
|
|
|
|
|
|
|
// add name and email cookies that will expire in a year (31536000 seconds)
|
2021-03-26 11:10:05 -07:00
|
|
|
http.SetCookie(writer, &http.Cookie{
|
|
|
|
Name: "name",
|
2022-12-20 10:30:20 -08:00
|
|
|
Value: url.QueryEscape(formName),
|
2021-03-26 11:10:05 -07:00
|
|
|
MaxAge: yearInSeconds,
|
|
|
|
})
|
|
|
|
http.SetCookie(writer, &http.Cookie{
|
|
|
|
Name: "password",
|
2022-12-20 10:30:20 -08:00
|
|
|
Value: url.QueryEscape(password),
|
2021-03-26 11:10:05 -07:00
|
|
|
MaxAge: yearInSeconds,
|
|
|
|
})
|
2020-04-29 17:44:29 -07:00
|
|
|
|
2022-11-07 12:56:51 -08:00
|
|
|
post.CreatedOn = time.Now()
|
|
|
|
// isSticky := request.FormValue("modstickied") == "on"
|
|
|
|
// isLocked := request.FormValue("modlocked") == "on"
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
//post has no referrer, or has a referrer from a different domain, probably a spambot
|
|
|
|
if !serverutil.ValidReferer(request) {
|
2022-09-04 14:27:14 -07:00
|
|
|
gcutil.LogWarning().
|
|
|
|
Str("spam", "badReferer").
|
|
|
|
Str("IP", post.IP).
|
2022-12-24 12:25:23 -08:00
|
|
|
Int("threadID", post.ThreadID).
|
2022-09-04 14:27:14 -07:00
|
|
|
Msg("Rejected post from possible spambot")
|
2023-01-06 14:38:35 -08:00
|
|
|
server.ServeError(writer, "Your post looks like spam", wantsJSON, nil)
|
2020-04-29 17:44:29 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-07 12:56:51 -08:00
|
|
|
var delay int
|
|
|
|
var tooSoon bool
|
2022-12-20 15:08:08 -08:00
|
|
|
if threadidStr == "" || threadidStr == "0" || threadidStr == "-1" {
|
2022-11-07 12:56:51 -08:00
|
|
|
// creating a new thread
|
|
|
|
delay, err = gcsql.SinceLastThread(post.IP)
|
2022-12-14 12:41:25 -08:00
|
|
|
tooSoon = delay < boardConfig.Cooldowns.NewThread
|
2022-11-07 12:56:51 -08:00
|
|
|
} else {
|
2022-12-20 13:13:08 -08:00
|
|
|
// replying to a thread
|
2022-11-07 12:56:51 -08:00
|
|
|
delay, err = gcsql.SinceLastPost(post.IP)
|
2022-12-14 12:41:25 -08:00
|
|
|
tooSoon = delay < boardConfig.Cooldowns.Reply
|
2020-07-09 13:08:24 -07:00
|
|
|
}
|
2022-11-07 12:56:51 -08:00
|
|
|
if err != nil {
|
2022-12-14 12:41:25 -08:00
|
|
|
errEv.Err(err).Caller().Str("boardDir", postBoard.Dir).Msg("Unable to check post cooldown")
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Error checking post cooldown: "+err.Error(), wantsJSON, map[string]any{
|
2022-11-07 12:56:51 -08:00
|
|
|
"boardDir": postBoard.Dir,
|
2022-11-23 10:12:28 -08:00
|
|
|
})
|
2022-11-07 12:56:51 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if tooSoon {
|
2022-11-23 10:12:28 -08:00
|
|
|
errEv.Int("delay", delay).Msg("Rejecting post (user must wait before making another post)")
|
2023-01-06 14:38:35 -08:00
|
|
|
server.ServeError(writer, "Please wait before making a new post", wantsJSON, nil)
|
2020-07-09 13:08:24 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-06-14 13:31:29 -07:00
|
|
|
if checkIpBan(post, postBoard, writer, request) {
|
2022-11-07 12:56:51 -08:00
|
|
|
return
|
|
|
|
}
|
2023-06-14 13:31:29 -07:00
|
|
|
if checkUsernameBan(post, postBoard, writer, request) {
|
2020-07-09 13:08:24 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-06-15 13:28:05 -07:00
|
|
|
captchaSuccess, err := submitCaptchaResponse(request)
|
2022-12-20 13:13:08 -08:00
|
|
|
if err != nil {
|
2024-03-18 12:41:03 -07:00
|
|
|
errEv.Err(err).Caller().Send()
|
2024-01-21 17:16:27 -08:00
|
|
|
server.ServeError(writer, "Error submitting captcha response:"+err.Error(), wantsJSON, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-03-13 13:58:36 -07:00
|
|
|
if boardConfig.EnableGeoIP || len(boardConfig.CustomFlags) > 0 {
|
|
|
|
if err = attachFlag(request, post, postBoard.Dir, errEv); err != nil {
|
|
|
|
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
|
|
|
return
|
2024-01-21 17:16:27 -08:00
|
|
|
}
|
2020-07-09 13:08:24 -07:00
|
|
|
}
|
2024-01-21 17:16:27 -08:00
|
|
|
|
2022-12-20 13:13:08 -08:00
|
|
|
if !captchaSuccess {
|
2023-06-15 12:15:12 -07:00
|
|
|
server.ServeError(writer, "Missing or invalid captcha response", wantsJSON, nil)
|
2022-12-20 13:13:08 -08:00
|
|
|
errEv.Msg("Missing or invalid captcha response")
|
2022-12-17 16:30:52 -08:00
|
|
|
return
|
|
|
|
}
|
2022-12-20 13:33:33 -08:00
|
|
|
_, _, err = request.FormFile("imagefile")
|
|
|
|
noFile := err == http.ErrMissingFile
|
|
|
|
if noFile && post.ThreadID == 0 && boardConfig.NewThreadsRequireUpload {
|
|
|
|
errEv.Caller().Msg("New thread rejected (NewThreadsRequireUpload set in config)")
|
2023-01-06 14:38:35 -08:00
|
|
|
server.ServeError(writer, "Upload required for new threads", wantsJSON, nil)
|
2022-12-20 13:33:33 -08:00
|
|
|
return
|
|
|
|
}
|
2022-12-20 13:37:54 -08:00
|
|
|
if post.MessageRaw == "" && noFile {
|
|
|
|
errEv.Caller().Msg("New post rejected (no file and message is blank)")
|
2023-01-06 14:38:35 -08:00
|
|
|
server.ServeError(writer, "Your post must have an upload or a comment", wantsJSON, nil)
|
2022-12-20 13:37:54 -08:00
|
|
|
return
|
|
|
|
}
|
2022-06-25 18:20:25 -07:00
|
|
|
|
2023-07-14 11:04:46 -07:00
|
|
|
upload, err := uploads.AttachUploadFromRequest(request, writer, post, postBoard)
|
2022-12-17 16:30:52 -08:00
|
|
|
documentRoot := config.GetSystemCriticalConfig().DocumentRoot
|
2022-12-31 01:51:14 -08:00
|
|
|
var filePath, thumbPath, catalogThumbPath string
|
|
|
|
if upload != nil {
|
|
|
|
filePath = path.Join(documentRoot, postBoard.Dir, "src", upload.Filename)
|
2023-07-14 11:04:46 -07:00
|
|
|
thumbPath, catalogThumbPath := uploads.GetThumbnailFilenames(
|
|
|
|
path.Join(documentRoot, postBoard.Dir, "thumb", upload.Filename))
|
2023-06-15 13:45:32 -07:00
|
|
|
if recovered {
|
|
|
|
os.Remove(filePath)
|
|
|
|
os.Remove(thumbPath)
|
|
|
|
os.Remove(catalogThumbPath)
|
|
|
|
writer.WriteHeader(http.StatusInternalServerError)
|
|
|
|
server.ServeError(writer, "Recovered from a panic in an event handler (incoming-upload)", wantsJSON, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Str("event", "incoming-upload").
|
|
|
|
Send()
|
|
|
|
server.ServeError(writer, "Unable to attach upload to post: "+err.Error(), wantsJSON, nil)
|
|
|
|
return
|
|
|
|
}
|
2024-03-04 13:55:03 -08:00
|
|
|
} else if err != nil {
|
|
|
|
errEv.Err(err).Caller().Send()
|
|
|
|
// got an error receiving the upload or the upload was rejected
|
|
|
|
server.ServeError(writer, err.Error(), wantsJSON, nil)
|
|
|
|
return
|
2022-12-31 01:51:14 -08:00
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
|
2022-11-07 16:56:50 -08:00
|
|
|
if err = post.Insert(emailCommand != "sage", postBoard.ID, false, false, false, false); err != nil {
|
2022-12-13 16:23:16 -08:00
|
|
|
errEv.Err(err).Caller().
|
2022-11-07 16:56:50 -08:00
|
|
|
Str("sql", "postInsertion").
|
|
|
|
Msg("Unable to insert post")
|
|
|
|
if upload != nil {
|
2020-07-09 13:08:24 -07:00
|
|
|
os.Remove(filePath)
|
|
|
|
os.Remove(thumbPath)
|
|
|
|
os.Remove(catalogThumbPath)
|
|
|
|
}
|
2023-06-15 12:15:12 -07:00
|
|
|
server.ServeError(writer, "Unable to insert post", wantsJSON, nil)
|
2022-11-07 16:56:50 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = post.AttachFile(upload); err != nil {
|
2022-12-13 16:23:16 -08:00
|
|
|
errEv.Err(err).Caller().
|
2022-11-07 16:56:50 -08:00
|
|
|
Str("sql", "postInsertion").
|
|
|
|
Msg("Unable to attach upload to post")
|
|
|
|
os.Remove(filePath)
|
|
|
|
os.Remove(thumbPath)
|
|
|
|
os.Remove(catalogThumbPath)
|
2023-06-05 12:35:11 -07:00
|
|
|
post.Delete()
|
2024-03-18 12:41:03 -07:00
|
|
|
server.ServeError(writer, "Unable to attach upload", wantsJSON, map[string]any{
|
2023-06-15 12:15:12 -07:00
|
|
|
"filename": upload.OriginalFilename,
|
|
|
|
})
|
2020-04-29 17:44:29 -07:00
|
|
|
return
|
|
|
|
}
|
2022-12-31 01:51:14 -08:00
|
|
|
if upload != nil {
|
|
|
|
if err = config.TakeOwnership(filePath); err != nil {
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Str("file", filePath).Send()
|
|
|
|
}
|
|
|
|
if err = config.TakeOwnership(thumbPath); err != nil {
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Str("thumbnail", thumbPath).Send()
|
|
|
|
}
|
|
|
|
if err = config.TakeOwnership(catalogThumbPath); err != nil && !os.IsNotExist(err) {
|
|
|
|
errEv.Err(err).Caller().
|
|
|
|
Str("catalogThumbnail", catalogThumbPath).Send()
|
|
|
|
}
|
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
// rebuild the board page
|
2022-12-13 16:23:16 -08:00
|
|
|
if err = building.BuildBoards(false, postBoard.ID); err != nil {
|
2023-06-15 12:15:12 -07:00
|
|
|
server.ServeError(writer, "Unable to build boards", wantsJSON, nil)
|
2022-12-13 16:23:16 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = building.BuildFrontPage(); err != nil {
|
2023-06-15 12:15:12 -07:00
|
|
|
server.ServeError(writer, "Unable to build front page", wantsJSON, nil)
|
2022-12-13 16:23:16 -08:00
|
|
|
return
|
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
|
2023-06-16 12:06:26 -07:00
|
|
|
if wantsJSON {
|
|
|
|
topPost := post.ID
|
|
|
|
if !post.IsTopPost {
|
|
|
|
topPost, _ = post.TopPostID()
|
|
|
|
}
|
2023-06-22 10:46:04 -07:00
|
|
|
writer.Header().Set("Content-Type", "application/json")
|
2024-03-18 12:41:03 -07:00
|
|
|
json.NewEncoder(writer).Encode(map[string]any{
|
2023-06-16 12:06:26 -07:00
|
|
|
"time": post.CreatedOn,
|
|
|
|
"id": post.ID,
|
|
|
|
"thread": config.WebPath(postBoard.Dir, "/res/", strconv.Itoa(topPost)+".html"),
|
|
|
|
})
|
|
|
|
} else if emailCommand == "noko" {
|
2022-11-07 16:56:50 -08:00
|
|
|
if post.IsTopPost {
|
2021-07-11 11:51:29 -07:00
|
|
|
http.Redirect(writer, request, systemCritical.WebRoot+postBoard.Dir+"/res/"+strconv.Itoa(post.ID)+".html", http.StatusFound)
|
2020-04-29 17:44:29 -07:00
|
|
|
} else {
|
2022-11-07 16:56:50 -08:00
|
|
|
topPost, _ := post.TopPostID()
|
|
|
|
http.Redirect(writer, request, systemCritical.WebRoot+postBoard.Dir+"/res/"+strconv.Itoa(topPost)+".html#"+strconv.Itoa(post.ID), http.StatusFound)
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
} else {
|
2021-07-11 11:51:29 -07:00
|
|
|
http.Redirect(writer, request, systemCritical.WebRoot+postBoard.Dir+"/", http.StatusFound)
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
}
|