1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 03:36:16 +00:00

Interwiki: Fix some bugs

* Actually, you could not edit interwiki entries before
* Fix faulty template in English locale
This commit is contained in:
Timur Ismagilov 2023-08-08 00:37:14 +05:00
parent c2619a6b82
commit fe4fd09cee
5 changed files with 123 additions and 17 deletions

View File

@ -29,6 +29,32 @@ func Init() {
log.Printf("Loaded %d interwiki entries\n", len(listOfEntries)) log.Printf("Loaded %d interwiki entries\n", len(listOfEntries))
} }
func dropEmptyStrings(ss []string) (clean []string) {
for _, s := range ss {
if s != "" {
clean = append(clean, s)
}
}
return clean
}
// difference returns the elements in `a` that aren't in `b`.
// Taken from https://stackoverflow.com/a/45428032
// CC BY-SA 4.0, no changes made
func difference(a, b []string) []string {
mb := make(map[string]struct{}, len(b))
for _, x := range b {
mb[x] = struct{}{}
}
var diff []string
for _, x := range a {
if _, found := mb[x]; !found {
diff = append(diff, x)
}
}
return diff
}
func areNamesFree(names []string) (bool, string) { func areNamesFree(names []string) (bool, string) {
for _, name := range names { for _, name := range names {
if _, found := entriesByName[name]; found { if _, found := entriesByName[name]; found {
@ -40,21 +66,59 @@ func areNamesFree(names []string) (bool, string) {
var mutex sync.Mutex var mutex sync.Mutex
func addEntry(wiki *Wiki) error { func replaceEntry(oldWiki *Wiki, newWiki *Wiki) error {
diff := difference(
append(newWiki.Aliases, newWiki.Name),
append(oldWiki.Aliases, oldWiki.Name),
)
if ok, name := areNamesFree(diff); !ok {
return errors.New(name)
}
deleteEntry(oldWiki)
return addEntry(newWiki)
}
func deleteEntry(wiki *Wiki) {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
var ( // I'm being fancy here. Come on, the code here is already a mess.
// non-empty names only // Let me have some fun.
names = func(names []string) []string { var wg sync.WaitGroup
var result []string
for _, name := range names { wg.Add(2)
if name != "" { go func() {
result = append(result, name) names := append(wiki.Aliases, wiki.Name)
} for _, name := range names {
name := name // I guess we need that
delete(entriesByName, name)
}
wg.Done()
}()
go func() {
for i, w := range listOfEntries {
i, w := i, w
if w.Name == wiki.Name {
log.Println("It came to delete")
// Drop ith element.
listOfEntries[i] = listOfEntries[len(listOfEntries)-1]
listOfEntries = listOfEntries[:len(listOfEntries)-1]
break
} }
return result }
}(append(wiki.Aliases, wiki.Name)) wg.Done()
}()
wg.Wait()
}
func addEntry(wiki *Wiki) error {
mutex.Lock()
defer mutex.Unlock()
wiki.Aliases = dropEmptyStrings(wiki.Aliases)
var (
names = append(wiki.Aliases, wiki.Name)
ok, name = areNamesFree(names) ok, name = areNamesFree(names)
) )
if !ok { if !ok {

View File

@ -5,6 +5,8 @@
{{define "aliases (,)"}}Aliases (separated by commas):{{end}} {{define "aliases (,)"}}Aliases (separated by commas):{{end}}
{{define "engine"}}Engine:{{end}} {{define "engine"}}Engine:{{end}}
{{define "engine/mycorrhiza"}}Mycorrhiza{{end}} {{define "engine/mycorrhiza"}}Mycorrhiza{{end}}
{{define "engine/betula"}}Betula{{end}}
{{define "engine/agora"}}Agora{{end}}
{{define "engine/generic"}}Generic (any website){{end}} {{define "engine/generic"}}Generic (any website){{end}}
{{define "url"}}URL{{end}} {{define "url"}}URL{{end}}
{{define "link href format"}}Link href attribute format string:{{end}} {{define "link href format"}}Link href attribute format string:{{end}}
@ -53,7 +55,7 @@
<form method="post" action="/interwiki/modify-entry/{{.Name}}"> <form method="post" action="/interwiki/modify-entry/{{.Name}}">
<p> <p>
<label for="name{{$i}}" class="required-field">{{template "name"}}</label> <label for="name{{$i}}" class="required-field">{{template "name"}}</label>
<input type="text" id="name" name="name{{$i}}" required <input type="text" id="name{{$i}}" name="name" required
value="{{.Name}}"> value="{{.Name}}">
</p> </p>
<p> <p>
@ -125,7 +127,7 @@
<input type="url" id="img-src-format" name="img-src-format" <input type="url" id="img-src-format" name="img-src-format"
placeholder="https://wiki.example.org/media/{NAME}"> placeholder="https://wiki.example.org/media/{NAME}">
</p> </p>
<input type="submit" class="btn"> <input type="submit" class="btn" value="Add entry">
</form> </form>
{{end}} {{end}}

View File

@ -2,7 +2,7 @@
<main class="main-width"> <main class="main-width">
<h1>{{block "heading" .}}Name taken{{end}}</h1> <h1>{{block "heading" .}}Name taken{{end}}</h1>
<p>{{block "tip" .TakenName}}Name <kbd>{{.}}</kbd> is already taken, please choose a different one.{{end}}</p> <p>{{block "tip" .TakenName}}Name <kbd>{{.}}</kbd> is already taken, please choose a different one.{{end}}</p>
<form method="post" action="/interwiki/add-entry"> <form method="post" action="/interwiki/{{.Action}}">
<p> <p>
<label for="name" class="required-field">Name:</label> <label for="name" class="required-field">Name:</label>
<input type="text" id="name" name="name" required <input type="text" id="name" name="name" required

View File

@ -4,6 +4,7 @@ import (
"embed" "embed"
"github.com/bouncepaw/mycorrhiza/viewutil" "github.com/bouncepaw/mycorrhiza/viewutil"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"log"
"net/http" "net/http"
"strings" "strings"
) )
@ -37,9 +38,10 @@ func InitHandlers(rtr *mux.Router) {
chainNameTaken = viewutil.CopyEnRuWith(fs, "view_name_taken.html", ruTranslation) chainNameTaken = viewutil.CopyEnRuWith(fs, "view_name_taken.html", ruTranslation)
rtr.HandleFunc("/interwiki", handlerInterwiki) rtr.HandleFunc("/interwiki", handlerInterwiki)
rtr.HandleFunc("/interwiki/add-entry", handlerAddEntry).Methods(http.MethodPost) rtr.HandleFunc("/interwiki/add-entry", handlerAddEntry).Methods(http.MethodPost)
rtr.HandleFunc("/interwiki/modify-entry/{target}", handlerModifyEntry).Methods(http.MethodPost)
} }
func handlerAddEntry(w http.ResponseWriter, rq *http.Request) { func readInterwikiEntryFromRequest(rq *http.Request) Wiki {
wiki := Wiki{ wiki := Wiki{
Name: rq.PostFormValue("name"), Name: rq.PostFormValue("name"),
Aliases: strings.Split(rq.PostFormValue("aliases"), ","), Aliases: strings.Split(rq.PostFormValue("aliases"), ","),
@ -49,8 +51,38 @@ func handlerAddEntry(w http.ResponseWriter, rq *http.Request) {
Engine: WikiEngine(rq.PostFormValue("engine")), Engine: WikiEngine(rq.PostFormValue("engine")),
} }
wiki.canonize() wiki.canonize()
return wiki
}
func handlerModifyEntry(w http.ResponseWriter, rq *http.Request) {
var (
oldData *Wiki
ok bool
name = mux.Vars(rq)["target"]
newData = readInterwikiEntryFromRequest(rq)
)
if oldData, ok = entriesByName[name]; !ok {
log.Printf("Could not modify interwiki entry %s because it does not exist", name)
viewutil.HandlerNotFound(w, rq)
return
}
if err := replaceEntry(oldData, &newData); err != nil {
log.Printf("Could not modify interwiki entry %s because one of the proposed aliases/name is taken\n", name)
viewNameTaken(viewutil.MetaFrom(w, rq), oldData, err.Error(), "modify-entry/"+name)
return
}
saveInterwikiJson()
log.Printf("Modified interwiki entry %s\n", name)
http.Redirect(w, rq, "/interwiki", http.StatusSeeOther)
}
func handlerAddEntry(w http.ResponseWriter, rq *http.Request) {
wiki := readInterwikiEntryFromRequest(rq)
if err := addEntry(&wiki); err != nil { if err := addEntry(&wiki); err != nil {
viewNameTaken(viewutil.MetaFrom(w, rq), &wiki, err.Error()) viewNameTaken(viewutil.MetaFrom(w, rq), &wiki, err.Error(), "add-entry")
return return
} }
saveInterwikiJson() saveInterwikiJson()
@ -61,13 +93,15 @@ type nameTakenData struct {
*viewutil.BaseData *viewutil.BaseData
*Wiki *Wiki
TakenName string TakenName string
Action string
} }
func viewNameTaken(meta viewutil.Meta, wiki *Wiki, takenName string) { func viewNameTaken(meta viewutil.Meta, wiki *Wiki, takenName, action string) {
viewutil.ExecutePage(meta, chainNameTaken, nameTakenData{ viewutil.ExecutePage(meta, chainNameTaken, nameTakenData{
BaseData: &viewutil.BaseData{}, BaseData: &viewutil.BaseData{},
Wiki: wiki, Wiki: wiki,
TakenName: takenName, TakenName: takenName,
Action: action,
}) })
} }

View File

@ -26,3 +26,9 @@ func HttpErr(meta Meta, status int, name, errMsg string) {
), ),
) )
} }
// HandlerNotFound prints the simples 404 page. Use in rare places that cannot be achieved normally.
func HandlerNotFound(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("404 Page not found"))
}