1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 19:56:16 +00:00
mycorrhiza/shroom/upload.go

196 lines
5.3 KiB
Go
Raw Normal View History

2021-02-20 14:03:54 +00:00
package shroom
import (
2021-09-29 14:56:17 +00:00
"bytes"
2021-02-20 14:03:54 +00:00
"errors"
"fmt"
"github.com/bouncepaw/mycorrhiza/hyphae/backlinks"
2022-02-04 17:04:39 +00:00
"github.com/bouncepaw/mycorrhiza/mimetype"
2021-07-02 08:29:55 +00:00
"io"
2021-02-20 14:03:54 +00:00
"log"
"mime/multipart"
"os"
"path/filepath"
"strings"
2021-02-20 14:03:54 +00:00
2021-06-19 04:51:10 +00:00
"github.com/bouncepaw/mycorrhiza/files"
2021-02-20 14:03:54 +00:00
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/l18n"
2021-02-20 14:03:54 +00:00
"github.com/bouncepaw/mycorrhiza/user"
)
2022-02-04 17:04:39 +00:00
func historyMessageForTextUpload(h hyphae.Hypher, userMessage string) string {
var verb string
switch h.(type) {
case *hyphae.EmptyHypha:
2022-02-04 17:04:39 +00:00
verb = "Create"
default:
2022-02-04 17:04:39 +00:00
verb = "Edit"
2021-02-20 14:03:54 +00:00
}
2022-02-04 17:04:39 +00:00
if userMessage == "" {
return fmt.Sprintf("%s %s", verb, h.CanonicalName())
2021-06-14 00:38:43 +00:00
}
2022-02-04 17:04:39 +00:00
return fmt.Sprintf("%s %s: %s", verb, h.CanonicalName(), userMessage)
}
2021-06-14 00:38:43 +00:00
2022-02-04 17:04:39 +00:00
func writeTextToDiskForEmptyHypha(eh *hyphae.EmptyHypha, data []byte) error {
h := hyphae.FillEmptyHyphaUpToTextualHypha(eh, filepath.Join(files.HyphaeDir(), eh.CanonicalName()+".myco"))
return writeTextToDiskForNonEmptyHypha(h, data)
}
func writeTextToDiskForNonEmptyHypha(h *hyphae.MediaHypha, data []byte) error {
if err := os.MkdirAll(filepath.Dir(h.TextPartPath()), 0777); err != nil {
return err
}
if err := os.WriteFile(h.TextPartPath(), data, 0666); err != nil {
return err
}
return nil
}
// UploadText edits the hypha's text part and makes a history record about that.
func UploadText(h hyphae.Hypher, data []byte, userMessage string, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) {
hop = history.
Operation(history.TypeEditText).
WithMsg(historyMessageForTextUpload(h, userMessage))
// Privilege check
if !u.CanProceed("upload-text") {
rejectEditLog(h, u, "no rights")
return hop.WithErrAbort(errors.New(lc.Get("ui.act_norights_edit"))), lc.Get("ui.act_no_rights")
2021-02-20 14:03:54 +00:00
}
2022-02-04 17:04:39 +00:00
// Hypha name exploit check
if !hyphae.IsValidName(h.CanonicalName()) {
// We check for the name only. I suppose the filepath would be valid as well.
err := errors.New("invalid hypha name")
return hop.WithErrAbort(err), err.Error()
}
// Empty data check
if len(bytes.TrimSpace(data)) == 0 { // if nothing but whitespace
switch h := h.(type) {
2022-02-04 17:04:39 +00:00
case *hyphae.EmptyHypha:
// It's ok, just like cancel button.
return hop.Abort(), ""
case *hyphae.MediaHypha:
2022-02-04 17:04:39 +00:00
switch h.Kind() {
case hyphae.HyphaMedia:
// Writing no description, it's ok, just like cancel button.
return hop.Abort(), ""
case hyphae.HyphaText:
// What do you want passing nothing for a textual hypha?
return hop.WithErrAbort(errors.New("No data passed")), "Empty"
}
}
2021-02-20 14:03:54 +00:00
}
2022-02-04 17:04:39 +00:00
// At this point, we have a savable user-generated Mycomarkup document. Gotta save it.
switch h := h.(type) {
case *hyphae.EmptyHypha:
err := writeTextToDiskForEmptyHypha(h, data)
if err != nil {
return hop.WithErrAbort(err), err.Error()
}
hyphae.InsertIfNew(h)
case *hyphae.MediaHypha:
oldText, err := FetchTextPart(h)
if err != nil {
return hop.WithErrAbort(err), err.Error()
}
// TODO: that []byte(...) part should be removed
if bytes.Compare(data, []byte(oldText)) == 0 {
// No changes! Just like cancel button
return hop.Abort(), ""
}
err = writeTextToDiskForNonEmptyHypha(h, data)
if err != nil {
return hop.WithErrAbort(err), err.Error()
}
backlinks.UpdateBacklinksAfterEdit(h, oldText)
}
return hop.
WithFiles(h.TextPartPath()).
WithUser(u).
Apply(), ""
2021-02-20 14:03:54 +00:00
}
2022-02-04 17:04:39 +00:00
// UploadBinary edits the hypha's media part and makes a history record about that.
func UploadBinary(h hyphae.Hypher, mime string, file multipart.File, u *user.User, lc *l18n.Localizer) (*history.Op, string) {
2021-02-20 14:03:54 +00:00
var (
2022-02-03 22:29:01 +00:00
hop = history.Operation(history.TypeEditBinary).WithMsg(fmt.Sprintf("Upload attachment for %s with type %s", h.CanonicalName(), mime))
2021-07-02 08:29:55 +00:00
data, err = io.ReadAll(file)
2021-02-20 14:03:54 +00:00
)
if err != nil {
2021-02-26 16:43:45 +00:00
return hop.WithErrAbort(err), err.Error()
2021-02-20 14:03:54 +00:00
}
if errtitle, err := CanAttach(u, h, lc); err != nil {
2021-02-26 16:43:45 +00:00
return hop.WithErrAbort(err), errtitle
2021-02-20 14:03:54 +00:00
}
if len(data) == 0 {
2021-02-26 16:43:45 +00:00
return hop.WithErrAbort(errors.New("No data passed")), "Empty"
2021-02-20 14:03:54 +00:00
}
2022-02-04 17:04:39 +00:00
ext := mimetype.ToExtension(mime)
2021-02-20 14:03:54 +00:00
var (
2022-02-03 22:29:01 +00:00
fullPath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+ext)
2022-02-03 22:04:01 +00:00
sourceFullPath = h.TextPartPath()
2021-02-20 14:03:54 +00:00
)
2022-02-03 22:29:01 +00:00
if !isValidPath(fullPath) || !hyphae.IsValidName(h.CanonicalName()) {
2021-06-15 21:00:29 +00:00
err := errors.New("bad path")
return hop.WithErrAbort(err), err.Error()
}
2022-02-04 11:00:38 +00:00
if h := h.(*hyphae.MediaHypha); hop.Type == history.TypeEditBinary {
2022-02-03 22:04:01 +00:00
sourceFullPath = h.BinaryPath()
2021-02-20 14:03:54 +00:00
}
if err := os.MkdirAll(filepath.Dir(fullPath), 0777); err != nil {
2021-02-26 16:43:45 +00:00
return hop.WithErrAbort(err), err.Error()
2021-02-20 14:03:54 +00:00
}
2021-07-02 08:29:55 +00:00
if err := os.WriteFile(fullPath, data, 0666); err != nil {
2021-02-26 16:43:45 +00:00
return hop.WithErrAbort(err), err.Error()
2021-02-20 14:03:54 +00:00
}
switch h.(type) {
case *hyphae.EmptyHypha:
default:
if sourceFullPath != fullPath && sourceFullPath != "" {
if err := history.Rename(sourceFullPath, fullPath); err != nil {
return hop.WithErrAbort(err), err.Error()
}
log.Println("Move", sourceFullPath, "to", fullPath)
2021-02-20 14:03:54 +00:00
}
}
2022-02-03 22:39:21 +00:00
hyphae.InsertIfNew(h)
switch h.(type) {
case *hyphae.EmptyHypha:
default:
if h.HasTextPart() && hop.Type == history.TypeEditText && !history.FileChanged(fullPath) {
return hop.Abort(), "No changes"
}
2021-02-20 14:03:54 +00:00
}
// sic!
2022-02-04 17:04:39 +00:00
h.(*hyphae.MediaHypha).SetBinaryPath(fullPath)
2021-02-20 14:03:54 +00:00
return hop.WithFiles(fullPath).WithUser(u).Apply(), ""
}
func isValidPath(pathname string) bool {
return strings.HasPrefix(pathname, files.HyphaeDir())
}