Didn't have the chance to migrate //all// templates just yet. We'll get there.
* Implement yet another template system
* Move orphans to the new system and fix a bug in it
* Link orphans in the admin panel
* Move the backlink handlers to the web package
* Move auth routing to web
* Move /user-list to the new system
* Move change password and translate it
* Move stuff
* Move admin-related stuff to the web
* Move a lot of files into internal dir
Outside of it are web and stuff that needs further refactoring
* Fix static not loading and de-qtpl tree
* Move tree to internal
* Keep the globe on the same line #230
* Revert "Keep the globe on the same line #230"
This reverts commit ae78e5e459.
* Migrate templates from hypview: delete, edit, start empty and existing WIP
The delete media view was removed, I didn't even know it still existed as a GET. A rudiment.
* Make views multi-file and break compilation
* Megarefactoring of hypha views
* Auth-related stuffs
* Fix some of those weird imports
* Migrate cat views
* Fix cat js
* Lower standards
* Internalize trauma
151 lines
4.5 KiB
Go
151 lines
4.5 KiB
Go
package shroom
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
|
||
"github.com/bouncepaw/mycorrhiza/internal/categories"
|
||
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||
"github.com/bouncepaw/mycorrhiza/internal/files"
|
||
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
||
"github.com/bouncepaw/mycorrhiza/internal/user"
|
||
"path"
|
||
"path/filepath"
|
||
"regexp"
|
||
"strings"
|
||
|
||
"github.com/bouncepaw/mycorrhiza/history"
|
||
"github.com/bouncepaw/mycorrhiza/util"
|
||
)
|
||
|
||
// Rename renames the old hypha to the new name and makes a history record about that. Call if and only if the user has the permission to rename.
|
||
func Rename(oldHypha hyphae2.ExistingHypha, newName string, recursive bool, leaveRedirections bool, u *user.User) error {
|
||
// * bouncepaw hates this function and related renaming functions
|
||
if newName == "" {
|
||
rejectRenameLog(oldHypha, u, "no new name given")
|
||
return errors.New("ui.rename_noname_tip")
|
||
}
|
||
|
||
if !hyphae2.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.
|
||
}
|
||
|
||
switch targetHypha := hyphae2.ByName(newName); targetHypha.(type) {
|
||
case hyphae2.ExistingHypha:
|
||
if targetHypha.CanonicalName() == oldHypha.CanonicalName() {
|
||
return nil
|
||
}
|
||
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)` + oldHypha.CanonicalName())
|
||
replaceName = func(str string) string {
|
||
namepart := strings.TrimPrefix(str, files.HyphaeDir())
|
||
// Can we drop that util.CanonicalName?:
|
||
replaced := re.ReplaceAllString(util.CanonicalName(namepart), newName)
|
||
return path.Join(files.HyphaeDir(), replaced)
|
||
}
|
||
hyphaeToRename = findHyphaeToRename(oldHypha, recursive)
|
||
renameMap, err = renamingPairs(hyphaeToRename, replaceName)
|
||
)
|
||
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
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)
|
||
|
||
if len(hop.Errs) != 0 {
|
||
return hop.Errs[0]
|
||
}
|
||
|
||
for _, h := range hyphaeToRename {
|
||
var (
|
||
oldName = h.CanonicalName()
|
||
newName = re.ReplaceAllString(oldName, newName)
|
||
)
|
||
hyphae2.RenameHyphaTo(h, newName, replaceName)
|
||
backlinks.UpdateBacklinksAfterRename(h, oldName)
|
||
categories.RenameHyphaInAllCategories(oldName, newName)
|
||
if leaveRedirections {
|
||
if err := leaveRedirection(oldName, newName, hop); err != nil {
|
||
hop.WithErrAbort(err)
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
|
||
hop.Apply()
|
||
|
||
return nil
|
||
}
|
||
|
||
const redirectionTemplate = `=> %[1]s | 👁️➡️ %[2]s
|
||
<= %[1]s | full
|
||
`
|
||
|
||
func leaveRedirection(oldName, newName string, hop *history.Op) error {
|
||
var (
|
||
text = fmt.Sprintf(redirectionTemplate, newName, util.BeautifulName(newName))
|
||
emptyHypha = hyphae2.ByName(oldName)
|
||
)
|
||
switch emptyHypha := emptyHypha.(type) {
|
||
case *hyphae2.EmptyHypha:
|
||
h := hyphae2.ExtendEmptyToTextual(emptyHypha, filepath.Join(files.HyphaeDir(), oldName+".myco"))
|
||
hyphae2.Insert(h)
|
||
categories.AddHyphaToCategory(oldName, cfg.RedirectionCategory)
|
||
defer backlinks.UpdateBacklinksAfterEdit(h, "")
|
||
return writeTextToDisk(h, []byte(text), hop)
|
||
default:
|
||
return errors.New("invalid state for hypha " + oldName + " renamed to " + newName)
|
||
}
|
||
}
|
||
|
||
func findHyphaeToRename(superhypha hyphae2.ExistingHypha, recursive bool) []hyphae2.ExistingHypha {
|
||
hyphaList := []hyphae2.ExistingHypha{superhypha}
|
||
if recursive {
|
||
hyphaList = append(hyphaList, hyphae2.Subhyphae(superhypha)...)
|
||
}
|
||
return hyphaList
|
||
}
|
||
|
||
func renamingPairs(hyphaeToRename []hyphae2.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.HasTextFile() {
|
||
renameMap[h.TextFilePath()] = replaceName(h.TextFilePath())
|
||
}
|
||
switch h := h.(type) {
|
||
case *hyphae2.MediaHypha:
|
||
renameMap[h.MediaFilePath()] = replaceName(h.MediaFilePath())
|
||
}
|
||
h.Unlock()
|
||
}
|
||
if firstFailure, ok := hyphae2.AreFreeNames(newNames...); !ok {
|
||
return nil, errors.New("Hypha " + firstFailure + " already exists")
|
||
}
|
||
return renameMap, nil
|
||
}
|