mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-07-22 18:52:50 +00:00
Interwiki: Add /interwiki/add-entry and the related stuff
This commit is contained in:
parent
df1f94eae4
commit
e38daba7ad
@ -3,11 +3,13 @@ package interwiki
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"github.com/bouncepaw/mycomarkup/v5/options"
|
"github.com/bouncepaw/mycomarkup/v5/options"
|
||||||
"github.com/bouncepaw/mycorrhiza/files"
|
"github.com/bouncepaw/mycorrhiza/files"
|
||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
@ -20,21 +22,47 @@ func Init() {
|
|||||||
for _, wiki := range record {
|
for _, wiki := range record {
|
||||||
wiki := wiki // This line is required
|
wiki := wiki // This line is required
|
||||||
wiki.canonize()
|
wiki.canonize()
|
||||||
theMap.list = append(theMap.list, &wiki)
|
if err := addEntry(&wiki); err != nil {
|
||||||
for _, name := range append(wiki.Aliases, wiki.Name) {
|
log.Fatalln(err.Error())
|
||||||
if _, found := theMap.byName[name]; found {
|
|
||||||
log.Fatalf("There are multiple uses of the same name ‘%s’\n", name)
|
|
||||||
} else {
|
|
||||||
theMap.byName[name] = &wiki
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Loaded %d interwiki entries\n", len(theMap.list))
|
log.Printf("Loaded %d interwiki entries\n", len(listOfEntries))
|
||||||
|
}
|
||||||
|
|
||||||
|
func areNamesFree(names []string) (bool, string) {
|
||||||
|
for _, name := range names {
|
||||||
|
if _, found := entriesByName[name]; found {
|
||||||
|
return false, name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var mutex sync.Mutex
|
||||||
|
|
||||||
|
func addEntry(wiki *Wiki) error {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
|
||||||
|
var (
|
||||||
|
names = append(wiki.Aliases, wiki.Name)
|
||||||
|
ok, name = areNamesFree(names)
|
||||||
|
)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("There are multiple uses of the same name ‘%s’\n", name)
|
||||||
|
return errors.New(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOfEntries = append(listOfEntries, wiki)
|
||||||
|
for _, name := range names {
|
||||||
|
entriesByName[name] = wiki
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HrefLinkFormatFor(prefix string) (string, options.InterwikiError) {
|
func HrefLinkFormatFor(prefix string) (string, options.InterwikiError) {
|
||||||
prefix = util.CanonicalName(prefix)
|
prefix = util.CanonicalName(prefix)
|
||||||
if wiki, ok := theMap.byName[prefix]; ok {
|
if wiki, ok := entriesByName[prefix]; ok {
|
||||||
return wiki.LinkHrefFormat, options.Ok
|
return wiki.LinkHrefFormat, options.Ok
|
||||||
}
|
}
|
||||||
return "", options.UnknownPrefix
|
return "", options.UnknownPrefix
|
||||||
@ -42,7 +70,7 @@ func HrefLinkFormatFor(prefix string) (string, options.InterwikiError) {
|
|||||||
|
|
||||||
func ImgSrcFormatFor(prefix string) (string, options.InterwikiError) {
|
func ImgSrcFormatFor(prefix string) (string, options.InterwikiError) {
|
||||||
prefix = util.CanonicalName(prefix)
|
prefix = util.CanonicalName(prefix)
|
||||||
if wiki, ok := theMap.byName[prefix]; ok {
|
if wiki, ok := entriesByName[prefix]; ok {
|
||||||
return wiki.ImgSrcFormat, options.Ok
|
return wiki.ImgSrcFormat, options.Ok
|
||||||
}
|
}
|
||||||
return "", options.UnknownPrefix
|
return "", options.UnknownPrefix
|
||||||
@ -66,3 +94,14 @@ func readInterwiki() ([]Wiki, error) {
|
|||||||
}
|
}
|
||||||
return record, nil
|
return record, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveInterwikiJson() {
|
||||||
|
// Trust me, wiki crashing when an admin takes an administrative action totally makes sense.
|
||||||
|
if data, err := json.MarshalIndent(listOfEntries, "", "\t"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
} else if err = os.WriteFile(files.InterwikiJSON(), data, 0666); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
} else {
|
||||||
|
log.Println("Saved interwiki.json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package interwiki
|
package interwiki
|
||||||
|
|
||||||
// Map is an interwiki map
|
var (
|
||||||
type Map struct {
|
listOfEntries []*Wiki
|
||||||
list []*Wiki
|
entriesByName map[string]*Wiki
|
||||||
byName map[string]*Wiki
|
)
|
||||||
}
|
|
||||||
|
|
||||||
var theMap Map
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
theMap.list = []*Wiki{}
|
listOfEntries = []*Wiki{}
|
||||||
theMap.byName = map[string]*Wiki{}
|
entriesByName = map[string]*Wiki{}
|
||||||
}
|
}
|
||||||
|
43
interwiki/view_name_taken.html
Normal file
43
interwiki/view_name_taken.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{{define "body"}}
|
||||||
|
<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">
|
||||||
|
<p>
|
||||||
|
<label for="name" class="required-field">Name:</label>
|
||||||
|
<input type="text" id="name" name="name" required
|
||||||
|
value="{{.Name}}">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="aliases">Aliases (separated by commas):</label>
|
||||||
|
<input type="text" id="aliases" name="aliases"
|
||||||
|
value="{{range $j, $alias := .Aliases}}{{if gt $j 0}}, {{end}}{{.}}{{end}}">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="url" class="required-field">URL:</label>
|
||||||
|
<input type="url" id="url" name="url" required
|
||||||
|
value="{{.URL}}">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="engine" class="required-field">Engine:</label>
|
||||||
|
<select name="engine" id="engine" required>
|
||||||
|
<option value="mycorrhiza" {{if eq .Engine "mycorrhiza"}}selected{{end}}>Mycorrhiza 🍄</option>
|
||||||
|
<option value="agora" {{if eq .Engine "agora"}}selected{{end}}>Agora ἀ</option>
|
||||||
|
<option value="generic" {{if eq .Engine "generic"}}selected{{end}}>Generic (any website)</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="link-href-format">Link href attribute format string:</label>
|
||||||
|
<input type="url" id="link-href-format" name="link-href-format"
|
||||||
|
value="{{.LinkHrefFormat}}">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="img-src-format">Image src attribute format string:</label>
|
||||||
|
<input type="url" id="img-src-format" name="img-src-format"
|
||||||
|
value="{{.ImgSrcFormat}}">
|
||||||
|
</p>
|
||||||
|
<input type="submit" class="btn" value="Save">
|
||||||
|
<a class="btn btn_weak" href="/interwiki">{{template "cancel"}}</a>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
{{end}}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/bouncepaw/mycorrhiza/viewutil"
|
"github.com/bouncepaw/mycorrhiza/viewutil"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -12,11 +13,46 @@ var (
|
|||||||
fs embed.FS
|
fs embed.FS
|
||||||
ruTranslation = ``
|
ruTranslation = ``
|
||||||
chainInterwiki viewutil.Chain
|
chainInterwiki viewutil.Chain
|
||||||
|
chainNameTaken viewutil.Chain
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitHandlers(rtr *mux.Router) {
|
func InitHandlers(rtr *mux.Router) {
|
||||||
chainInterwiki = viewutil.CopyEnRuWith(fs, "view_interwiki.html", ruTranslation)
|
chainInterwiki = viewutil.CopyEnRuWith(fs, "view_interwiki.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlerAddEntry(w http.ResponseWriter, rq *http.Request) {
|
||||||
|
wiki := Wiki{
|
||||||
|
Name: rq.PostFormValue("name"),
|
||||||
|
Aliases: strings.Split(rq.PostFormValue("aliases"), ","),
|
||||||
|
URL: rq.PostFormValue("url"),
|
||||||
|
LinkHrefFormat: rq.PostFormValue("link-href-format"),
|
||||||
|
ImgSrcFormat: rq.PostFormValue("img-src-format"),
|
||||||
|
Engine: WikiEngine(rq.PostFormValue("engine")),
|
||||||
|
}
|
||||||
|
wiki.canonize()
|
||||||
|
if err := addEntry(&wiki); err != nil {
|
||||||
|
viewNameTaken(viewutil.MetaFrom(w, rq), &wiki, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saveInterwikiJson()
|
||||||
|
http.Redirect(w, rq, "/interwiki", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nameTakenData struct {
|
||||||
|
*viewutil.BaseData
|
||||||
|
*Wiki
|
||||||
|
TakenName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewNameTaken(meta viewutil.Meta, wiki *Wiki, takenName string) {
|
||||||
|
viewutil.ExecutePage(meta, chainNameTaken, nameTakenData{
|
||||||
|
BaseData: &viewutil.BaseData{},
|
||||||
|
Wiki: wiki,
|
||||||
|
TakenName: takenName,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlerInterwiki(w http.ResponseWriter, rq *http.Request) {
|
func handlerInterwiki(w http.ResponseWriter, rq *http.Request) {
|
||||||
@ -33,7 +69,7 @@ type interwikiData struct {
|
|||||||
func viewInterwiki(meta viewutil.Meta) {
|
func viewInterwiki(meta viewutil.Meta) {
|
||||||
viewutil.ExecutePage(meta, chainInterwiki, interwikiData{
|
viewutil.ExecutePage(meta, chainInterwiki, interwikiData{
|
||||||
BaseData: &viewutil.BaseData{},
|
BaseData: &viewutil.BaseData{},
|
||||||
Entries: theMap.list,
|
Entries: listOfEntries,
|
||||||
CanEdit: meta.U.Group == "admin",
|
CanEdit: meta.U.Group == "admin",
|
||||||
Error: "",
|
Error: "",
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user