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 %}
{% endif %}
- {% endif %}
+ {% endswitch %}
{% if u.CanProceed("upload-binary") %}
- {% 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: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: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: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: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
}