1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-03-10 13:38:20 +00:00
mycorrhiza/interwiki/interwiki.go
Timur Ismagilov 41733c50bd
New templates #117 (#236)
Didn't have the chance to migrate //all// templates just yet. We'll get there.

* Implement yet another template system

* Move orphans to the new system and fix a bug in it

* Link orphans in the admin panel

* Move the backlink handlers to the web package

* Move auth routing to web

* Move /user-list to the new system

* Move change password and translate it

* Move stuff

* Move admin-related stuff to the web

* Move a lot of files into internal dir

Outside of it are web and stuff that needs further refactoring

* Fix static not loading and de-qtpl tree

* Move tree to internal

* Keep the globe on the same line #230

* Revert "Keep the globe on the same line #230"

This reverts commit ae78e5e459b1e980ba89bf29e61f75c0625ed2c7.

* Migrate templates from hypview: delete, edit, start empty and existing WIP

The delete media view was removed, I didn't even know it still existed as a GET. A rudiment.

* Make views multi-file and break compilation

* Megarefactoring of hypha views

* Auth-related stuffs

* Fix some of those weird imports

* Migrate cat views

* Fix cat js

* Lower standards

* Internalize trauma
2024-09-07 21:22:41 +03:00

186 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package interwiki provides interwiki capabilities. Most of them, at least.
package interwiki
import (
"encoding/json"
"errors"
"git.sr.ht/~bouncepaw/mycomarkup/v5/options"
"github.com/bouncepaw/mycorrhiza/internal/files"
"github.com/bouncepaw/mycorrhiza/util"
"log"
"os"
"sync"
)
func Init() {
var (
record, err = readInterwiki()
)
if err != nil {
log.Fatalln(err)
}
for _, wiki := range record {
wiki := wiki // This line is required
wiki.canonize()
if err := addEntry(&wiki); err != nil {
log.Fatalln(err.Error())
}
}
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 {
return false, name
}
}
return true, ""
}
var mutex sync.Mutex
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()
// 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
}
}
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 {
log.Printf("There are multiple uses of the same name %s\n", name)
return errors.New(name)
}
if len(names) == 0 {
log.Println("No names passed for a new interwiki entry")
// There is something clearly wrong with error-returning in this function.
return errors.New("")
}
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 := entriesByName[prefix]; ok {
return wiki.LinkHrefFormat, options.Ok
}
return "", options.UnknownPrefix
}
func ImgSrcFormatFor(prefix string) (string, options.InterwikiError) {
prefix = util.CanonicalName(prefix)
if wiki, ok := entriesByName[prefix]; ok {
return wiki.ImgSrcFormat, options.Ok
}
return "", options.UnknownPrefix
}
func readInterwiki() ([]Wiki, error) {
var (
record []Wiki
fileContents, err = os.ReadFile(files.InterwikiJSON())
)
if os.IsNotExist(err) {
return record, nil
}
if err != nil {
return nil, err
}
err = json.Unmarshal(fileContents, &record)
if err != nil {
return nil, err
}
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")
}
}