1
0
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:
Timur Ismagilov 2022-06-22 00:39:56 +03:00
parent df1f94eae4
commit e38daba7ad
4 changed files with 135 additions and 20 deletions

View File

@ -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")
}
}

View File

@ -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{}
}

View 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}}

View File

@ -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: "",
})