1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-11 21:10:26 +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))
}
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) {
for _, name := range names {
if _, found := entriesByName[name]; found {
@ -40,21 +66,59 @@ func areNamesFree(names []string) (bool, string) {
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()
defer mutex.Unlock()
var (
// non-empty names only
names = func(names []string) []string {
var result []string
for _, name := range names {
if name != "" {
result = append(result, name)
}
// I'm being fancy here. Come on, the code here is already a mess.
// Let me have some fun.
var wg sync.WaitGroup
wg.Add(2)
go func() {
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)
)
if !ok {

View File

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

View File

@ -2,7 +2,7 @@
<main class="main-width">
<h1>{{block "heading" .}}Name taken{{end}}</h1>
<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>
<label for="name" class="required-field">Name:</label>
<input type="text" id="name" name="name" required

View File

@ -4,6 +4,7 @@ import (
"embed"
"github.com/bouncepaw/mycorrhiza/viewutil"
"github.com/gorilla/mux"
"log"
"net/http"
"strings"
)
@ -37,9 +38,10 @@ func InitHandlers(rtr *mux.Router) {
chainNameTaken = viewutil.CopyEnRuWith(fs, "view_name_taken.html", ruTranslation)
rtr.HandleFunc("/interwiki", handlerInterwiki)
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{
Name: rq.PostFormValue("name"),
Aliases: strings.Split(rq.PostFormValue("aliases"), ","),
@ -49,8 +51,38 @@ func handlerAddEntry(w http.ResponseWriter, rq *http.Request) {
Engine: WikiEngine(rq.PostFormValue("engine")),
}
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 {
viewNameTaken(viewutil.MetaFrom(w, rq), &wiki, err.Error())
viewNameTaken(viewutil.MetaFrom(w, rq), &wiki, err.Error(), "add-entry")
return
}
saveInterwikiJson()
@ -61,13 +93,15 @@ type nameTakenData struct {
*viewutil.BaseData
*Wiki
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{
BaseData: &viewutil.BaseData{},
Wiki: wiki,
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"))
}