mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-10-30 03:36:16 +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 (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/bouncepaw/mycomarkup/v5/options"
|
||||
"github.com/bouncepaw/mycorrhiza/files"
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
@ -20,21 +22,47 @@ func Init() {
|
||||
for _, wiki := range record {
|
||||
wiki := wiki // This line is required
|
||||
wiki.canonize()
|
||||
theMap.list = append(theMap.list, &wiki)
|
||||
for _, name := range append(wiki.Aliases, wiki.Name) {
|
||||
if _, found := theMap.byName[name]; found {
|
||||
log.Fatalf("There are multiple uses of the same name ‘%s’\n", name)
|
||||
} else {
|
||||
theMap.byName[name] = &wiki
|
||||
}
|
||||
if err := addEntry(&wiki); err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
}
|
||||
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) {
|
||||
prefix = util.CanonicalName(prefix)
|
||||
if wiki, ok := theMap.byName[prefix]; ok {
|
||||
if wiki, ok := entriesByName[prefix]; ok {
|
||||
return wiki.LinkHrefFormat, options.Ok
|
||||
}
|
||||
return "", options.UnknownPrefix
|
||||
@ -42,7 +70,7 @@ func HrefLinkFormatFor(prefix string) (string, options.InterwikiError) {
|
||||
|
||||
func ImgSrcFormatFor(prefix string) (string, options.InterwikiError) {
|
||||
prefix = util.CanonicalName(prefix)
|
||||
if wiki, ok := theMap.byName[prefix]; ok {
|
||||
if wiki, ok := entriesByName[prefix]; ok {
|
||||
return wiki.ImgSrcFormat, options.Ok
|
||||
}
|
||||
return "", options.UnknownPrefix
|
||||
@ -66,3 +94,14 @@ func readInterwiki() ([]Wiki, error) {
|
||||
}
|
||||
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
|
||||
|
||||
// Map is an interwiki map
|
||||
type Map struct {
|
||||
list []*Wiki
|
||||
byName map[string]*Wiki
|
||||
}
|
||||
|
||||
var theMap Map
|
||||
var (
|
||||
listOfEntries []*Wiki
|
||||
entriesByName map[string]*Wiki
|
||||
)
|
||||
|
||||
func init() {
|
||||
theMap.list = []*Wiki{}
|
||||
theMap.byName = map[string]*Wiki{}
|
||||
listOfEntries = []*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/gorilla/mux"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -12,11 +13,46 @@ var (
|
||||
fs embed.FS
|
||||
ruTranslation = ``
|
||||
chainInterwiki viewutil.Chain
|
||||
chainNameTaken viewutil.Chain
|
||||
)
|
||||
|
||||
func InitHandlers(rtr *mux.Router) {
|
||||
chainInterwiki = viewutil.CopyEnRuWith(fs, "view_interwiki.html", ruTranslation)
|
||||
chainNameTaken = viewutil.CopyEnRuWith(fs, "view_name_taken.html", ruTranslation)
|
||||
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) {
|
||||
@ -33,7 +69,7 @@ type interwikiData struct {
|
||||
func viewInterwiki(meta viewutil.Meta) {
|
||||
viewutil.ExecutePage(meta, chainInterwiki, interwikiData{
|
||||
BaseData: &viewutil.BaseData{},
|
||||
Entries: theMap.list,
|
||||
Entries: listOfEntries,
|
||||
CanEdit: meta.U.Group == "admin",
|
||||
Error: "",
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user