diff --git a/hyphae/backlinks/backlinks.go b/hyphae/backlinks/backlinks.go index 3390bf7..6ed43b0 100644 --- a/hyphae/backlinks/backlinks.go +++ b/hyphae/backlinks/backlinks.go @@ -2,6 +2,7 @@ package backlinks import ( + "log" "os" "github.com/bouncepaw/mycorrhiza/hyphae" @@ -53,7 +54,7 @@ func IndexBacklinks() { } // BacklinksCount returns the amount of backlinks to the hypha. -func BacklinksCount(h hyphae.Hypher) int { +func BacklinksCount(h hyphae.Hypha) int { if links, exists := backlinkIndex[h.CanonicalName()]; exists { return len(links) } @@ -71,15 +72,26 @@ func toLinkSet(xs []string) linkSet { return result } -func fetchText(h hyphae.Hypher) string { - if !h.HasTextPart() { +func fetchText(h hyphae.Hypha) string { + var path string + switch h := h.(type) { + case *hyphae.EmptyHypha: + return "" + case *hyphae.TextualHypha: + path = h.TextFilePath() + case *hyphae.MediaHypha: + if !h.HasTextFile() { + return "" + } + path = h.TextFilePath() + } + + text, err := os.ReadFile(path) + if err != nil { + log.Println(err) return "" } - text, err := os.ReadFile(h.TextPartPath()) - if err == nil { - return string(text) - } - return "" + return string(text) } // backlinkIndexOperation is an operation for the backlink index. This operation is executed async-safe. diff --git a/hyphae/backlinks/hooks.go b/hyphae/backlinks/hooks.go index b5e8a39..9cc5237 100644 --- a/hyphae/backlinks/hooks.go +++ b/hyphae/backlinks/hooks.go @@ -9,26 +9,26 @@ import ( ) // UpdateBacklinksAfterEdit is a creation/editing hook for backlinks index -func UpdateBacklinksAfterEdit(h hyphae.Hypher, oldText string) { +func UpdateBacklinksAfterEdit(h hyphae.Hypha, oldText string) { oldLinks := extractHyphaLinksFromContent(h.CanonicalName(), oldText) newLinks := extractHyphaLinks(h) backlinkConveyor <- backlinkIndexEdit{h.CanonicalName(), oldLinks, newLinks} } // UpdateBacklinksAfterDelete is a deletion hook for backlinks index -func UpdateBacklinksAfterDelete(h hyphae.Hypher, oldText string) { +func UpdateBacklinksAfterDelete(h hyphae.Hypha, oldText string) { oldLinks := extractHyphaLinksFromContent(h.CanonicalName(), oldText) backlinkConveyor <- backlinkIndexDeletion{h.CanonicalName(), oldLinks} } // UpdateBacklinksAfterRename is a renaming hook for backlinks index -func UpdateBacklinksAfterRename(h hyphae.Hypher, oldName string) { +func UpdateBacklinksAfterRename(h hyphae.Hypha, oldName string) { actualLinks := extractHyphaLinks(h) backlinkConveyor <- backlinkIndexRenaming{oldName, h.CanonicalName(), actualLinks} } // extractHyphaLinks extracts hypha links from a desired hypha -func extractHyphaLinks(h hyphae.Hypher) []string { +func extractHyphaLinks(h hyphae.Hypha) []string { return extractHyphaLinksFromContent(h.CanonicalName(), fetchText(h)) } diff --git a/hyphae/count.go b/hyphae/count.go index 1f769d3..a414e84 100644 --- a/hyphae/count.go +++ b/hyphae/count.go @@ -17,7 +17,7 @@ func ResetCount() { count.Unlock() } -// Count how many hyphae there are. +// Count how many hyphae there are. This is a O(1), the number of hyphae is stored in memory. func Count() int { count.Lock() defer count.Unlock() diff --git a/hyphae/empty_hypha.go b/hyphae/empty_hypha.go index 25218d2..d205187 100644 --- a/hyphae/empty_hypha.go +++ b/hyphae/empty_hypha.go @@ -12,31 +12,17 @@ func (e *EmptyHypha) CanonicalName() string { return e.canonicalName } -func (e *EmptyHypha) HasTextPart() bool { - return false -} - -func (e *EmptyHypha) TextPartPath() string { - return "" -} - -// NewEmptyHypha returns an empty hypha struct with given name. -func NewEmptyHypha(hyphaName string) *EmptyHypha { - return &EmptyHypha{ - canonicalName: hyphaName, +func ExtendEmptyToTextual(e *EmptyHypha, mycoFilePath string) *TextualHypha { + return &TextualHypha{ + canonicalName: e.CanonicalName(), + mycoFilePath: mycoFilePath, } } -func FillEmptyHyphaUpToTextualHypha(e *EmptyHypha, textPath string) *NonEmptyHypha { // sic! - return &NonEmptyHypha{ - name: e.CanonicalName(), - TextPath: textPath, - } -} - -func FillEmptyHyphaUpToMediaHypha(e *EmptyHypha, binaryPath string) *NonEmptyHypha { // sic! - return &NonEmptyHypha{ - name: e.CanonicalName(), - binaryPath: binaryPath, +func ExtendEmptyToMedia(e *EmptyHypha, mediaFilePath string) *MediaHypha { + return &MediaHypha{ + canonicalName: e.CanonicalName(), + mycoFilePath: "", + mediaFilePath: mediaFilePath, } } diff --git a/hyphae/existing_hypha.go b/hyphae/existing_hypha.go new file mode 100644 index 0000000..9fa9491 --- /dev/null +++ b/hyphae/existing_hypha.go @@ -0,0 +1,39 @@ +package hyphae + +import ( + "github.com/bouncepaw/mycorrhiza/util" +) + +// ExistingHypha is not EmptyHypha. +type ExistingHypha interface { + Hypha + + // DoesExist does nothing except marks that the type is an ExistingHypha. + DoesExist() + + HasTextFile() bool + TextFilePath() string +} + +// RenameHyphaTo renames a hypha and renames stored filepaths as needed. The actual files are not moved, move them yourself. +func RenameHyphaTo(h ExistingHypha, newName string, replaceName func(string) string) { + // TODO: that replaceName is suspicious. + newName = util.CanonicalName(newName) + byNamesMutex.Lock() + h.Lock() + delete(byNames, h.CanonicalName()) + + switch h := h.(type) { + case *TextualHypha: + h.canonicalName = newName + h.mycoFilePath = replaceName(h.mycoFilePath) + case *MediaHypha: + h.canonicalName = newName + h.mycoFilePath = replaceName(h.mediaFilePath) + h.mediaFilePath = replaceName(h.mediaFilePath) + } + + byNames[h.CanonicalName()] = h + byNamesMutex.Unlock() + h.Unlock() +} diff --git a/hyphae/files.go b/hyphae/files.go index 423bc79..12a64cd 100644 --- a/hyphae/files.go +++ b/hyphae/files.go @@ -10,34 +10,45 @@ import ( // Index finds all hypha files in the full `path` and saves them to the hypha storage. func Index(path string) { - byNames = make(map[string]Hypher) - ch := make(chan Hypher, 5) + byNames = make(map[string]ExistingHypha) + ch := make(chan ExistingHypha, 5) - go func(ch chan Hypher) { + go func(ch chan ExistingHypha) { indexHelper(path, 0, ch) close(ch) }(ch) - for nh := range ch { - switch oh := ByName(nh.CanonicalName()).(type) { + for foundHypha := range ch { + switch storedHypha := ByName(foundHypha.CanonicalName()).(type) { case *EmptyHypha: - Insert(nh) - default: - // In case of conflicts the newer hypha overwrites the previous - switch nh, oh := nh.(*NonEmptyHypha), oh.(*NonEmptyHypha); { - case (nh.Kind() == HyphaText) && (oh.Kind() == HyphaMedia): - oh.TextPath = nh.TextPartPath() + Insert(foundHypha) - case (nh.Kind() == HyphaText) && (oh.Kind() == HyphaText): - log.Printf("File collision for hypha ‘%s’, using %s rather than %s\n", nh.CanonicalName(), nh.TextPartPath(), oh.TextPartPath()) - oh.TextPath = nh.TextPartPath() + case *TextualHypha: + switch foundHypha := foundHypha.(type) { + case *TextualHypha: // conflict! overwrite + storedHypha.mycoFilePath = foundHypha.mycoFilePath + log.Printf( + "File collision for hypha ‘%s’, using ‘%s’ rather than ‘%s’\n", + foundHypha.CanonicalName(), + foundHypha.TextFilePath(), + storedHypha.TextFilePath(), + ) + case *MediaHypha: // no conflict + Insert(ExtendTextualToMedia(storedHypha, foundHypha.mediaFilePath)) + } - case (nh.Kind() == HyphaMedia) && (oh.Kind() == HyphaMedia): - log.Printf("File collision for hypha ‘%s’, using %s rather than %s\n", nh.CanonicalName(), nh.BinaryPath(), oh.BinaryPath()) - oh.SetBinaryPath(nh.BinaryPath()) - - case (nh.Kind() == HyphaMedia) && (oh.Kind() == HyphaText): - oh.SetBinaryPath(nh.BinaryPath()) + case *MediaHypha: + switch foundHypha := foundHypha.(type) { + case *TextualHypha: // no conflict + storedHypha.mycoFilePath = foundHypha.mycoFilePath + case *MediaHypha: // conflict! overwrite + storedHypha.mediaFilePath = foundHypha.mediaFilePath + log.Printf( + "File collision for hypha ‘%s’, using ‘%s’ rather than ‘%s’\n", + foundHypha.CanonicalName(), + foundHypha.MediaFilePath(), + storedHypha.MediaFilePath(), + ) } } } @@ -47,7 +58,7 @@ func Index(path string) { // indexHelper finds all hypha files in the full `path` and sends them to the // channel. Handling of duplicate entries and attachment and counting them is // up to the caller. -func indexHelper(path string, nestLevel uint, ch chan Hypher) { +func indexHelper(path string, nestLevel uint, ch chan ExistingHypha) { nodes, err := os.ReadDir(path) if err != nil { log.Fatal(err) @@ -64,15 +75,20 @@ func indexHelper(path string, nestLevel uint, ch chan Hypher) { var ( hyphaPartPath = filepath.Join(path, node.Name()) hyphaName, isText, skip = mimetype.DataFromFilename(hyphaPartPath) - hypha = &NonEmptyHypha{name: hyphaName, Exists: true} ) if !skip { if isText { - hypha.TextPath = hyphaPartPath + ch <- &TextualHypha{ + canonicalName: hyphaName, + mycoFilePath: hyphaPartPath, + } } else { - hypha.SetBinaryPath(hyphaPartPath) + ch <- &MediaHypha{ + canonicalName: hyphaName, + mycoFilePath: "", + mediaFilePath: hyphaPartPath, + } } - ch <- hypha } } } diff --git a/hyphae/interface.go b/hyphae/hypha.go similarity index 55% rename from hyphae/interface.go rename to hyphae/hypha.go index 1d6c9d0..8dbc0ad 100644 --- a/hyphae/interface.go +++ b/hyphae/hypha.go @@ -22,25 +22,15 @@ func IsValidName(hyphaName string) bool { return true } -type HyphaKind int - -const ( - HyphaText HyphaKind = iota - HyphaMedia -) - -// Hypher is a temporary name for this interface. The name will become NonEmptyHypha, once the struct with the said name is deprecated for good. -type Hypher interface { +// Hypha is a hypha you know and love. +type Hypha interface { sync.Locker CanonicalName() string - - HasTextPart() bool - TextPartPath() string } // DeleteHypha deletes the hypha from the storage. -func DeleteHypha(h Hypher) { +func DeleteHypha(h ExistingHypha) { byNamesMutex.Lock() h.Lock() delete(byNames, h.CanonicalName()) @@ -49,19 +39,8 @@ func DeleteHypha(h Hypher) { h.Unlock() } -// RenameHyphaTo renames a hypha and performs respective changes in the storage. -func RenameHyphaTo(h Hypher, newName string) { - byNamesMutex.Lock() - h.Lock() - delete(byNames, h.CanonicalName()) - h.(*NonEmptyHypha).SetName(newName) - byNames[h.CanonicalName()] = h.(*NonEmptyHypha) - byNamesMutex.Unlock() - h.Unlock() -} - -// Insert inserts the hypha into the storage, possibly overwriting the previous hypha with the same name. Count incrementation is done if needed. -func Insert(h Hypher) (madeNewRecord bool) { +// Insert inserts the hypha into the storage, possibly overwriting the previous hypha with the same name. Count incrementation is done if needed. You cannot insert an empty hypha. +func Insert(h ExistingHypha) (madeNewRecord bool) { _, recorded := byNames[h.CanonicalName()] byNamesMutex.Lock() @@ -75,23 +54,15 @@ func Insert(h Hypher) (madeNewRecord bool) { return !recorded } -// InsertIfNew checks whether the hypha exists and returns `true` if it didn't and has been created. -func InsertIfNew(h Hypher) (madeNewRecord bool) { - switch ByName(h.CanonicalName()).(type) { - case *EmptyHypha: - return Insert(h) - default: - return false - } -} - // ByName returns a hypha by name. It returns an *EmptyHypha if there is no such hypha. This function is the only source of empty hyphae. -func ByName(hyphaName string) (h Hypher) { +func ByName(hyphaName string) (h Hypha) { byNamesMutex.Lock() defer byNamesMutex.Unlock() h, recorded := byNames[hyphaName] if recorded { return h } - return NewEmptyHypha(hyphaName) + return &EmptyHypha{ + canonicalName: hyphaName, + } } diff --git a/hyphae/iteration.go b/hyphae/iteration.go index ae9c2b8..b0d20d5 100644 --- a/hyphae/iteration.go +++ b/hyphae/iteration.go @@ -7,20 +7,20 @@ import ( // Iteration represents an iteration over all hyphae in the storage. You may use it instead of directly iterating using hyphae.YieldExistingHyphae when you want to do n checks at once instead of iterating n times. type Iteration struct { sync.Mutex - iterator func() chan Hypher - checks []func(h Hypher) CheckResult + iterator func() chan ExistingHypha + checks []func(h Hypha) CheckResult } // NewIteration constructs an iteration without checks. func NewIteration() *Iteration { return &Iteration{ iterator: YieldExistingHyphae, - checks: make([]func(h Hypher) CheckResult, 0), + checks: make([]func(h Hypha) CheckResult, 0), } } // AddCheck adds the check to the iteration. It is concurrent-safe. -func (i7n *Iteration) AddCheck(check func(h Hypher) CheckResult) { +func (i7n *Iteration) AddCheck(check func(h Hypha) CheckResult) { i7n.Lock() i7n.checks = append(i7n.checks, check) i7n.Unlock() diff --git a/hyphae/iterators.go b/hyphae/iterators.go index 13e8e3c..022b8f1 100644 --- a/hyphae/iterators.go +++ b/hyphae/iterators.go @@ -8,16 +8,15 @@ import ( "sync" ) -var byNames = make(map[string]Hypher) +var byNames = make(map[string]ExistingHypha) var byNamesMutex = sync.Mutex{} // YieldExistingHyphae iterates over all hyphae and yields all existing ones. -func YieldExistingHyphae() chan Hypher { - ch := make(chan Hypher) +func YieldExistingHyphae() chan ExistingHypha { + ch := make(chan ExistingHypha) go func() { for _, h := range byNames { switch h.(type) { - case *EmptyHypha: default: ch <- h } @@ -28,13 +27,18 @@ func YieldExistingHyphae() chan Hypher { } // FilterHyphaeWithText filters the source channel and yields only those hyphae than have text parts. -func FilterHyphaeWithText(src chan Hypher) chan Hypher { +func FilterHyphaeWithText(src chan ExistingHypha) chan ExistingHypha { // TODO: reimplement as a function with a callback? - sink := make(chan Hypher) + sink := make(chan ExistingHypha) go func() { for h := range src { - if h.HasTextPart() { + switch h := h.(type) { + case *TextualHypha: sink <- h + case *MediaHypha: + if h.HasTextFile() { + sink <- h + } } } close(sink) @@ -85,8 +89,8 @@ func PathographicSort(src chan string) <-chan string { } // Subhyphae returns slice of subhyphae. -func Subhyphae(h Hypher) []Hypher { - var hyphae []Hypher +func Subhyphae(h Hypha) []ExistingHypha { + var hyphae []ExistingHypha for subh := range YieldExistingHyphae() { if strings.HasPrefix(subh.CanonicalName(), h.CanonicalName()+"/") { hyphae = append(hyphae, subh) diff --git a/hyphae/media_hypha.go b/hyphae/media_hypha.go new file mode 100644 index 0000000..e3d48a6 --- /dev/null +++ b/hyphae/media_hypha.go @@ -0,0 +1,48 @@ +package hyphae + +import ( + "github.com/bouncepaw/mycorrhiza/files" + "path/filepath" + "sync" +) + +type MediaHypha struct { + sync.RWMutex + + canonicalName string + mycoFilePath string + mediaFilePath string +} + +func (m *MediaHypha) DoesExist() { +} + +func (m *MediaHypha) CanonicalName() string { + return m.canonicalName +} + +func (m *MediaHypha) TextFilePath() string { + if m.mycoFilePath == "" { + return filepath.Join(files.HyphaeDir(), m.CanonicalName()+".myco") + } + return m.mycoFilePath +} + +func (m *MediaHypha) HasTextFile() bool { + return m.mycoFilePath != "" +} + +func (m *MediaHypha) MediaFilePath() string { + return m.mediaFilePath +} + +func (m *MediaHypha) SetMediaFilePath(newPath string) { + m.mediaFilePath = newPath +} + +func ShrinkMediaToTextual(m *MediaHypha) *TextualHypha { + return &TextualHypha{ + canonicalName: m.CanonicalName(), + mycoFilePath: m.TextFilePath(), + } +} diff --git a/hyphae/non_empty_hypha.go b/hyphae/non_empty_hypha.go deleted file mode 100644 index 425544d..0000000 --- a/hyphae/non_empty_hypha.go +++ /dev/null @@ -1,52 +0,0 @@ -// Package hyphae is for the NonEmptyHypha type, hypha storage and stuff like that. It shall not depend on mycorrhiza modules other than util. -package hyphae - -import ( - "path/filepath" - "sync" - - "github.com/bouncepaw/mycorrhiza/files" -) - -// NonEmptyHypha keeps vital information about a media hypha -type NonEmptyHypha struct { - sync.RWMutex - - name string // Canonical name - Exists bool - TextPath string // == "" => no text part - binaryPath string // == "" => no attachment -} - -func (h *NonEmptyHypha) SetName(s string) { h.name = s } - -func (h *NonEmptyHypha) BinaryPath() string { return h.binaryPath } -func (h *NonEmptyHypha) SetBinaryPath(s string) { h.binaryPath = s } - -func (h *NonEmptyHypha) CanonicalName() string { - return h.name -} - -func (h *NonEmptyHypha) Kind() HyphaKind { // sic! - if h.HasAttachment() { - return HyphaMedia - } - return HyphaText -} - -func (h *NonEmptyHypha) HasTextPart() bool { - return h.TextPath != "" -} - -// TextPartPath returns rooted path to the file where the text part should be. -func (h *NonEmptyHypha) TextPartPath() string { - if h.TextPath == "" { - return filepath.Join(files.HyphaeDir(), h.name+".myco") - } - return h.TextPath -} - -// HasAttachment is true if the hypha has an attachment. -func (h *NonEmptyHypha) HasAttachment() bool { - return h.binaryPath != "" -} diff --git a/hyphae/textual_hypha.go b/hyphae/textual_hypha.go new file mode 100644 index 0000000..51af499 --- /dev/null +++ b/hyphae/textual_hypha.go @@ -0,0 +1,35 @@ +package hyphae + +import ( + "sync" +) + +type TextualHypha struct { + sync.RWMutex + + canonicalName string + mycoFilePath string +} + +func (t *TextualHypha) DoesExist() { +} + +func (t *TextualHypha) CanonicalName() string { + return t.canonicalName +} + +func (t *TextualHypha) HasTextFile() bool { + return true +} + +func (t *TextualHypha) TextFilePath() string { + return t.mycoFilePath +} + +func ExtendTextualToMedia(t *TextualHypha, mediaFilePath string) *MediaHypha { + return &MediaHypha{ + canonicalName: t.CanonicalName(), + mycoFilePath: t.TextFilePath(), + mediaFilePath: mediaFilePath, + } +} diff --git a/migration/rockets.go b/migration/rockets.go index eee0d39..f68ce97 100644 --- a/migration/rockets.go +++ b/migration/rockets.go @@ -41,10 +41,10 @@ func MigrateRocketsMaybe() { for hypha := range hyphae.FilterHyphaeWithText(hyphae.YieldExistingHyphae()) { /// Open file, read from file, modify file. If anything goes wrong, scream and shout. - file, err := os.OpenFile(hypha.TextPartPath(), os.O_RDWR, 0766) + file, err := os.OpenFile(hypha.TextFilePath(), os.O_RDWR, 0766) if err != nil { hop.WithErrAbort(err) - log.Fatal("Something went wrong when opening ", hypha.TextPartPath(), ": ", err.Error()) + log.Fatal("Something went wrong when opening ", hypha.TextFilePath(), ": ", err.Error()) } var buf strings.Builder @@ -52,7 +52,7 @@ func MigrateRocketsMaybe() { if err != nil { hop.WithErrAbort(err) _ = file.Close() - log.Fatal("Something went wrong when reading ", hypha.TextPartPath(), ": ", err.Error()) + log.Fatal("Something went wrong when reading ", hypha.TextFilePath(), ": ", err.Error()) } var ( @@ -60,27 +60,27 @@ func MigrateRocketsMaybe() { newText = tools.MigrateRocketLinks(oldText) ) if oldText != newText { // This file right here is being migrated for real. - mycoFiles = append(mycoFiles, hypha.TextPartPath()) + mycoFiles = append(mycoFiles, hypha.TextFilePath()) err = file.Truncate(0) if err != nil { hop.WithErrAbort(err) _ = file.Close() - log.Fatal("Something went wrong when truncating ", hypha.TextPartPath(), ": ", err.Error()) + log.Fatal("Something went wrong when truncating ", hypha.TextFilePath(), ": ", err.Error()) } _, err = file.Seek(0, 0) if err != nil { hop.WithErrAbort(err) _ = file.Close() - log.Fatal("Something went wrong when seeking in ", hypha.TextPartPath(), ": ", err.Error()) + log.Fatal("Something went wrong when seeking in ", hypha.TextFilePath(), ": ", err.Error()) } _, err = file.WriteString(newText) if err != nil { hop.WithErrAbort(err) _ = file.Close() - log.Fatal("Something went wrong when writing to ", hypha.TextPartPath(), ": ", err.Error()) + log.Fatal("Something went wrong when writing to ", hypha.TextFilePath(), ": ", err.Error()) } } _ = file.Close() diff --git a/shroom/can.go b/shroom/can.go index 8c269a2..b790ce0 100644 --- a/shroom/can.go +++ b/shroom/can.go @@ -11,14 +11,14 @@ import ( // TODO: get rid of this abomination func canFactory( - rejectLogger func(hyphae.Hypher, *user.User, string), + rejectLogger func(hyphae.Hypha, *user.User, string), action string, - dispatcher func(hyphae.Hypher, *user.User, *l18n.Localizer) (string, string), + dispatcher func(hyphae.Hypha, *user.User, *l18n.Localizer) (string, string), noRightsMsg string, notExistsMsg string, mustExist bool, -) func(*user.User, hyphae.Hypher, *l18n.Localizer) (string, error) { - return func(u *user.User, h hyphae.Hypher, lc *l18n.Localizer) (string, error) { +) func(*user.User, hyphae.Hypha, *l18n.Localizer) (string, error) { + return func(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (string, error) { if !u.CanProceed(action) { rejectLogger(h, u, "no rights") return lc.Get("ui.act_no_rights"), errors.New(lc.Get(noRightsMsg)) @@ -66,14 +66,12 @@ var ( CanUnattach = canFactory( rejectUnattachLog, "unattach-confirm", - func(h hyphae.Hypher, u *user.User, lc *l18n.Localizer) (errmsg, errtitle string) { + func(h hyphae.Hypha, u *user.User, lc *l18n.Localizer) (errmsg, errtitle string) { switch h := h.(type) { case *hyphae.EmptyHypha: - case *hyphae.NonEmptyHypha: - if h.Kind() != hyphae.HyphaMedia { - rejectUnattachLog(h, u, "no amnt") - return lc.Get("ui.act_noattachment_tip"), lc.Get("ui.act_noattachment") - } + case *hyphae.TextualHypha: + rejectUnattachLog(h, u, "no amnt") + return lc.Get("ui.act_noattachment_tip"), lc.Get("ui.act_noattachment") } return "", "" diff --git a/shroom/delete.go b/shroom/delete.go index 9654710..90fa332 100644 --- a/shroom/delete.go +++ b/shroom/delete.go @@ -11,23 +11,30 @@ import ( ) // DeleteHypha deletes hypha and makes a history record about that. -func DeleteHypha(u *user.User, h hyphae.Hypher, lc *l18n.Localizer) (hop *history.Op, errtitle string) { - hop = history.Operation(history.TypeDeleteHypha) +func DeleteHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *history.Op, errtitle string) { + hop = history. + Operation(history.TypeDeleteHypha). + WithMsg(fmt.Sprintf("Delete ‘%s’", h.CanonicalName())). + WithUser(u) if errtitle, err := CanDelete(u, h, lc); errtitle != "" { hop.WithErrAbort(err) return hop, errtitle } - originalText, _ := FetchTextPart(h) - hop. - WithFilesRemoved(h.TextPartPath(), h.(*hyphae.NonEmptyHypha).BinaryPath()). - WithMsg(fmt.Sprintf("Delete ‘%s’", h.CanonicalName())). - WithUser(u). - Apply() + switch h := h.(type) { + case *hyphae.MediaHypha: + hop.WithFilesRemoved(h.MediaFilePath(), h.TextFilePath()) + case *hyphae.TextualHypha: + hop.WithFilesRemoved(h.TextFilePath()) + default: + panic("impossible") + } + originalText, _ := FetchTextFile(h) + hop.Apply() if !hop.HasErrors() { backlinks.UpdateBacklinksAfterDelete(h, originalText) - hyphae.DeleteHypha(h) + hyphae.DeleteHypha(h.(hyphae.ExistingHypha)) // we panicked before, so it's safe } return hop, "" } diff --git a/shroom/init.go b/shroom/init.go index 751d4dc..172f8cc 100644 --- a/shroom/init.go +++ b/shroom/init.go @@ -10,6 +10,7 @@ import ( ) func init() { + // TODO: clean this complete and utter mess globals.HyphaExists = func(hyphaName string) bool { switch hyphae.ByName(hyphaName).(type) { case *hyphae.EmptyHypha: @@ -22,12 +23,11 @@ func init() { switch h := hyphae.ByName(hyphaName).(type) { case *hyphae.EmptyHypha: err = errors.New("Hypha " + hyphaName + " does not exist") - default: - rawText, err = FetchTextPart(h) - if h := h.(*hyphae.NonEmptyHypha); h.Kind() == hyphae.HyphaMedia { - // the view is localized, but we can't pass it, so... - binaryBlock = views.AttachmentHTMLRaw(h) - } + case *hyphae.TextualHypha: + rawText, err = FetchTextFile(h) + case *hyphae.MediaHypha: + rawText, err = FetchTextFile(h) + binaryBlock = views.AttachmentHTMLRaw(h) } return } diff --git a/shroom/log.go b/shroom/log.go index d626fa1..d86bc9f 100644 --- a/shroom/log.go +++ b/shroom/log.go @@ -7,18 +7,18 @@ import ( "github.com/bouncepaw/mycorrhiza/user" ) -func rejectDeleteLog(h hyphae.Hypher, u *user.User, errmsg string) { +func rejectDeleteLog(h hyphae.Hypha, u *user.User, errmsg string) { log.Printf("Reject delete ‘%s’ by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) } -func rejectRenameLog(h hyphae.Hypher, u *user.User, errmsg string) { +func rejectRenameLog(h hyphae.Hypha, u *user.User, errmsg string) { log.Printf("Reject rename ‘%s’ by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) } -func rejectUnattachLog(h hyphae.Hypher, u *user.User, errmsg string) { +func rejectUnattachLog(h hyphae.Hypha, u *user.User, errmsg string) { log.Printf("Reject unattach ‘%s’ by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) } -func rejectEditLog(h hyphae.Hypher, u *user.User, errmsg string) { +func rejectEditLog(h hyphae.Hypha, u *user.User, errmsg string) { log.Printf("Reject edit ‘%s’ by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) } -func rejectAttachLog(h hyphae.Hypher, u *user.User, errmsg string) { +func rejectAttachLog(h hyphae.Hypha, u *user.User, errmsg string) { log.Printf("Reject attach ‘%s’ by @%s: %s\n", h.CanonicalName(), u.Name, errmsg) } diff --git a/shroom/rename.go b/shroom/rename.go index ec2d8e3..3a5a60b 100644 --- a/shroom/rename.go +++ b/shroom/rename.go @@ -13,7 +13,7 @@ import ( "github.com/bouncepaw/mycorrhiza/util" ) -func canRenameThisToThat(oh hyphae.Hypher, nh hyphae.Hypher, u *user.User, lc *l18n.Localizer) (errtitle string, err error) { +func canRenameThisToThat(oh hyphae.Hypha, nh hyphae.Hypha, u *user.User, lc *l18n.Localizer) (errtitle string, err error) { switch nh.(type) { case *hyphae.EmptyHypha: default: @@ -35,7 +35,7 @@ func canRenameThisToThat(oh hyphae.Hypher, nh hyphae.Hypher, u *user.User, lc *l } // RenameHypha renames hypha from old name `hyphaName` to `newName` and makes a history record about that. If `recursive` is `true`, its subhyphae will be renamed the same way. -func RenameHypha(h hyphae.Hypher, newHypha hyphae.Hypher, recursive bool, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) { +func RenameHypha(h hyphae.Hypha, newHypha hyphae.Hypha, recursive bool, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) { newHypha.Lock() defer newHypha.Unlock() hop = history.Operation(history.TypeRenameHypha) @@ -54,7 +54,7 @@ func RenameHypha(h hyphae.Hypher, newHypha hyphae.Hypher, recursive bool, u *use replaceName = func(str string) string { return re.ReplaceAllString(util.CanonicalName(str), newHypha.CanonicalName()) } - hyphaeToRename = findHyphaeToRename(h, recursive) + hyphaeToRename = findHyphaeToRename(h.(hyphae.ExistingHypha), recursive) renameMap, err = renamingPairs(hyphaeToRename, replaceName) renameMsg = "Rename ‘%s’ to ‘%s’" ) @@ -70,47 +70,43 @@ func RenameHypha(h hyphae.Hypher, newHypha hyphae.Hypher, recursive bool, u *use WithUser(u). Apply() if len(hop.Errs) == 0 { - for _, h := range hyphaeToRename { - h := h.(*hyphae.NonEmptyHypha) // ontology think + for _, H := range hyphaeToRename { + h := H.(hyphae.ExistingHypha) // ontology think oldName := h.CanonicalName() - hyphae.RenameHyphaTo(h, replaceName(h.CanonicalName())) - h.Lock() - h.TextPath = replaceName(h.TextPath) - h.SetBinaryPath(replaceName(h.BinaryPath())) - h.Unlock() + hyphae.RenameHyphaTo(h, replaceName(h.CanonicalName()), replaceName) backlinks.UpdateBacklinksAfterRename(h, oldName) } } return hop, "" } -func findHyphaeToRename(superhypha hyphae.Hypher, recursive bool) []hyphae.Hypher { - hyphaList := []hyphae.Hypher{superhypha} +func findHyphaeToRename(superhypha hyphae.ExistingHypha, recursive bool) []hyphae.ExistingHypha { + hyphaList := []hyphae.ExistingHypha{superhypha} if recursive { hyphaList = append(hyphaList, hyphae.Subhyphae(superhypha)...) } return hyphaList } -func renamingPairs(hyphaeToRename []hyphae.Hypher, replaceName func(string) string) (map[string]string, error) { - renameMap := make(map[string]string) - newNames := make([]string, len(hyphaeToRename)) +func renamingPairs(hyphaeToRename []hyphae.ExistingHypha, replaceName func(string) string) (map[string]string, error) { + var ( + renameMap = make(map[string]string) + newNames = make([]string, len(hyphaeToRename)) + ) for _, h := range hyphaeToRename { h.Lock() newNames = append(newNames, replaceName(h.CanonicalName())) - if h.HasTextPart() { - renameMap[h.TextPartPath()] = replaceName(h.TextPartPath()) + if h.HasTextFile() { + renameMap[h.TextFilePath()] = replaceName(h.TextFilePath()) } switch h := h.(type) { - case *hyphae.NonEmptyHypha: - if h.Kind() == hyphae.HyphaMedia { // ontology think - renameMap[h.BinaryPath()] = replaceName(h.BinaryPath()) - } + case *hyphae.MediaHypha: + renameMap[h.MediaFilePath()] = replaceName(h.MediaFilePath()) } h.Unlock() } if firstFailure, ok := hyphae.AreFreeNames(newNames...); !ok { - return nil, errors.New("NonEmptyHypha " + firstFailure + " already exists") + return nil, errors.New("Hypha " + firstFailure + " already exists") } return renameMap, nil } diff --git a/shroom/unattach.go b/shroom/unattach.go index 3ef4877..a2edc97 100644 --- a/shroom/unattach.go +++ b/shroom/unattach.go @@ -10,17 +10,17 @@ import ( ) // UnattachHypha unattaches hypha and makes a history record about that. -func UnattachHypha(u *user.User, h hyphae.Hypher, lc *l18n.Localizer) (hop *history.Op, errtitle string) { +func UnattachHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *history.Op, errtitle string) { hop = history.Operation(history.TypeUnattachHypha) if errtitle, err := CanUnattach(u, h, lc); errtitle != "" { hop.WithErrAbort(err) return hop, errtitle } - H := h.(*hyphae.NonEmptyHypha) + H := h.(*hyphae.MediaHypha) hop. - WithFilesRemoved(H.BinaryPath()). + WithFilesRemoved(H.MediaFilePath()). WithMsg(fmt.Sprintf("Unattach ‘%s’", h.CanonicalName())). WithUser(u). Apply() @@ -31,12 +31,10 @@ func UnattachHypha(u *user.User, h hyphae.Hypher, lc *l18n.Localizer) (hop *hist return hop.WithErrAbort(fmt.Errorf("Could not unattach this hypha due to internal server errors: %v", hop.Errs)), "Error" } - if H.BinaryPath() != "" { - H.SetBinaryPath("") - } - // If nothing is left of the hypha - if H.TextPath == "" { - hyphae.DeleteHypha(h) + if H.HasTextFile() { + hyphae.Insert(hyphae.ShrinkMediaToTextual(H)) + } else { + hyphae.DeleteHypha(H) } return hop, "" } diff --git a/shroom/upload.go b/shroom/upload.go index 67c9653..8ec5f9c 100644 --- a/shroom/upload.go +++ b/shroom/upload.go @@ -18,7 +18,7 @@ import ( "path/filepath" ) -func historyMessageForTextUpload(h hyphae.Hypher, userMessage string) string { +func historyMessageForTextUpload(h hyphae.Hypha, userMessage string) string { var verb string switch h.(type) { case *hyphae.EmptyHypha: @@ -33,21 +33,21 @@ func historyMessageForTextUpload(h hyphae.Hypher, userMessage string) string { return fmt.Sprintf("%s ‘%s’: %s", verb, h.CanonicalName(), userMessage) } -func writeTextToDisk(h *hyphae.NonEmptyHypha, data []byte, hop *history.Op) error { - if err := os.MkdirAll(filepath.Dir(h.TextPartPath()), 0777); err != nil { +func writeTextToDisk(h hyphae.ExistingHypha, data []byte, hop *history.Op) error { + if err := os.MkdirAll(filepath.Dir(h.TextFilePath()), 0777); err != nil { return err } - if err := os.WriteFile(h.TextPartPath(), data, 0666); err != nil { + if err := os.WriteFile(h.TextFilePath(), data, 0666); err != nil { return err } - hop.WithFiles(h.TextPartPath()) + hop.WithFiles(h.TextFilePath()) 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) { +func UploadText(h hyphae.Hypha, data []byte, userMessage string, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) { hop = history. Operation(history.TypeEditText). WithMsg(historyMessageForTextUpload(h, userMessage)). @@ -68,19 +68,16 @@ func UploadText(h hyphae.Hypher, data []byte, userMessage string, u *user.User, // Empty data check if len(bytes.TrimSpace(data)) == 0 { // if nothing but whitespace - switch h := h.(type) { + switch h.(type) { case *hyphae.EmptyHypha: // It's ok, just like cancel button. return hop.Abort(), "" - case *hyphae.NonEmptyHypha: - 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" - } + case *hyphae.MediaHypha: + // Writing no description, it's ok, just like cancel button. + return hop.Abort(), "" + case *hyphae.TextualHypha: + // What do you want passing nothing for a textual hypha? + return hop.WithErrAbort(errors.New("No data passed")), "Empty" } } @@ -88,7 +85,7 @@ func UploadText(h hyphae.Hypher, data []byte, userMessage string, u *user.User, switch h := h.(type) { case *hyphae.EmptyHypha: - H := hyphae.FillEmptyHyphaUpToTextualHypha(h, filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")) + H := hyphae.ExtendEmptyToTextual(h, filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")) err := writeTextToDisk(H, data, hop) if err != nil { @@ -96,8 +93,26 @@ func UploadText(h hyphae.Hypher, data []byte, userMessage string, u *user.User, } hyphae.Insert(H) - case *hyphae.NonEmptyHypha: - oldText, err := FetchTextPart(h) + case *hyphae.MediaHypha: + oldText, err := FetchTextFile(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 = writeTextToDisk(h, data, hop) + if err != nil { + return hop.WithErrAbort(err), err.Error() + } + + backlinks.UpdateBacklinksAfterEdit(h, oldText) + case *hyphae.TextualHypha: + oldText, err := FetchTextFile(h) if err != nil { return hop.WithErrAbort(err), err.Error() } @@ -119,12 +134,12 @@ func UploadText(h hyphae.Hypher, data []byte, userMessage string, u *user.User, return hop.Apply(), "" } -func historyMessageForMediaUpload(h hyphae.Hypher, mime string) string { +func historyMessageForMediaUpload(h hyphae.Hypha, mime string) string { return fmt.Sprintf("Upload media for ‘%s’ with type ‘%s’", h.CanonicalName(), mime) } // writeMediaToDisk saves the given data with the given mime type for the given hypha to the disk and returns the path to the saved file and an error, if any. -func writeMediaToDisk(h hyphae.Hypher, mime string, data []byte) (string, error) { +func writeMediaToDisk(h hyphae.Hypha, mime string, data []byte) (string, error) { var ( ext = mimetype.ToExtension(mime) // That's where the file will go @@ -142,7 +157,7 @@ func writeMediaToDisk(h hyphae.Hypher, mime string, data []byte) (string, error) } // 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) { +func UploadBinary(h hyphae.Hypha, mime string, file multipart.File, u *user.User, lc *l18n.Localizer) (*history.Op, string) { hop := history. Operation(history.TypeEditBinary). WithMsg(historyMessageForMediaUpload(h, mime)). @@ -180,21 +195,18 @@ func UploadBinary(h hyphae.Hypher, mime string, file multipart.File, u *user.Use switch h := h.(type) { case *hyphae.EmptyHypha: - H := hyphae.FillEmptyHyphaUpToMediaHypha(h, uploadedFilePath) + H := hyphae.ExtendEmptyToMedia(h, uploadedFilePath) hyphae.Insert(H) - case *hyphae.NonEmptyHypha: - switch h.Kind() { - case hyphae.HyphaText: - h.SetBinaryPath(uploadedFilePath) - case hyphae.HyphaMedia: // If this is not the first media the hypha gets - prevFilePath := h.BinaryPath() - if prevFilePath != uploadedFilePath { - if err := history.Rename(prevFilePath, uploadedFilePath); err != nil { - return hop.WithErrAbort(err), err.Error() - } - log.Printf("Move ‘%s’ to ‘%s’\n", prevFilePath, uploadedFilePath) - h.SetBinaryPath(uploadedFilePath) + case *hyphae.TextualHypha: + hyphae.Insert(hyphae.ExtendTextualToMedia(h, uploadedFilePath)) + case *hyphae.MediaHypha: // If this is not the first media the hypha gets + prevFilePath := h.MediaFilePath() + if prevFilePath != uploadedFilePath { + if err := history.Rename(prevFilePath, uploadedFilePath); err != nil { + return hop.WithErrAbort(err), err.Error() } + log.Printf("Move ‘%s’ to ‘%s’\n", prevFilePath, uploadedFilePath) + h.SetMediaFilePath(uploadedFilePath) } } diff --git a/shroom/view.go b/shroom/view.go index b410dc5..c1ef63b 100644 --- a/shroom/view.go +++ b/shroom/view.go @@ -8,22 +8,32 @@ import ( "github.com/bouncepaw/mycorrhiza/hyphae" ) -// FetchTextPart tries to read text file of the given hypha. If there is no file, empty string is returned. -func FetchTextPart(h hyphae.Hypher) (string, error) { - switch h.(type) { +// FetchTextFile tries to read text file of the given hypha. If there is no file, empty string is returned. +func FetchTextFile(h hyphae.Hypha) (string, error) { + switch h := h.(type) { case *hyphae.EmptyHypha: return "", errors.New("empty hyphae have no text") + case *hyphae.MediaHypha: + if !h.HasTextFile() { + return "", nil + } + text, err := os.ReadFile(h.TextFilePath()) + if os.IsNotExist(err) { + return "", nil + } else if err != nil { + return "", err + } + return string(text), nil + case *hyphae.TextualHypha: + text, err := os.ReadFile(h.TextFilePath()) + if os.IsNotExist(err) { + return "", nil + } else if err != nil { + return "", err + } + return string(text), nil } - if !h.HasTextPart() { - return "", nil - } - text, err := os.ReadFile(h.TextPartPath()) - if os.IsNotExist(err) { - return "", nil - } else if err != nil { - return "", err - } - return string(text), nil + panic("unreachable") } // SetHeaderLinks initializes header links by reading the configured hypha, if there is any, or resorting to default values. @@ -31,8 +41,8 @@ func SetHeaderLinks() { switch userLinksHypha := hyphae.ByName(cfg.HeaderLinksHypha).(type) { case *hyphae.EmptyHypha: cfg.SetDefaultHeaderLinks() - default: - contents, err := os.ReadFile(userLinksHypha.TextPartPath()) + case hyphae.ExistingHypha: + contents, err := os.ReadFile(userLinksHypha.TextFilePath()) if err != nil || len(contents) == 0 { cfg.SetDefaultHeaderLinks() } else { diff --git a/tree/tree.go b/tree/tree.go index 0a38770..6d05e8d 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -18,7 +18,7 @@ func findSiblings(hyphaName string) []*sibling { } var ( siblingsMap = make(map[string]bool) - siblingCheck = func(h hyphae.Hypher) hyphae.CheckResult { + siblingCheck = func(h hyphae.Hypha) hyphae.CheckResult { switch { case h.CanonicalName() == hyphaName, // NonEmptyHypha is no sibling of itself h.CanonicalName() == parentHyphaName: // Parent hypha is no sibling of its child @@ -63,7 +63,7 @@ func findSiblings(hyphaName string) []*sibling { func countSubhyphae(siblings []*sibling) { var ( - subhyphaCheck = func(h hyphae.Hypher) hyphae.CheckResult { + subhyphaCheck = func(h hyphae.Hypha) hyphae.CheckResult { for _, s := range siblings { if path.Dir(h.CanonicalName()) == s.name { s.directSubhyphaeCount++ diff --git a/views/history.qtpl b/views/history.qtpl index eb3ead6..9f6d957 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -9,10 +9,10 @@ {% import "github.com/bouncepaw/mycorrhiza/history" %} -{% func PrimitiveDiffHTML(rq *http.Request, h hyphae.Hypher, u *user.User, hash string) %} +{% func PrimitiveDiffHTML(rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) %} {% code lc := l18n.FromRequest(rq) -text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash) +text, err := history.PrimitiveDiffAtRevision(h.TextFilePath(), hash) if err != nil { text = err.Error() } diff --git a/views/history.qtpl.go b/views/history.qtpl.go index 86c5e32..92327ec 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -42,13 +42,13 @@ var ( ) //line views/history.qtpl:12 -func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hypher, u *user.User, hash string) { +func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) { //line views/history.qtpl:12 qw422016.N().S(` `) //line views/history.qtpl:14 lc := l18n.FromRequest(rq) - text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash) + text, err := history.PrimitiveDiffAtRevision(h.TextFilePath(), hash) if err != nil { text = err.Error() } @@ -76,7 +76,7 @@ func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h hyph } //line views/history.qtpl:28 -func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hypher, u *user.User, hash string) { +func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) { //line views/history.qtpl:28 qw422016 := qt422016.AcquireWriter(qq422016) //line views/history.qtpl:28 @@ -87,7 +87,7 @@ func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h hyph } //line views/history.qtpl:28 -func PrimitiveDiffHTML(rq *http.Request, h hyphae.Hypher, u *user.User, hash string) string { +func PrimitiveDiffHTML(rq *http.Request, h hyphae.ExistingHypha, u *user.User, hash string) string { //line views/history.qtpl:28 qb422016 := qt422016.AcquireByteBuffer() //line views/history.qtpl:28 diff --git a/views/hypha.qtpl b/views/hypha.qtpl index 8997de1..366a280 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -11,7 +11,7 @@ {% func mycoLink(lc *l18n.Localizer) %}{%s lc.Get("ui.notexist_write_myco") %}{% endfunc %} -{% func nonExistentHyphaNotice(h hyphae.Hypher, u *user.User, lc *l18n.Localizer) %} +{% func nonExistentHyphaNotice(h hyphae.Hypha, u *user.User, lc *l18n.Localizer) %}

{%s lc.Get("ui.notexist_heading") %}

{% if cfg.UseAuth && u.Group == "anon" %} @@ -47,7 +47,7 @@
{% endfunc %} -{% func NaviTitleHTML(h hyphae.Hypher) %} +{% func NaviTitleHTML(h hyphae.Hypha) %} {% code var ( prevAcc = "/hypha/" @@ -75,10 +75,10 @@ {% endfunc %} -{% func AttachmentHTMLRaw(h *hyphae.NonEmptyHypha) %}{%= AttachmentHTML(h, l18n.New("en", "en")) %}{% endfunc %} +{% func AttachmentHTMLRaw(h *hyphae.MediaHypha) %}{%= AttachmentHTML(h, l18n.New("en", "en")) %}{% endfunc %} -{% func AttachmentHTML(h *hyphae.NonEmptyHypha, lc *l18n.Localizer) %} - {% switch filepath.Ext(h.BinaryPath()) %} +{% func AttachmentHTML(h *hyphae.MediaHypha, lc *l18n.Localizer) %} + {% switch filepath.Ext(h.MediaFilePath()) %} {% case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico" %}
diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index d689883..0832a78 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -117,7 +117,7 @@ func mycoLink(lc *l18n.Localizer) string { } //line views/hypha.qtpl:14 -func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h hyphae.Hypher, u *user.User, lc *l18n.Localizer) { +func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h hyphae.Hypha, u *user.User, lc *l18n.Localizer) { //line views/hypha.qtpl:14 qw422016.N().S(`
@@ -230,7 +230,7 @@ func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h hyphae.Hypher, u } //line views/hypha.qtpl:48 -func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h hyphae.Hypher, u *user.User, lc *l18n.Localizer) { +func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h hyphae.Hypha, u *user.User, lc *l18n.Localizer) { //line views/hypha.qtpl:48 qw422016 := qt422016.AcquireWriter(qq422016) //line views/hypha.qtpl:48 @@ -241,7 +241,7 @@ func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h hyphae.Hypher, u } //line views/hypha.qtpl:48 -func nonExistentHyphaNotice(h hyphae.Hypher, u *user.User, lc *l18n.Localizer) string { +func nonExistentHyphaNotice(h hyphae.Hypha, u *user.User, lc *l18n.Localizer) string { //line views/hypha.qtpl:48 qb422016 := qt422016.AcquireByteBuffer() //line views/hypha.qtpl:48 @@ -256,7 +256,7 @@ func nonExistentHyphaNotice(h hyphae.Hypher, u *user.User, lc *l18n.Localizer) s } //line views/hypha.qtpl:50 -func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h hyphae.Hypher) { +func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h hyphae.Hypha) { //line views/hypha.qtpl:50 qw422016.N().S(` `) @@ -323,7 +323,7 @@ func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h hyphae.Hypher) { } //line views/hypha.qtpl:76 -func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h hyphae.Hypher) { +func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h hyphae.Hypha) { //line views/hypha.qtpl:76 qw422016 := qt422016.AcquireWriter(qq422016) //line views/hypha.qtpl:76 @@ -334,7 +334,7 @@ func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h hyphae.Hypher) { } //line views/hypha.qtpl:76 -func NaviTitleHTML(h hyphae.Hypher) string { +func NaviTitleHTML(h hyphae.Hypha) string { //line views/hypha.qtpl:76 qb422016 := qt422016.AcquireByteBuffer() //line views/hypha.qtpl:76 @@ -349,14 +349,14 @@ func NaviTitleHTML(h hyphae.Hypher) string { } //line views/hypha.qtpl:78 -func StreamAttachmentHTMLRaw(qw422016 *qt422016.Writer, h *hyphae.NonEmptyHypha) { +func StreamAttachmentHTMLRaw(qw422016 *qt422016.Writer, h *hyphae.MediaHypha) { //line views/hypha.qtpl:78 StreamAttachmentHTML(qw422016, h, l18n.New("en", "en")) //line views/hypha.qtpl:78 } //line views/hypha.qtpl:78 -func WriteAttachmentHTMLRaw(qq422016 qtio422016.Writer, h *hyphae.NonEmptyHypha) { +func WriteAttachmentHTMLRaw(qq422016 qtio422016.Writer, h *hyphae.MediaHypha) { //line views/hypha.qtpl:78 qw422016 := qt422016.AcquireWriter(qq422016) //line views/hypha.qtpl:78 @@ -367,7 +367,7 @@ func WriteAttachmentHTMLRaw(qq422016 qtio422016.Writer, h *hyphae.NonEmptyHypha) } //line views/hypha.qtpl:78 -func AttachmentHTMLRaw(h *hyphae.NonEmptyHypha) string { +func AttachmentHTMLRaw(h *hyphae.MediaHypha) string { //line views/hypha.qtpl:78 qb422016 := qt422016.AcquireByteBuffer() //line views/hypha.qtpl:78 @@ -382,12 +382,12 @@ func AttachmentHTMLRaw(h *hyphae.NonEmptyHypha) string { } //line views/hypha.qtpl:80 -func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.NonEmptyHypha, lc *l18n.Localizer) { +func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.MediaHypha, lc *l18n.Localizer) { //line views/hypha.qtpl:80 qw422016.N().S(` `) //line views/hypha.qtpl:81 - switch filepath.Ext(h.BinaryPath()) { + switch filepath.Ext(h.MediaFilePath()) { //line views/hypha.qtpl:83 case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico": //line views/hypha.qtpl:83 @@ -486,7 +486,7 @@ func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.NonEmptyHypha, lc } //line views/hypha.qtpl:109 -func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.NonEmptyHypha, lc *l18n.Localizer) { +func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.MediaHypha, lc *l18n.Localizer) { //line views/hypha.qtpl:109 qw422016 := qt422016.AcquireWriter(qq422016) //line views/hypha.qtpl:109 @@ -497,7 +497,7 @@ func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.NonEmptyHypha, lc } //line views/hypha.qtpl:109 -func AttachmentHTML(h *hyphae.NonEmptyHypha, lc *l18n.Localizer) string { +func AttachmentHTML(h *hyphae.MediaHypha, lc *l18n.Localizer) string { //line views/hypha.qtpl:109 qb422016 := qt422016.AcquireByteBuffer() //line views/hypha.qtpl:109 diff --git a/views/nav.qtpl b/views/nav.qtpl index 52230d4..479b728 100644 --- a/views/nav.qtpl +++ b/views/nav.qtpl @@ -5,7 +5,7 @@ {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} -{% func hyphaInfoEntry(h hyphae.Hypher, u *user.User, action, displayText string) %} +{% func hyphaInfoEntry(h hyphae.Hypha, u *user.User, action, displayText string) %} {% if u.CanProceed(action) %}
  • {%s displayText %} @@ -13,7 +13,7 @@ {% endif %} {% endfunc %} -{% func hyphaInfo(rq *http.Request, h hyphae.Hypher) %} +{% func hyphaInfo(rq *http.Request, h hyphae.Hypha) %} {% code u := user.FromRequest(rq) lc := l18n.FromRequest(rq) diff --git a/views/nav.qtpl.go b/views/nav.qtpl.go index 1d2ae4e..822cc3e 100644 --- a/views/nav.qtpl.go +++ b/views/nav.qtpl.go @@ -36,7 +36,7 @@ var ( ) //line views/nav.qtpl:8 -func streamhyphaInfoEntry(qw422016 *qt422016.Writer, h hyphae.Hypher, u *user.User, action, displayText string) { +func streamhyphaInfoEntry(qw422016 *qt422016.Writer, h hyphae.Hypha, u *user.User, action, displayText string) { //line views/nav.qtpl:8 qw422016.N().S(` `) @@ -73,7 +73,7 @@ func streamhyphaInfoEntry(qw422016 *qt422016.Writer, h hyphae.Hypher, u *user.Us } //line views/nav.qtpl:14 -func writehyphaInfoEntry(qq422016 qtio422016.Writer, h hyphae.Hypher, u *user.User, action, displayText string) { +func writehyphaInfoEntry(qq422016 qtio422016.Writer, h hyphae.Hypha, u *user.User, action, displayText string) { //line views/nav.qtpl:14 qw422016 := qt422016.AcquireWriter(qq422016) //line views/nav.qtpl:14 @@ -84,7 +84,7 @@ func writehyphaInfoEntry(qq422016 qtio422016.Writer, h hyphae.Hypher, u *user.Us } //line views/nav.qtpl:14 -func hyphaInfoEntry(h hyphae.Hypher, u *user.User, action, displayText string) string { +func hyphaInfoEntry(h hyphae.Hypha, u *user.User, action, displayText string) string { //line views/nav.qtpl:14 qb422016 := qt422016.AcquireByteBuffer() //line views/nav.qtpl:14 @@ -99,7 +99,7 @@ func hyphaInfoEntry(h hyphae.Hypher, u *user.User, action, displayText string) s } //line views/nav.qtpl:16 -func streamhyphaInfo(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hypher) { +func streamhyphaInfo(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hypha) { //line views/nav.qtpl:16 qw422016.N().S(` `) @@ -149,7 +149,7 @@ func streamhyphaInfo(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hyphe } //line views/nav.qtpl:32 -func writehyphaInfo(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hypher) { +func writehyphaInfo(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hypha) { //line views/nav.qtpl:32 qw422016 := qt422016.AcquireWriter(qq422016) //line views/nav.qtpl:32 @@ -160,7 +160,7 @@ func writehyphaInfo(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hyphe } //line views/nav.qtpl:32 -func hyphaInfo(rq *http.Request, h hyphae.Hypher) string { +func hyphaInfo(rq *http.Request, h hyphae.Hypha) string { //line views/nav.qtpl:32 qb422016 := qt422016.AcquireByteBuffer() //line views/nav.qtpl:32 diff --git a/views/readers.qtpl b/views/readers.qtpl index e3a5beb..0ce2968 100644 --- a/views/readers.qtpl +++ b/views/readers.qtpl @@ -11,25 +11,26 @@ {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} -{% func AttachmentMenuHTML(rq *http.Request, h *hyphae.NonEmptyHypha, u *user.User) %} +{% func AttachmentMenuHTML(rq *http.Request, h hyphae.Hypha, u *user.User) %} {% code lc := l18n.FromRequest(rq) %}

    {%s= lc.Get("ui.attach_title", &l18n.Replacements{"name": beautifulLink(h.CanonicalName())}) %}

    - {% if h.BinaryPath() == "" %} -

    {%s lc.Get("ui.attach_empty") %} {%s lc.Get("ui.attach_link") %}

    - {% else %} -

    {%s lc.Get("ui.attach_tip") %} {%s lc.Get("ui.attach_link") %}

    - {% endif %} + {% switch h.(type) %} + {% case *hyphae.MediaHypha %} +

    {%s lc.Get("ui.attach_tip") %} {%s lc.Get("ui.attach_link") %}

    + {% default %} +

    {%s lc.Get("ui.attach_empty") %} {%s lc.Get("ui.attach_link") %}

    + {% endswitch %}
    - - {% if h.BinaryPath() != "" %} + {% switch h := h.(type) %} + {% case *hyphae.MediaHypha %} {% code - mime := mimetype.FromExtension(path.Ext(h.BinaryPath())) - fileinfo, err := os.Stat(h.BinaryPath()) %} + mime := mimetype.FromExtension(path.Ext(h.MediaFilePath())) + fileinfo, err := os.Stat(h.MediaFilePath()) %} {% if err == nil %}
    {%s lc.Get("ui.attach_stat") %} @@ -45,7 +46,7 @@
    img { {%s h.CanonicalName() %} }
    {% endif %} - {% endif %} + {% endswitch %} {% if u.CanProceed("upload-binary") %}
    {% endif %} - {% if h.BinaryPath() != "" && u.CanProceed("unattach-confirm") %} - - -
    - {% endif %} + + {% switch h := h.(type) %} + {% case *hyphae.MediaHypha %} + {% if u.CanProceed("unattach-confirm") %} + + {% endif %} + {% endswitch %}
    @@ -80,7 +85,7 @@ If `contents` == "", a helpful message is shown instead. If you rename .prevnext, change the docs too. -{% func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents string) %} +{% func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) %} {% code siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName()) u := user.FromRequest(rq) @@ -131,7 +136,7 @@ If you rename .prevnext, change the docs too. {%= viewScripts() %} {% endfunc %} -{% func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents, revHash string) %} +{% func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) %} {% code siblings, subhyphae, _, _ := tree.Tree(h.CanonicalName()) %} diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index 62e974f..fcc02ad 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -51,7 +51,7 @@ var ( ) //line views/readers.qtpl:14 -func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.NonEmptyHypha, u *user.User) { +func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hypha, u *user.User) { //line views/readers.qtpl:14 qw422016.N().S(` `) @@ -69,562 +69,578 @@ func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hy qw422016.N().S(` `) //line views/readers.qtpl:21 - if h.BinaryPath() == "" { -//line views/readers.qtpl:21 + switch h.(type) { +//line views/readers.qtpl:22 + case *hyphae.MediaHypha: +//line views/readers.qtpl:22 qw422016.N().S(` -

    `) -//line views/readers.qtpl:22 - qw422016.E().S(lc.Get("ui.attach_empty")) -//line views/readers.qtpl:22 - qw422016.N().S(` `) -//line views/readers.qtpl:22 - qw422016.E().S(lc.Get("ui.attach_link")) -//line views/readers.qtpl:22 - qw422016.N().S(`

    - `) +

    `) //line views/readers.qtpl:23 - } else { -//line views/readers.qtpl:23 - qw422016.N().S(` -

    `) -//line views/readers.qtpl:24 qw422016.E().S(lc.Get("ui.attach_tip")) -//line views/readers.qtpl:24 +//line views/readers.qtpl:23 qw422016.N().S(` `) -//line views/readers.qtpl:24 +//line views/readers.qtpl:23 qw422016.E().S(lc.Get("ui.attach_link")) -//line views/readers.qtpl:24 +//line views/readers.qtpl:23 qw422016.N().S(`

    `) +//line views/readers.qtpl:24 + default: +//line views/readers.qtpl:24 + qw422016.N().S(` +

    `) //line views/readers.qtpl:25 + qw422016.E().S(lc.Get("ui.attach_empty")) +//line views/readers.qtpl:25 + qw422016.N().S(` `) +//line views/readers.qtpl:25 + qw422016.E().S(lc.Get("ui.attach_link")) +//line views/readers.qtpl:25 + qw422016.N().S(`

    + `) +//line views/readers.qtpl:26 } -//line views/readers.qtpl:25 +//line views/readers.qtpl:26 qw422016.N().S(`
    - `) //line views/readers.qtpl:29 - if h.BinaryPath() != "" { -//line views/readers.qtpl:29 + switch h := h.(type) { +//line views/readers.qtpl:30 + case *hyphae.MediaHypha: +//line views/readers.qtpl:30 qw422016.N().S(` `) -//line views/readers.qtpl:31 - mime := mimetype.FromExtension(path.Ext(h.BinaryPath())) - fileinfo, err := os.Stat(h.BinaryPath()) - //line views/readers.qtpl:32 + mime := mimetype.FromExtension(path.Ext(h.MediaFilePath())) + fileinfo, err := os.Stat(h.MediaFilePath()) + +//line views/readers.qtpl:33 qw422016.N().S(` `) -//line views/readers.qtpl:33 +//line views/readers.qtpl:34 if err == nil { -//line views/readers.qtpl:33 +//line views/readers.qtpl:34 qw422016.N().S(`
    `) -//line views/readers.qtpl:35 +//line views/readers.qtpl:36 qw422016.E().S(lc.Get("ui.attach_stat")) -//line views/readers.qtpl:35 +//line views/readers.qtpl:36 qw422016.N().S(`

    `) -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 qw422016.E().S(lc.Get("ui.attach_stat_mime")) -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 qw422016.N().S(` `) -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 qw422016.E().S(mime) -//line views/readers.qtpl:37 +//line views/readers.qtpl:38 qw422016.N().S(`

    `) -//line views/readers.qtpl:39 +//line views/readers.qtpl:40 } -//line views/readers.qtpl:39 +//line views/readers.qtpl:40 qw422016.N().S(` `) -//line views/readers.qtpl:41 +//line views/readers.qtpl:42 if strings.HasPrefix(mime, "image/") { -//line views/readers.qtpl:41 +//line views/readers.qtpl:42 qw422016.N().S(`
    `) -//line views/readers.qtpl:43 +//line views/readers.qtpl:44 qw422016.E().S(lc.Get("ui.attach_include")) -//line views/readers.qtpl:43 +//line views/readers.qtpl:44 qw422016.N().S(`
    img { `)
    -//line views/readers.qtpl:45
    +//line views/readers.qtpl:46
     			qw422016.E().S(h.CanonicalName())
    -//line views/readers.qtpl:45
    +//line views/readers.qtpl:46
     			qw422016.N().S(` }
    `) -//line views/readers.qtpl:47 +//line views/readers.qtpl:48 } -//line views/readers.qtpl:47 +//line views/readers.qtpl:48 qw422016.N().S(` `) -//line views/readers.qtpl:48 +//line views/readers.qtpl:49 } -//line views/readers.qtpl:48 +//line views/readers.qtpl:49 qw422016.N().S(` `) -//line views/readers.qtpl:50 +//line views/readers.qtpl:51 if u.CanProceed("upload-binary") { -//line views/readers.qtpl:50 +//line views/readers.qtpl:51 qw422016.N().S(` `) -//line views/readers.qtpl:63 +//line views/readers.qtpl:64 } -//line views/readers.qtpl:63 +//line views/readers.qtpl:64 qw422016.N().S(` + `) -//line views/readers.qtpl:65 - if h.BinaryPath() != "" && u.CanProceed("unattach-confirm") { -//line views/readers.qtpl:65 +//line views/readers.qtpl:67 + switch h := h.(type) { +//line views/readers.qtpl:68 + case *hyphae.MediaHypha: +//line views/readers.qtpl:68 qw422016.N().S(` - + qw422016.N().S(`" method="post" class="modal amnt-menu-block"> + + + `) +//line views/readers.qtpl:77 + } +//line views/readers.qtpl:77 + qw422016.N().S(` `) -//line views/readers.qtpl:73 +//line views/readers.qtpl:78 } -//line views/readers.qtpl:73 +//line views/readers.qtpl:78 qw422016.N().S(`
    `) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 } -//line views/readers.qtpl:78 -func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.NonEmptyHypha, u *user.User) { -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 +func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hypha, u *user.User) { +//line views/readers.qtpl:83 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 StreamAttachmentMenuHTML(qw422016, rq, h, u) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 } -//line views/readers.qtpl:78 -func AttachmentMenuHTML(rq *http.Request, h *hyphae.NonEmptyHypha, u *user.User) string { -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 +func AttachmentMenuHTML(rq *http.Request, h hyphae.Hypha, u *user.User) string { +//line views/readers.qtpl:83 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 WriteAttachmentMenuHTML(qb422016, rq, h, u) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 qs422016 := string(qb422016.B) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 return qs422016 -//line views/readers.qtpl:78 +//line views/readers.qtpl:83 } // If `contents` == "", a helpful message is shown instead. // // If you rename .prevnext, change the docs too. -//line views/readers.qtpl:83 -func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents string) { -//line views/readers.qtpl:83 +//line views/readers.qtpl:88 +func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) { +//line views/readers.qtpl:88 qw422016.N().S(` `) -//line views/readers.qtpl:85 +//line views/readers.qtpl:90 siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName()) u := user.FromRequest(rq) -//line views/readers.qtpl:87 +//line views/readers.qtpl:92 qw422016.N().S(`
    `) -//line views/readers.qtpl:91 +//line views/readers.qtpl:96 if u.CanProceed("edit") { -//line views/readers.qtpl:91 +//line views/readers.qtpl:96 qw422016.N().S(` `) -//line views/readers.qtpl:95 +//line views/readers.qtpl:100 } -//line views/readers.qtpl:95 +//line views/readers.qtpl:100 qw422016.N().S(` `) -//line views/readers.qtpl:97 +//line views/readers.qtpl:102 if cfg.UseAuth && util.IsProfileName(h.CanonicalName()) && u.Name == strings.TrimPrefix(h.CanonicalName(), cfg.UserHypha+"/") { -//line views/readers.qtpl:97 +//line views/readers.qtpl:102 qw422016.N().S(` `) -//line views/readers.qtpl:101 +//line views/readers.qtpl:106 if u.Group == "admin" { -//line views/readers.qtpl:101 +//line views/readers.qtpl:106 qw422016.N().S(` `) -//line views/readers.qtpl:105 +//line views/readers.qtpl:110 } -//line views/readers.qtpl:105 +//line views/readers.qtpl:110 qw422016.N().S(` `) -//line views/readers.qtpl:106 +//line views/readers.qtpl:111 } -//line views/readers.qtpl:106 +//line views/readers.qtpl:111 qw422016.N().S(` `) -//line views/readers.qtpl:108 +//line views/readers.qtpl:113 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:108 +//line views/readers.qtpl:113 qw422016.N().S(` `) -//line views/readers.qtpl:109 +//line views/readers.qtpl:114 switch h.(type) { -//line views/readers.qtpl:110 +//line views/readers.qtpl:115 case *hyphae.EmptyHypha: -//line views/readers.qtpl:110 +//line views/readers.qtpl:115 qw422016.N().S(` `) -//line views/readers.qtpl:111 +//line views/readers.qtpl:116 streamnonExistentHyphaNotice(qw422016, h, u, lc) -//line views/readers.qtpl:111 +//line views/readers.qtpl:116 qw422016.N().S(` `) -//line views/readers.qtpl:112 +//line views/readers.qtpl:117 default: -//line views/readers.qtpl:112 +//line views/readers.qtpl:117 qw422016.N().S(` `) -//line views/readers.qtpl:113 +//line views/readers.qtpl:118 qw422016.N().S(contents) -//line views/readers.qtpl:113 +//line views/readers.qtpl:118 qw422016.N().S(` `) -//line views/readers.qtpl:114 +//line views/readers.qtpl:119 } -//line views/readers.qtpl:114 +//line views/readers.qtpl:119 qw422016.N().S(`
    `) -//line views/readers.qtpl:117 +//line views/readers.qtpl:122 if prevHyphaName != "" { -//line views/readers.qtpl:117 +//line views/readers.qtpl:122 qw422016.N().S(` `) -//line views/readers.qtpl:119 +//line views/readers.qtpl:124 } -//line views/readers.qtpl:119 +//line views/readers.qtpl:124 qw422016.N().S(` `) -//line views/readers.qtpl:120 +//line views/readers.qtpl:125 if nextHyphaName != "" { -//line views/readers.qtpl:120 +//line views/readers.qtpl:125 qw422016.N().S(` `) -//line views/readers.qtpl:122 +//line views/readers.qtpl:127 } -//line views/readers.qtpl:122 +//line views/readers.qtpl:127 qw422016.N().S(`
    `) -//line views/readers.qtpl:124 +//line views/readers.qtpl:129 StreamSubhyphaeHTML(qw422016, subhyphae, lc) -//line views/readers.qtpl:124 +//line views/readers.qtpl:129 qw422016.N().S(`
    `) -//line views/readers.qtpl:126 +//line views/readers.qtpl:131 streamhyphaInfo(qw422016, rq, h) -//line views/readers.qtpl:126 +//line views/readers.qtpl:131 qw422016.N().S(`
    `) -//line views/readers.qtpl:129 +//line views/readers.qtpl:134 streamsiblingHyphaeHTML(qw422016, siblings, lc) -//line views/readers.qtpl:129 +//line views/readers.qtpl:134 qw422016.N().S(`
    `) -//line views/readers.qtpl:131 - streamviewScripts(qw422016) -//line views/readers.qtpl:131 - qw422016.N().S(` -`) -//line views/readers.qtpl:132 -} - -//line views/readers.qtpl:132 -func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents string) { -//line views/readers.qtpl:132 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:132 - StreamHyphaHTML(qw422016, rq, lc, h, contents) -//line views/readers.qtpl:132 - qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:132 -} - -//line views/readers.qtpl:132 -func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents string) string { -//line views/readers.qtpl:132 - qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:132 - WriteHyphaHTML(qb422016, rq, lc, h, contents) -//line views/readers.qtpl:132 - qs422016 := string(qb422016.B) -//line views/readers.qtpl:132 - qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:132 - return qs422016 -//line views/readers.qtpl:132 -} - -//line views/readers.qtpl:134 -func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents, revHash string) { -//line views/readers.qtpl:134 - qw422016.N().S(` -`) //line views/readers.qtpl:136 - siblings, subhyphae, _, _ := tree.Tree(h.CanonicalName()) + streamviewScripts(qw422016) +//line views/readers.qtpl:136 + qw422016.N().S(` +`) +//line views/readers.qtpl:137 +} //line views/readers.qtpl:137 +func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) { +//line views/readers.qtpl:137 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/readers.qtpl:137 + StreamHyphaHTML(qw422016, rq, lc, h, contents) +//line views/readers.qtpl:137 + qt422016.ReleaseWriter(qw422016) +//line views/readers.qtpl:137 +} + +//line views/readers.qtpl:137 +func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) string { +//line views/readers.qtpl:137 + qb422016 := qt422016.AcquireByteBuffer() +//line views/readers.qtpl:137 + WriteHyphaHTML(qb422016, rq, lc, h, contents) +//line views/readers.qtpl:137 + qs422016 := string(qb422016.B) +//line views/readers.qtpl:137 + qt422016.ReleaseByteBuffer(qb422016) +//line views/readers.qtpl:137 + return qs422016 +//line views/readers.qtpl:137 +} + +//line views/readers.qtpl:139 +func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) { +//line views/readers.qtpl:139 + qw422016.N().S(` +`) +//line views/readers.qtpl:141 + siblings, subhyphae, _, _ := tree.Tree(h.CanonicalName()) + +//line views/readers.qtpl:142 qw422016.N().S(`

    `) -//line views/readers.qtpl:141 +//line views/readers.qtpl:146 qw422016.E().S(lc.Get("ui.revision_warning")) -//line views/readers.qtpl:141 +//line views/readers.qtpl:146 qw422016.N().S(` `) -//line views/readers.qtpl:141 +//line views/readers.qtpl:146 qw422016.E().S(lc.Get("ui.revision_link")) -//line views/readers.qtpl:141 +//line views/readers.qtpl:146 qw422016.N().S(`

    `) -//line views/readers.qtpl:142 +//line views/readers.qtpl:147 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:142 +//line views/readers.qtpl:147 qw422016.N().S(` `) -//line views/readers.qtpl:143 +//line views/readers.qtpl:148 qw422016.N().S(contents) -//line views/readers.qtpl:143 +//line views/readers.qtpl:148 qw422016.N().S(`
    `) -//line views/readers.qtpl:145 +//line views/readers.qtpl:150 StreamSubhyphaeHTML(qw422016, subhyphae, lc) -//line views/readers.qtpl:145 +//line views/readers.qtpl:150 qw422016.N().S(`
    `) -//line views/readers.qtpl:147 +//line views/readers.qtpl:152 streamsiblingHyphaeHTML(qw422016, siblings, lc) -//line views/readers.qtpl:147 +//line views/readers.qtpl:152 qw422016.N().S(`
    `) -//line views/readers.qtpl:149 +//line views/readers.qtpl:154 streamviewScripts(qw422016) -//line views/readers.qtpl:149 +//line views/readers.qtpl:154 qw422016.N().S(` `) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 } -//line views/readers.qtpl:150 -func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents, revHash string) { -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 +func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) { +//line views/readers.qtpl:155 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 StreamRevisionHTML(qw422016, rq, lc, h, contents, revHash) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 } -//line views/readers.qtpl:150 -func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypher, contents, revHash string) string { -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 +func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) string { +//line views/readers.qtpl:155 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 WriteRevisionHTML(qb422016, rq, lc, h, contents, revHash) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 qs422016 := string(qb422016.B) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 return qs422016 -//line views/readers.qtpl:150 +//line views/readers.qtpl:155 } -//line views/readers.qtpl:152 +//line views/readers.qtpl:157 func streamviewScripts(qw422016 *qt422016.Writer) { -//line views/readers.qtpl:152 +//line views/readers.qtpl:157 qw422016.N().S(` `) -//line views/readers.qtpl:153 +//line views/readers.qtpl:158 for _, scriptPath := range cfg.ViewScripts { -//line views/readers.qtpl:153 +//line views/readers.qtpl:158 qw422016.N().S(` `) -//line views/readers.qtpl:155 +//line views/readers.qtpl:160 } -//line views/readers.qtpl:155 +//line views/readers.qtpl:160 qw422016.N().S(` `) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 } -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 func writeviewScripts(qq422016 qtio422016.Writer) { -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 streamviewScripts(qw422016) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 } -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 func viewScripts() string { -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 writeviewScripts(qb422016) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 qs422016 := string(qb422016.B) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 return qs422016 -//line views/readers.qtpl:156 +//line views/readers.qtpl:161 } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 9547ef2..2587f4e 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -262,16 +262,17 @@ sort.Strings(editors) close(hyphaNames) %} {% for hyphaName := range sortedHypha %} - {% code hypha := hyphae.ByName(hyphaName).(*hyphae.NonEmptyHypha) %} + {% code h := hyphae.ByName(hyphaName) %}
  • - - {%s util.BeautifulName(hypha.CanonicalName()) %} + + {%s util.BeautifulName(h.CanonicalName()) %} - {% if hypha.Kind() == hyphae.HyphaMedia %} - - {%s filepath.Ext(hypha.BinaryPath())[1:] %} - - {% endif %} + {% switch h := h.(type) %} + {% case *hyphae.MediaHypha %} + + {%s filepath.Ext(h.MediaFilePath())[1:] %} + + {% endswitch %}
  • {% endfor %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 25d21c6..c3e9175 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -1020,247 +1020,249 @@ func StreamHyphaListHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { qw422016.N().S(` `) //line views/stuff.qtpl:265 - hypha := hyphae.ByName(hyphaName).(*hyphae.NonEmptyHypha) + h := hyphae.ByName(hyphaName) //line views/stuff.qtpl:265 qw422016.N().S(`
  • `) //line views/stuff.qtpl:268 - qw422016.E().S(util.BeautifulName(hypha.CanonicalName())) + qw422016.E().S(util.BeautifulName(h.CanonicalName())) //line views/stuff.qtpl:268 qw422016.N().S(` `) //line views/stuff.qtpl:270 - if hypha.Kind() == hyphae.HyphaMedia { -//line views/stuff.qtpl:270 + switch h := h.(type) { +//line views/stuff.qtpl:271 + case *hyphae.MediaHypha: +//line views/stuff.qtpl:271 qw422016.N().S(` - - `) -//line views/stuff.qtpl:272 - qw422016.E().S(filepath.Ext(hypha.BinaryPath())[1:]) -//line views/stuff.qtpl:272 + + `) +//line views/stuff.qtpl:273 + qw422016.E().S(filepath.Ext(h.MediaFilePath())[1:]) +//line views/stuff.qtpl:273 qw422016.N().S(` - + `) -//line views/stuff.qtpl:274 +//line views/stuff.qtpl:275 } -//line views/stuff.qtpl:274 +//line views/stuff.qtpl:275 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:276 +//line views/stuff.qtpl:277 } -//line views/stuff.qtpl:276 +//line views/stuff.qtpl:277 qw422016.N().S(`
    `) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 } -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 func WriteHyphaListHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 StreamHyphaListHTML(qw422016, lc) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 } -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 func HyphaListHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 WriteHyphaListHTML(qb422016, lc) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 return qs422016 -//line views/stuff.qtpl:280 +//line views/stuff.qtpl:281 } -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 func StreamAboutHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:282 +//line views/stuff.qtpl:283 qw422016.N().S(`

    `) -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 qw422016.E().S(lc.Get("ui.about_title", &l18n.Replacements{"name": cfg.WikiName})) -//line views/stuff.qtpl:286 +//line views/stuff.qtpl:287 qw422016.N().S(`

    • `) -//line views/stuff.qtpl:288 +//line views/stuff.qtpl:289 qw422016.N().S(lc.Get("ui.about_version", &l18n.Replacements{"pre": "", "post": ""})) -//line views/stuff.qtpl:288 +//line views/stuff.qtpl:289 qw422016.N().S(` 1.8.0
    • `) -//line views/stuff.qtpl:289 +//line views/stuff.qtpl:290 if cfg.UseAuth { -//line views/stuff.qtpl:289 +//line views/stuff.qtpl:290 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:290 +//line views/stuff.qtpl:291 qw422016.E().S(lc.Get("ui.about_usercount")) -//line views/stuff.qtpl:290 +//line views/stuff.qtpl:291 qw422016.N().S(` `) -//line views/stuff.qtpl:290 +//line views/stuff.qtpl:291 qw422016.N().DUL(user.Count()) -//line views/stuff.qtpl:290 +//line views/stuff.qtpl:291 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.E().S(lc.Get("ui.about_homepage")) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.N().S(` `) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.E().S(cfg.HomeHypha) -//line views/stuff.qtpl:291 +//line views/stuff.qtpl:292 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:292 +//line views/stuff.qtpl:293 qw422016.E().S(lc.Get("ui.about_admins")) -//line views/stuff.qtpl:292 +//line views/stuff.qtpl:293 qw422016.N().S(``) -//line views/stuff.qtpl:292 +//line views/stuff.qtpl:293 for i, username := range user.ListUsersWithGroup("admin") { -//line views/stuff.qtpl:293 +//line views/stuff.qtpl:294 if i > 0 { -//line views/stuff.qtpl:293 +//line views/stuff.qtpl:294 qw422016.N().S(` `) -//line views/stuff.qtpl:294 +//line views/stuff.qtpl:295 } -//line views/stuff.qtpl:294 +//line views/stuff.qtpl:295 qw422016.N().S(` `) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qw422016.E().S(username) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qw422016.N().S(``) -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 } -//line views/stuff.qtpl:295 +//line views/stuff.qtpl:296 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:296 +//line views/stuff.qtpl:297 } else { -//line views/stuff.qtpl:296 +//line views/stuff.qtpl:297 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:297 +//line views/stuff.qtpl:298 qw422016.E().S(lc.Get("ui.about_noauth")) -//line views/stuff.qtpl:297 +//line views/stuff.qtpl:298 qw422016.N().S(`
    • `) -//line views/stuff.qtpl:298 +//line views/stuff.qtpl:299 } -//line views/stuff.qtpl:298 +//line views/stuff.qtpl:299 qw422016.N().S(`

    `) -//line views/stuff.qtpl:300 +//line views/stuff.qtpl:301 qw422016.N().S(lc.Get("ui.about_hyphae", &l18n.Replacements{"link": "/list"})) -//line views/stuff.qtpl:300 +//line views/stuff.qtpl:301 qw422016.N().S(`

    `) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 } -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 func WriteAboutHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 StreamAboutHTML(qw422016, lc) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 } -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 func AboutHTML(lc *l18n.Localizer) string { -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 WriteAboutHTML(qb422016, lc) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 return qs422016 -//line views/stuff.qtpl:304 +//line views/stuff.qtpl:305 } -//line views/stuff.qtpl:306 +//line views/stuff.qtpl:307 func StreamCommonScripts(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:306 +//line views/stuff.qtpl:307 qw422016.N().S(` `) -//line views/stuff.qtpl:307 +//line views/stuff.qtpl:308 for _, scriptPath := range cfg.CommonScripts { -//line views/stuff.qtpl:307 +//line views/stuff.qtpl:308 qw422016.N().S(` `) -//line views/stuff.qtpl:309 +//line views/stuff.qtpl:310 } -//line views/stuff.qtpl:309 +//line views/stuff.qtpl:310 qw422016.N().S(` `) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 } -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 func WriteCommonScripts(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 StreamCommonScripts(qw422016) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 } -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 func CommonScripts() string { -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 WriteCommonScripts(qb422016) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 return qs422016 -//line views/stuff.qtpl:310 +//line views/stuff.qtpl:311 } diff --git a/web/mutators.go b/web/mutators.go index 7ff71b1..69caaed 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -37,7 +37,7 @@ func initMutators(r *mux.Router) { func factoryHandlerAsker( actionPath string, - asker func(*user.User, hyphae.Hypher, *l18n.Localizer) (string, error), + asker func(*user.User, hyphae.Hypha, *l18n.Localizer) (string, error), succTitleKey string, succPageTemplate func(*http.Request, string, bool) string, ) func(http.ResponseWriter, *http.Request) { @@ -63,7 +63,7 @@ func factoryHandlerAsker( w, views.BaseHTML( fmt.Sprintf(lc.Get(succTitleKey), util.BeautifulName(hyphaName)), - succPageTemplate(rq, hyphaName, func(h hyphae.Hypher) bool { + succPageTemplate(rq, hyphaName, func(h hyphae.Hypha) bool { switch h.(type) { case *hyphae.EmptyHypha: return false @@ -99,7 +99,7 @@ var handlerRenameAsk = factoryHandlerAsker( func factoryHandlerConfirmer( actionPath string, - confirmer func(hyphae.Hypher, *user.User, *http.Request) (*history.Op, string), + confirmer func(hyphae.Hypha, *user.User, *http.Request) (*history.Op, string), ) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) @@ -121,14 +121,14 @@ func factoryHandlerConfirmer( var handlerUnattachConfirm = factoryHandlerConfirmer( "unattach-confirm", - func(h hyphae.Hypher, u *user.User, rq *http.Request) (*history.Op, string) { + func(h hyphae.Hypha, u *user.User, rq *http.Request) (*history.Op, string) { return shroom.UnattachHypha(u, h, l18n.FromRequest(rq)) }, ) var handlerDeleteConfirm = factoryHandlerConfirmer( "delete-confirm", - func(h hyphae.Hypher, u *user.User, rq *http.Request) (*history.Op, string) { + func(h hyphae.Hypha, u *user.User, rq *http.Request) (*history.Op, string) { return shroom.DeleteHypha(u, h, l18n.FromRequest(rq)) }, ) @@ -177,7 +177,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { case *hyphae.EmptyHypha: warning = fmt.Sprintf(`

    %s

    `, lc.Get("edit.new_hypha")) default: - textAreaFill, err = shroom.FetchTextPart(h) + textAreaFill, err = shroom.FetchTextFile(h) if err != nil { log.Println(err) httpErr(w, lc, http.StatusInternalServerError, hyphaName, diff --git a/web/readers.go b/web/readers.go index 217df39..c860321 100644 --- a/web/readers.go +++ b/web/readers.go @@ -47,7 +47,7 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) { util.HTTP200Page(w, views.BaseHTML( lc.Get("ui.attach_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}), - views.AttachmentMenuHTML(rq, h.(*hyphae.NonEmptyHypha), u), + views.AttachmentMenuHTML(rq, h, u), lc, u)) } @@ -63,12 +63,18 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) lc = l18n.FromRequest(rq) ) - util.HTTP200Page(w, - views.BaseHTML( - lc.Get("ui.diff_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}), - views.PrimitiveDiffHTML(rq, h, u, revHash), - lc, - u)) + switch h := h.(type) { + case *hyphae.EmptyHypha: + w.WriteHeader(http.StatusNotFound) + _, _ = io.WriteString(w, "404 not found") + case hyphae.ExistingHypha: + util.HTTP200Page(w, + views.BaseHTML( + lc.Get("ui.diff_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}), + views.PrimitiveDiffHTML(rq, h, u, revHash), + lc, + u)) + } } // handlerRevisionText sends Mycomarkup text of the hypha at the given revision. See also: handlerRevision, handlerText. @@ -77,42 +83,57 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) { func handlerRevisionText(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( - shorterURL = strings.TrimPrefix(rq.URL.Path, "/rev-text/") - firstSlashIndex = strings.IndexRune(shorterURL, '/') - revHash = shorterURL[:firstSlashIndex] - hyphaName = util.CanonicalName(shorterURL[firstSlashIndex+1:]) - h = hyphae.ByName(hyphaName) - textContents, err = history.FileAtRevision(h.TextPartPath(), revHash) + shorterURL = strings.TrimPrefix(rq.URL.Path, "/rev-text/") + firstSlashIndex = strings.IndexRune(shorterURL, '/') + revHash = shorterURL[:firstSlashIndex] + hyphaName = util.CanonicalName(shorterURL[firstSlashIndex+1:]) + h = hyphae.ByName(hyphaName) ) w.Header().Set("Content-Type", "text/plain; charset=utf-8") - if err != nil { + switch h := h.(type) { + case *hyphae.EmptyHypha: + log.Printf(`Hypha ‘%s’ does not exist`) w.WriteHeader(http.StatusNotFound) - log.Printf("While serving text of ‘%s’ at revision ‘%s’: %s\n", hyphaName, revHash, err.Error()) - _, _ = io.WriteString(w, "Error: "+err.Error()) - return + case hyphae.ExistingHypha: + if !h.HasTextFile() { + log.Printf(`Media hypha ‘%s’ has no text`) + w.WriteHeader(http.StatusNotFound) + } + var textContents, err = history.FileAtRevision(h.TextFilePath(), revHash) + + if err != nil { + w.WriteHeader(http.StatusNotFound) + log.Printf("While serving text of ‘%s’ at revision ‘%s’: %s\n", hyphaName, revHash, err.Error()) + _, _ = io.WriteString(w, "Error: "+err.Error()) + return + } + log.Printf("Serving text of ‘%s’ from ‘%s’ at revision ‘%s’\n", hyphaName, h.TextFilePath(), revHash) + w.WriteHeader(http.StatusOK) + _, _ = io.WriteString(w, textContents) } - log.Printf("Serving text of ‘%s’ from ‘%s’ at revision ‘%s’\n", hyphaName, h.TextPartPath(), revHash) - w.WriteHeader(http.StatusOK) - _, _ = io.WriteString(w, textContents) } // handlerRevision displays a specific revision of the text part the hypha func handlerRevision(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( - lc = l18n.FromRequest(rq) - shorterURL = strings.TrimPrefix(rq.URL.Path, "/rev/") - firstSlashIndex = strings.IndexRune(shorterURL, '/') - revHash = shorterURL[:firstSlashIndex] - hyphaName = util.CanonicalName(shorterURL[firstSlashIndex+1:]) - h = hyphae.ByName(hyphaName) - contents = fmt.Sprintf(`

    %s

    `, lc.Get("ui.revision_no_text")) - textContents, err = history.FileAtRevision(h.TextPartPath(), revHash) - u = user.FromRequest(rq) + lc = l18n.FromRequest(rq) + shorterURL = strings.TrimPrefix(rq.URL.Path, "/rev/") + firstSlashIndex = strings.IndexRune(shorterURL, '/') + revHash = shorterURL[:firstSlashIndex] + hyphaName = util.CanonicalName(shorterURL[firstSlashIndex+1:]) + h = hyphae.ByName(hyphaName) + contents = fmt.Sprintf(`

    %s

    `, lc.Get("ui.revision_no_text")) + u = user.FromRequest(rq) ) - if err == nil { - ctx, _ := mycocontext.ContextFromStringInput(hyphaName, textContents) - contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)) + switch h := h.(type) { + case *hyphae.TextualHypha: + var textContents, err = history.FileAtRevision(h.TextFilePath(), revHash) + + if err == nil { + ctx, _ := mycocontext.ContextFromStringInput(hyphaName, textContents) + contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)) + } } page := views.RevisionHTML( rq, @@ -139,13 +160,10 @@ func handlerText(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) hyphaName := util.HyphaNameFromRq(rq, "text") switch h := hyphae.ByName(hyphaName).(type) { - case *hyphae.EmptyHypha: - case *hyphae.NonEmptyHypha: - if h.Kind() == hyphae.HyphaText { - log.Println("Serving", h.TextPartPath()) - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - http.ServeFile(w, rq, h.TextPartPath()) - } + case *hyphae.TextualHypha: + log.Println("Serving", h.TextFilePath()) + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + http.ServeFile(w, rq, h.TextFilePath()) } } @@ -155,16 +173,13 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) { hyphaName := util.HyphaNameFromRq(rq, "binary") switch h := hyphae.ByName(hyphaName).(type) { case *hyphae.EmptyHypha: - default: // TODO: deindent - switch h := h.(*hyphae.NonEmptyHypha); h.Kind() { - case hyphae.HyphaText: - w.WriteHeader(http.StatusNotFound) - log.Printf("Textual hypha ‘%s’ has no media, cannot serve\n", h.CanonicalName()) - default: - log.Println("Serving", h.BinaryPath()) - w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.BinaryPath()))) - http.ServeFile(w, rq, h.BinaryPath()) - } + case *hyphae.TextualHypha: + w.WriteHeader(http.StatusNotFound) + log.Printf("Textual hypha ‘%s’ has no media, cannot serve\n", h.CanonicalName()) + case *hyphae.MediaHypha: + log.Println("Serving", h.MediaFilePath()) + w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath()))) + http.ServeFile(w, rq, h.MediaFilePath()) } } @@ -189,8 +204,8 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { lc, u, openGraph)) - case *hyphae.NonEmptyHypha: - fileContentsT, errT := os.ReadFile(h.TextPartPath()) + case hyphae.ExistingHypha: + fileContentsT, errT := os.ReadFile(h.TextFilePath()) if errT == nil { ctx, _ := mycocontext.ContextFromStringInput(hyphaName, string(fileContentsT)) ctx = mycocontext.WithWebSiteURL(ctx, cfg.URL) @@ -199,7 +214,8 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { contents = mycomarkup.BlocksToHTML(ctx, ast) openGraph = getOpenGraph() } - if h.Kind() == hyphae.HyphaMedia { + switch h := h.(type) { + case *hyphae.MediaHypha: contents = views.AttachmentHTML(h, lc) + contents }