diff --git a/hyphae/empty_hypha.go b/hyphae/empty_hypha.go
index d205187..a80e148 100644
--- a/hyphae/empty_hypha.go
+++ b/hyphae/empty_hypha.go
@@ -2,6 +2,7 @@ package hyphae
import "sync"
+// EmptyHypha is a hypha that does not exist and is not stored anywhere. You get one when querying for a hypha that was not created before.
type EmptyHypha struct {
sync.RWMutex
@@ -12,6 +13,7 @@ func (e *EmptyHypha) CanonicalName() string {
return e.canonicalName
}
+// ExtendEmptyToTextual returns a new textual hypha with the same name as the given empty hypha. The created hypha is not stored yet.
func ExtendEmptyToTextual(e *EmptyHypha, mycoFilePath string) *TextualHypha {
return &TextualHypha{
canonicalName: e.CanonicalName(),
@@ -19,6 +21,7 @@ func ExtendEmptyToTextual(e *EmptyHypha, mycoFilePath string) *TextualHypha {
}
}
+// ExtendEmptyToMedia returns a new media hypha with the same name as the given empty hypha. The created hypha is not stored yet.
func ExtendEmptyToMedia(e *EmptyHypha, mediaFilePath string) *MediaHypha {
return &MediaHypha{
canonicalName: e.CanonicalName(),
diff --git a/hyphae/existing_hypha.go b/hyphae/existing_hypha.go
index 9fa9491..d75523a 100644
--- a/hyphae/existing_hypha.go
+++ b/hyphae/existing_hypha.go
@@ -4,20 +4,17 @@ import (
"github.com/bouncepaw/mycorrhiza/util"
)
-// ExistingHypha is not EmptyHypha.
+// ExistingHypha is not EmptyHypha. *MediaHypha and *TextualHypha implement this interface.
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.
+ // TODO: that replaceName is suspicious, get rid of it.
newName = util.CanonicalName(newName)
byNamesMutex.Lock()
h.Lock()
@@ -37,3 +34,28 @@ func RenameHyphaTo(h ExistingHypha, newName string, replaceName func(string) str
byNamesMutex.Unlock()
h.Unlock()
}
+
+// DeleteHypha deletes the hypha from the storage.
+func DeleteHypha(h ExistingHypha) {
+ byNamesMutex.Lock()
+ h.Lock()
+ delete(byNames, h.CanonicalName())
+ decrementCount()
+ 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. You cannot insert an empty hypha.
+func Insert(h ExistingHypha) (madeNewRecord bool) {
+ _, recorded := byNames[h.CanonicalName()]
+
+ byNamesMutex.Lock()
+ byNames[h.CanonicalName()] = h
+ byNamesMutex.Unlock()
+
+ if !recorded {
+ incrementCount()
+ }
+
+ return !recorded
+}
diff --git a/hyphae/hypha.go b/hyphae/hypha.go
index 8dbc0ad..c4c185c 100644
--- a/hyphae/hypha.go
+++ b/hyphae/hypha.go
@@ -6,12 +6,12 @@ import (
"sync"
)
-// HyphaPattern is a pattern which all hyphae names must match.
-var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}]+`)
+// hyphaNamePattern is a pattern which all hyphae names must match.
+var hyphaNamePattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}]+`)
// IsValidName checks for invalid characters and path traversals.
func IsValidName(hyphaName string) bool {
- if !HyphaPattern.MatchString(hyphaName) {
+ if !hyphaNamePattern.MatchString(hyphaName) {
return false
}
for _, segment := range strings.Split(hyphaName, "/") {
@@ -22,38 +22,16 @@ func IsValidName(hyphaName string) bool {
return true
}
-// Hypha is a hypha you know and love.
+// Hypha is the hypha you know and love.
type Hypha interface {
sync.Locker
+ // CanonicalName returns the canonical name of the hypha.
+ //
+ // util.CanonicalName(h.CanonicalName()) == h.CanonicalName()
CanonicalName() string
}
-// DeleteHypha deletes the hypha from the storage.
-func DeleteHypha(h ExistingHypha) {
- byNamesMutex.Lock()
- h.Lock()
- delete(byNames, h.CanonicalName())
- decrementCount()
- 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. You cannot insert an empty hypha.
-func Insert(h ExistingHypha) (madeNewRecord bool) {
- _, recorded := byNames[h.CanonicalName()]
-
- byNamesMutex.Lock()
- byNames[h.CanonicalName()] = h
- byNamesMutex.Unlock()
-
- if !recorded {
- incrementCount()
- }
-
- return !recorded
-}
-
// 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 Hypha) {
byNamesMutex.Lock()
diff --git a/hyphae/media_hypha.go b/hyphae/media_hypha.go
index e3d48a6..60e3505 100644
--- a/hyphae/media_hypha.go
+++ b/hyphae/media_hypha.go
@@ -14,9 +14,6 @@ type MediaHypha struct {
mediaFilePath string
}
-func (m *MediaHypha) DoesExist() {
-}
-
func (m *MediaHypha) CanonicalName() string {
return m.canonicalName
}
diff --git a/hyphae/textual_hypha.go b/hyphae/textual_hypha.go
index 51af499..aa286be 100644
--- a/hyphae/textual_hypha.go
+++ b/hyphae/textual_hypha.go
@@ -4,6 +4,7 @@ import (
"sync"
)
+// TextualHypha is a hypha with text, and nothing else. An article, a note, a poem, whatnot.
type TextualHypha struct {
sync.RWMutex
@@ -11,9 +12,6 @@ type TextualHypha struct {
mycoFilePath string
}
-func (t *TextualHypha) DoesExist() {
-}
-
func (t *TextualHypha) CanonicalName() string {
return t.canonicalName
}
@@ -26,6 +24,7 @@ func (t *TextualHypha) TextFilePath() string {
return t.mycoFilePath
}
+// ExtendTextualToMedia returns a new media hypha with the same name and text file as the given textual hypha. The new hypha is not stored yet.
func ExtendTextualToMedia(t *TextualHypha, mediaFilePath string) *MediaHypha {
return &MediaHypha{
canonicalName: t.CanonicalName(),
diff --git a/shroom/can.go b/shroom/can.go
index b790ce0..316112d 100644
--- a/shroom/can.go
+++ b/shroom/can.go
@@ -17,29 +17,29 @@ func canFactory(
noRightsMsg string,
notExistsMsg string,
mustExist bool,
-) func(*user.User, hyphae.Hypha, *l18n.Localizer) (string, error) {
- return func(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (string, error) {
+) func(*user.User, hyphae.Hypha, *l18n.Localizer) error {
+ return func(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) error {
if !u.CanProceed(action) {
rejectLogger(h, u, "no rights")
- return lc.Get("ui.act_no_rights"), errors.New(lc.Get(noRightsMsg))
+ return errors.New(noRightsMsg)
}
if mustExist {
switch h.(type) {
case *hyphae.EmptyHypha:
rejectLogger(h, u, "does not exist")
- return lc.Get("ui.act_notexist"), errors.New(lc.Get(notExistsMsg))
+ return errors.New(notExistsMsg)
}
}
if dispatcher == nil {
- return "", nil
+ return nil
}
errmsg, errtitle := dispatcher(h, u, lc)
if errtitle == "" {
- return "", nil
+ return nil
}
- return errtitle, errors.New(errmsg)
+ return errors.New(errmsg)
}
}
@@ -54,22 +54,12 @@ var (
true,
)
- CanRename = canFactory(
- rejectRenameLog,
- "rename-confirm",
- nil,
- "ui.act_norights_rename",
- "ui.act_notexist_rename",
- true,
- )
-
CanUnattach = canFactory(
rejectUnattachLog,
"unattach-confirm",
func(h hyphae.Hypha, u *user.User, lc *l18n.Localizer) (errmsg, errtitle string) {
switch h := h.(type) {
- case *hyphae.EmptyHypha:
- case *hyphae.TextualHypha:
+ case *hyphae.EmptyHypha, *hyphae.TextualHypha:
rejectUnattachLog(h, u, "no amnt")
return lc.Get("ui.act_noattachment_tip"), lc.Get("ui.act_noattachment")
}
diff --git a/shroom/delete.go b/shroom/delete.go
index 90fa332..6e1224a 100644
--- a/shroom/delete.go
+++ b/shroom/delete.go
@@ -11,17 +11,16 @@ import (
)
// DeleteHypha deletes hypha and makes a history record about that.
-func DeleteHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *history.Op, errtitle string) {
- hop = history.
+func DeleteHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) error {
+ if err := CanDelete(u, h, lc); err != nil {
+ return err
+ }
+
+ 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
- }
-
switch h := h.(type) {
case *hyphae.MediaHypha:
hop.WithFilesRemoved(h.MediaFilePath(), h.TextFilePath())
@@ -36,5 +35,5 @@ func DeleteHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *history
backlinks.UpdateBacklinksAfterDelete(h, originalText)
hyphae.DeleteHypha(h.(hyphae.ExistingHypha)) // we panicked before, so it's safe
}
- return hop, ""
+ return nil
}
diff --git a/shroom/rename.go b/shroom/rename.go
index 3a5a60b..e59bb5a 100644
--- a/shroom/rename.go
+++ b/shroom/rename.go
@@ -8,76 +8,68 @@ import (
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hyphae"
- "github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
)
-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:
- rejectRenameLog(oh, u, fmt.Sprintf("name ‘%s’ taken already", nh.CanonicalName()))
- return lc.Get("ui.rename_taken"), fmt.Errorf(lc.Get("ui.rename_taken_tip", &l18n.Replacements{"name": "%[1]s"}), nh.CanonicalName())
+// Rename renames the old hypha to the new name. Call if and only if the user has the permission to rename.
+func Rename(oldHypha hyphae.ExistingHypha, newName string, recursive bool, u *user.User) error {
+ if newName == "" {
+ rejectRenameLog(oldHypha, u, "no new name given")
+ return errors.New("ui.rename_noname_tip")
}
- if nh.CanonicalName() == "" {
- rejectRenameLog(oh, u, "no new name given")
- return lc.Get("ui.rename_noname"), errors.New(lc.Get("ui.rename_noname_tip"))
+ if !hyphae.IsValidName(newName) {
+ rejectRenameLog(oldHypha, u, fmt.Sprintf("new name ‘%s’ invalid", newName))
+ return errors.New("ui.rename_badname_tip") // FIXME: There is a bug related to this.
}
- if !hyphae.IsValidName(nh.CanonicalName()) {
- rejectRenameLog(oh, u, fmt.Sprintf("new name ‘%s’ invalid", nh.CanonicalName()))
- return lc.Get("ui.rename_badname"), errors.New(lc.Get("ui.rename_badname_tip", &l18n.Replacements{"chars": "^?!:#@><*|\"\\'&%"}))
- }
-
- return "", nil
-}
-
-// 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.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)
-
- if errtitle, err := CanRename(u, h, lc); errtitle != "" {
- hop.WithErrAbort(err)
- return hop, errtitle
- }
- if errtitle, err := canRenameThisToThat(h, newHypha, u, lc); errtitle != "" {
- hop.WithErrAbort(err)
- return hop, errtitle
+ switch targetHypha := hyphae.ByName(newName); targetHypha.(type) {
+ case hyphae.ExistingHypha:
+ rejectRenameLog(oldHypha, u, fmt.Sprintf("name ‘%s’ taken already", newName))
+ return errors.New("ui.rename_taken_tip") // FIXME: There is a bug related to this.
}
var (
- re = regexp.MustCompile(`(?i)` + h.CanonicalName())
+ re = regexp.MustCompile(`(?i)` + oldHypha.CanonicalName())
replaceName = func(str string) string {
- return re.ReplaceAllString(util.CanonicalName(str), newHypha.CanonicalName())
+ return re.ReplaceAllString(util.CanonicalName(str), newName)
}
- hyphaeToRename = findHyphaeToRename(h.(hyphae.ExistingHypha), recursive)
+ hyphaeToRename = findHyphaeToRename(oldHypha, recursive)
renameMap, err = renamingPairs(hyphaeToRename, replaceName)
- renameMsg = "Rename ‘%s’ to ‘%s’"
)
+
if err != nil {
- hop.Errs = append(hop.Errs, err)
- return hop, hop.FirstErrorText()
+ return err
}
- if recursive && len(hyphaeToRename) > 0 {
- renameMsg += " recursively"
+
+ hop := history.Operation(history.TypeRenameHypha).WithUser(u)
+
+ if len(hyphaeToRename) > 0 {
+ hop.WithMsg(fmt.Sprintf(
+ "Rename ‘%s’ to ‘%s’ recursively",
+ oldHypha.CanonicalName(),
+ newName))
+ } else {
+ hop.WithMsg(fmt.Sprintf(
+ "Rename ‘%s’ to ‘%s’",
+ oldHypha.CanonicalName(),
+ newName))
}
- hop.WithFilesRenamed(renameMap).
- WithMsg(fmt.Sprintf(renameMsg, h.CanonicalName(), newHypha.CanonicalName())).
- WithUser(u).
- Apply()
- if len(hop.Errs) == 0 {
- for _, H := range hyphaeToRename {
- h := H.(hyphae.ExistingHypha) // ontology think
- oldName := h.CanonicalName()
- hyphae.RenameHyphaTo(h, replaceName(h.CanonicalName()), replaceName)
- backlinks.UpdateBacklinksAfterRename(h, oldName)
- }
+
+ hop.WithFilesRenamed(renameMap).Apply()
+
+ if len(hop.Errs) != 0 {
+ return hop.Errs[0]
}
- return hop, ""
+
+ for _, h := range hyphaeToRename {
+ oldName := h.CanonicalName()
+ hyphae.RenameHyphaTo(h, replaceName(h.CanonicalName()), replaceName)
+ backlinks.UpdateBacklinksAfterRename(h, oldName)
+ }
+
+ return nil
}
func findHyphaeToRename(superhypha hyphae.ExistingHypha, recursive bool) []hyphae.ExistingHypha {
diff --git a/shroom/unattach.go b/shroom/unattach.go
index a2edc97..14f9af5 100644
--- a/shroom/unattach.go
+++ b/shroom/unattach.go
@@ -10,16 +10,15 @@ import (
)
// UnattachHypha unattaches hypha and makes a history record about that.
-func UnattachHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *history.Op, errtitle string) {
- hop = history.Operation(history.TypeUnattachHypha)
+func UnattachHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) error {
- if errtitle, err := CanUnattach(u, h, lc); errtitle != "" {
- hop.WithErrAbort(err)
- return hop, errtitle
+ if err := CanUnattach(u, h, lc); err != nil {
+ return err
}
H := h.(*hyphae.MediaHypha)
- hop.
+ hop := history.
+ Operation(history.TypeUnattachHypha).
WithFilesRemoved(H.MediaFilePath()).
WithMsg(fmt.Sprintf("Unattach ‘%s’", h.CanonicalName())).
WithUser(u).
@@ -28,7 +27,7 @@ func UnattachHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *histo
if len(hop.Errs) > 0 {
rejectUnattachLog(h, u, "fail")
// FIXME: something may be wrong here
- return hop.WithErrAbort(fmt.Errorf("Could not unattach this hypha due to internal server errors: %v", hop.Errs)), "Error"
+ return fmt.Errorf("Could not unattach this hypha due to internal server errors: %v", hop.Errs)
}
if H.HasTextFile() {
@@ -36,5 +35,5 @@ func UnattachHypha(u *user.User, h hyphae.Hypha, lc *l18n.Localizer) (hop *histo
} else {
hyphae.DeleteHypha(H)
}
- return hop, ""
+ return nil
}
diff --git a/shroom/upload.go b/shroom/upload.go
index 8ec5f9c..21b5182 100644
--- a/shroom/upload.go
+++ b/shroom/upload.go
@@ -47,8 +47,8 @@ func writeTextToDisk(h hyphae.ExistingHypha, data []byte, hop *history.Op) error
}
// UploadText edits the hypha's text part and makes a history record about that.
-func UploadText(h hyphae.Hypha, data []byte, userMessage string, u *user.User, lc *l18n.Localizer) (hop *history.Op, errtitle string) {
- hop = history.
+func UploadText(h hyphae.Hypha, data []byte, userMessage string, u *user.User, lc *l18n.Localizer) error {
+ hop := history.
Operation(history.TypeEditText).
WithMsg(historyMessageForTextUpload(h, userMessage)).
WithUser(u)
@@ -56,28 +56,27 @@ func UploadText(h hyphae.Hypha, data []byte, userMessage string, u *user.User, l
// Privilege check
if !u.CanProceed("upload-text") {
rejectEditLog(h, u, "no rights")
- return hop.WithErrAbort(errors.New(lc.Get("ui.act_norights_edit"))), lc.Get("ui.act_no_rights")
+ hop.Abort()
+ return errors.New("ui.act_no_rights")
}
// Hypha name exploit check
if !hyphae.IsValidName(h.CanonicalName()) {
// We check for the name only. I suppose the filepath would be valid as well.
- err := errors.New("invalid hypha name")
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return errors.New("invalid hypha name")
}
// Empty data check
if len(bytes.TrimSpace(data)) == 0 { // if nothing but whitespace
switch h.(type) {
- case *hyphae.EmptyHypha:
- // It's ok, just like cancel button.
- return hop.Abort(), ""
- case *hyphae.MediaHypha:
+ case *hyphae.EmptyHypha, *hyphae.MediaHypha:
// Writing no description, it's ok, just like cancel button.
- return hop.Abort(), ""
+ hop.Abort()
+ return nil
case *hyphae.TextualHypha:
// What do you want passing nothing for a textual hypha?
- return hop.WithErrAbort(errors.New("No data passed")), "Empty"
+ return errors.New("No data passed")
}
}
@@ -89,49 +88,57 @@ func UploadText(h hyphae.Hypha, data []byte, userMessage string, u *user.User, l
err := writeTextToDisk(H, data, hop)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return err
}
hyphae.Insert(H)
case *hyphae.MediaHypha:
oldText, err := FetchTextFile(h)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return err
}
// TODO: that []byte(...) part should be removed
if bytes.Compare(data, []byte(oldText)) == 0 {
// No changes! Just like cancel button
- return hop.Abort(), ""
+ hop.Abort()
+ return nil
}
err = writeTextToDisk(h, data, hop)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return err
}
backlinks.UpdateBacklinksAfterEdit(h, oldText)
case *hyphae.TextualHypha:
oldText, err := FetchTextFile(h)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return err
}
// TODO: that []byte(...) part should be removed
if bytes.Compare(data, []byte(oldText)) == 0 {
// No changes! Just like cancel button
- return hop.Abort(), ""
+ hop.Abort()
+ return nil
}
err = writeTextToDisk(h, data, hop)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ hop.Abort()
+ return err
}
backlinks.UpdateBacklinksAfterEdit(h, oldText)
}
- return hop.Apply(), ""
+ hop.Apply()
+ return nil
}
func historyMessageForMediaUpload(h hyphae.Hypha, mime string) string {
@@ -157,40 +164,35 @@ func writeMediaToDisk(h hyphae.Hypha, mime string, data []byte) (string, error)
}
// UploadBinary edits the hypha's media part and makes a history record about that.
-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)).
- WithUser(u)
+func UploadBinary(h hyphae.Hypha, mime string, file multipart.File, u *user.User, lc *l18n.Localizer) error {
// Privilege check
if !u.CanProceed("upload-binary") {
rejectAttachLog(h, u, "no rights")
- return hop.WithErrAbort(errors.New(lc.Get("ui.act_norights_attach"))), lc.Get("ui.act_no_rights")
+ return errors.New("ui.act_no_rights")
}
// Hypha name exploit check
if !hyphae.IsValidName(h.CanonicalName()) {
// We check for the name only. I suppose the filepath would be valid as well.
- err := errors.New("invalid hypha name")
- return hop.WithErrAbort(err), err.Error()
+ return errors.New("invalid hypha name")
}
data, err := io.ReadAll(file)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ return err
}
// Empty data check
if len(data) == 0 {
- return hop.WithErrAbort(errors.New("No data passed")), "Empty"
+ return errors.New("No data passed")
}
// At this point, we have a savable media document. Gotta save it.
uploadedFilePath, err := writeMediaToDisk(h, mime, data)
if err != nil {
- return hop.WithErrAbort(err), err.Error()
+ return err
}
switch h := h.(type) {
@@ -203,12 +205,18 @@ func UploadBinary(h hyphae.Hypha, mime string, file multipart.File, u *user.User
prevFilePath := h.MediaFilePath()
if prevFilePath != uploadedFilePath {
if err := history.Rename(prevFilePath, uploadedFilePath); err != nil {
- return hop.WithErrAbort(err), err.Error()
+ return err
}
log.Printf("Move ‘%s’ to ‘%s’\n", prevFilePath, uploadedFilePath)
h.SetMediaFilePath(uploadedFilePath)
}
}
- return hop.WithFiles(uploadedFilePath).Apply(), ""
+ history.
+ Operation(history.TypeEditBinary).
+ WithMsg(historyMessageForMediaUpload(h, mime)).
+ WithUser(u).
+ WithFiles(uploadedFilePath).
+ Apply()
+ return nil
}
diff --git a/user/user.go b/user/user.go
index a49dade..6020522 100644
--- a/user/user.go
+++ b/user/user.go
@@ -34,11 +34,14 @@ var minimalRights = map[string]int{
"edit": 1,
"upload-binary": 1,
"upload-text": 1,
+ "rename": 2,
"rename-ask": 2,
"rename-confirm": 2,
+ "remove-media": 2,
"unattach-ask": 2,
"unattach-confirm": 2,
"update-header-links": 3,
+ "delete": 3,
"delete-ask": 3,
"delete-confirm": 3,
"reindex": 4,
diff --git a/views/modal.qtpl b/views/modal.qtpl
index 2a0378d..8d6adf0 100644
--- a/views/modal.qtpl
+++ b/views/modal.qtpl
@@ -2,7 +2,7 @@
{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
-{% func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
+{% func DeleteAskHTML(rq *http.Request, hyphaName string) %}
{% code
lc := l18n.FromRequest(rq)
%}
@@ -16,7 +16,7 @@
{%= modalEnd(hyphaName, true, lc) %}
{% endfunc %}
-{% func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
+{% func UnattachAskHTML(rq *http.Request, hyphaName string) %}
{% code
lc := l18n.FromRequest(rq)
%}
@@ -29,7 +29,7 @@
{%= modalEnd(hyphaName, true, lc) %}
{% endfunc %}
-{% func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
+{% func RenameAskHTML(rq *http.Request, hyphaName string) %}
{% code
lc := l18n.FromRequest(rq)
%}
diff --git a/views/modal.qtpl.go b/views/modal.qtpl.go
index 85bb49f..10bddfe 100644
--- a/views/modal.qtpl.go
+++ b/views/modal.qtpl.go
@@ -27,7 +27,7 @@ var (
)
//line views/modal.qtpl:5
-func StreamDeleteAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func StreamDeleteAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:5
qw422016.N().S(`
`)
@@ -65,22 +65,22 @@ func StreamDeleteAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName
}
//line views/modal.qtpl:17
-func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:17
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:17
- StreamDeleteAskHTML(qw422016, rq, hyphaName, isOld)
+ StreamDeleteAskHTML(qw422016, rq, hyphaName)
//line views/modal.qtpl:17
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:17
}
//line views/modal.qtpl:17
-func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
+func DeleteAskHTML(rq *http.Request, hyphaName string) string {
//line views/modal.qtpl:17
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:17
- WriteDeleteAskHTML(qb422016, rq, hyphaName, isOld)
+ WriteDeleteAskHTML(qb422016, rq, hyphaName)
//line views/modal.qtpl:17
qs422016 := string(qb422016.B)
//line views/modal.qtpl:17
@@ -91,7 +91,7 @@ func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
}
//line views/modal.qtpl:19
-func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:19
qw422016.N().S(`
`)
@@ -124,22 +124,22 @@ func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaNam
}
//line views/modal.qtpl:30
-func WriteUnattachAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func WriteUnattachAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:30
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:30
- StreamUnattachAskHTML(qw422016, rq, hyphaName, isOld)
+ StreamUnattachAskHTML(qw422016, rq, hyphaName)
//line views/modal.qtpl:30
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:30
}
//line views/modal.qtpl:30
-func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
+func UnattachAskHTML(rq *http.Request, hyphaName string) string {
//line views/modal.qtpl:30
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:30
- WriteUnattachAskHTML(qb422016, rq, hyphaName, isOld)
+ WriteUnattachAskHTML(qb422016, rq, hyphaName)
//line views/modal.qtpl:30
qs422016 := string(qb422016.B)
//line views/modal.qtpl:30
@@ -150,7 +150,7 @@ func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
}
//line views/modal.qtpl:32
-func StreamRenameAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func StreamRenameAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:32
qw422016.N().S(`
`)
@@ -201,22 +201,22 @@ func StreamRenameAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName
}
//line views/modal.qtpl:49
-func WriteRenameAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
+func WriteRenameAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string) {
//line views/modal.qtpl:49
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:49
- StreamRenameAskHTML(qw422016, rq, hyphaName, isOld)
+ StreamRenameAskHTML(qw422016, rq, hyphaName)
//line views/modal.qtpl:49
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:49
}
//line views/modal.qtpl:49
-func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
+func RenameAskHTML(rq *http.Request, hyphaName string) string {
//line views/modal.qtpl:49
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:49
- WriteRenameAskHTML(qb422016, rq, hyphaName, isOld)
+ WriteRenameAskHTML(qb422016, rq, hyphaName)
//line views/modal.qtpl:49
qs422016 := string(qb422016.B)
//line views/modal.qtpl:49
diff --git a/views/nav.qtpl b/views/nav.qtpl
index 2223e1b..5bf2897 100644
--- a/views/nav.qtpl
+++ b/views/nav.qtpl
@@ -23,7 +23,7 @@