Add add config validators

This commit is contained in:
jrenslin committed 2025-02-24 04:33:43 +01:00
1 parent dfe1bdfeb4
commit d4c83e27d2
8 files changed
+262 -42

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
package configloader
import _ "embed"
import (
"encoding/json"
"errors"
"slices"
)
type ParserListItem struct {
Title string `json:"title"`
Comment string `json:"comment"`
Authors []string `json:"authors"`
Links []string `json:"links"`
}
// Load parser list from JSON retrieved from musdb's API
// See https://<subdomain>.museum-digital.org/musdb/api/meta/list_import_parsers
// The embed module requires the variable to not be bound to a function.
//go:embed parser_list.json
var rawParserList []byte
// Returns a list of the available parsers.
func ListParsers() []ParserListItem {
parserListFromApi := []ParserListItem{}
// parserListFromApi := new(ApiParserListFormat)
json.Unmarshal(rawParserList, &parserListFromApi)
print(parserListFromApi)
return parserListFromApi
}
// Checks if inputParser is in the list of available parsers.
// Returns the parser name or an error.
func ValidateParser(inputParser string) (string, error) {
parserList := ListParsers()
parserTitles := []string{}
for _, p := range(parserList) {
parserTitles = append(parserTitles, p.Title)
}
if slices.Contains(parserTitles, inputParser) {
return inputParser, nil
}
// Accepted invalid modes to clean up:
// ParserLido > Lido
// lido > Lido
cleaned := inputParser[6:]
if slices.Contains(parserTitles, cleaned) {
return cleaned, nil
}
return "", errors.New("Invalid parser selected")
}
+55
View File
@@ -0,0 +1,55 @@
package configloader
import (
"testing"
)
// Tests that the list of parsers is not empty.
func TestListParserReturnsNonEmptyResult(t *testing.T) {
parserList := ListParsers()
if len(parserList) == 0 {
t.Fatalf("The list of returned parsers is empty")
}
}
// Ensures that validating a parser will not accept an invalid parser name.
func TestInvalidParserIsNotAccepted(t *testing.T) {
parser, err := ValidateParser("Liddasfasdo")
if parser != "" {
t.Fatalf("ValidateParser() should return an empty string + error")
}
if err == nil {
t.Fatalf("ValidateParser() did not return an error where it should")
}
}
// Ensures that a parser is valid at its expected name.
func TestValidParserIsAccepted(t *testing.T) {
parser, err := ValidateParser("Lido")
if parser != "Lido" {
t.Fatalf("Test expected validated parser for input 'Lido' to be 'Lido'")
}
if err != nil {
t.Fatalf("ValidateParser() returned an error where it should not")
}
}
// Prepending the prefix "Parser" to a parser name should work as well.
// In this case, the prefix should be removed by ValidateParser().
func TestValidParserIsAcceptedAndCleaned(t *testing.T) {
parser, err := ValidateParser("ParserLido")
if parser != "Lido" {
t.Fatalf("Test expected validated parser for input 'ParserLido' to be 'Lido'")
}
if err != nil {
t.Fatalf("ValidateParser() returned an error where it should not")
}
}
+47
View File
@@ -0,0 +1,47 @@
package configloader
import (
"errors"
"net/url"
"net/http"
"strings"
)
// Validates a museum-digital instance URL to upload to.
// The link must be a valid URL. As it can be expected that people will
// enter broken values, the URL should be reduced to its hostname and
// rebuilt from there.
func ValidateInstanceLink(instanceUrl string) (string, error) {
parsed, err := url.Parse(instanceUrl)
if err != nil {
return "", err
}
// Check the hostname contains "museum-digital.de" or "museum-digital.org"
if !strings.HasSuffix(parsed.Host, "museum-digital.de") && !strings.HasSuffix(parsed.Host, "museum-digital.org") {
return "", errors.New("This tool only supports uploading to XYZ.museum-digital.de or XYZ.museum-digital.org")
}
// Check /musdb is available on the md instance
musdbUrl := url.URL{
Scheme: "https",
Host: parsed.Host,
Path: "/musdb",
}
resp, err := http.Get(musdbUrl.String())
if err != nil {
return "", err
}
if resp.StatusCode > 399 {
return "", errors.New("The museum-digital subdomain does not contain a musdb path")
}
// https should be assumed and enforced.
url := url.URL{
Scheme: "https",
Host: parsed.Host,
}
return url.String(), nil
}
@@ -0,0 +1,55 @@
package configloader
import (
"testing"
)
// Test that ValidateInstanceLink() fails on non-URLs.
func TestValidateInstanceFailsOnNonUrl(t *testing.T) {
_, err := ValidateInstanceLink("abcmuseum-digital.org")
if err == nil {
t.Fatalf("ValidateInstanceLink() does not return an error on a non-URL")
}
}
// Test that ValidateInstanceLink() fails on links outside of md.
func TestValidateInstanceLinkFailsOutsideOfMd(t *testing.T) {
_, err := ValidateInstanceLink("test.museum-digital.de")
if err == nil {
t.Fatalf("ValidateInstanceLink() accepts URLs outside of the main museum-digital")
}
}
// Test that ValidateInstanceLink() fails on valid md aggregated instances
// (uploads can only happen to regional instances / those that have a dedicated
// instance of musdb).
func TestValidateInstanceLinkFailsWithAggregatedInstance(t *testing.T) {
_, err := ValidateInstanceLink("https://nat.museum-digital.de")
if err == nil {
t.Fatalf("ValidateInstanceLink() accepts URLs of aggregated instance")
}
}
// Test that ValidateInstanceLink() works with a valid instance of md.
func TestValidateInstanceWorks(t *testing.T) {
result, err := ValidateInstanceLink("https://hessen.museum-digital.de")
if err != nil {
t.Fatalf("ValidateInstanceLink() returns an error where it should work")
}
if result != "https://hessen.museum-digital.de" {
t.Fatalf("Output of ValidateInstanceLink() is not https://hessen.museum-digital.de where it should be")
}
}
+15
View File
@@ -0,0 +1,15 @@
package configloader
import "net/mail"
// Validates an input mail address.
// Returns the valid mail address or an eQueries therror.
func ValidateMail(email string) (string, error) {
_, err := mail.ParseAddress(email)
if err != nil {
return "", err
}
return email, nil
}
+27
View File
@@ -0,0 +1,27 @@
package configloader
import (
"testing"
)
// Test that ValidateMail() returns the mail address if it is valid.
func TestValidateMailAcceptsValidMailAddress(t *testing.T) {
_, err := ValidateMail("test@example.com")
if err != nil {
t.Fatalf("ValidateMail() returns an error on a valid mail address")
}
}
// Test that ValidateMail() filters out invalid mail addresses.
func TestValidateMailDoesNotAcceptInvalidMailAddress(t *testing.T) {
_, err := ValidateMail("test")
if err == nil {
t.Fatalf("ValidateMail() does not prevent entering an invalid mail address")
}
}
-42
View File
@@ -11,11 +11,6 @@ type MDWebDavUploaderConfig struct {
PublishOnImport bool `json:"visible"`
}
type ParserListItem struct {
name string
}
// Returns a uniform filepath for the configuration of this tool.
// To be compatible across operating systems, this will be a JSON
// file in the same directory as the current programm.
@@ -23,45 +18,8 @@ func getConfigFilepath() string {
}
// Returns a uniform filepath for the cache for the list of
// available parsers.
func getParserCacheFilepath() string {
}
// Loads configuration from the configuration file (located using
// getConfigFilepath()).
func LoadFromFile() MDWebDavUploaderConfig {
}
// Stores a parser list to a cache file (located via
// getParserCacheFilepath()).
func StoreParserList(parserList []ParserListItem) {
}
// Returns a list of the available parsers.
func ListParsers() []ParserListItem {
}
// Checks if inputParser is in the list of available parsers.
// Returns the parser name or an error.
func ValidateParser(inputParser string) (string, error) {
}
// Validates an input mail address.
// Returns the valid mail address or an eQueries therror.
func ValidateMail(mail string) (string, error) {
}
// Validates an entered instance URL.
// Returns the entered URL in a unified form (minus optional
// trailing slashes and the /musdb suffix) or an error.
func ValidateInstanceLink(instanceUrl string) (string, error) {
}
+1
View File
@@ -0,0 +1 @@
[{"title":"AdlibCsv","comment":"Parser for CSV exports from Adlib.\n\nHas the following settings:\n\nstart_at Setting this option to any number other than 0 makes the importer\n\n skip the first X files. This can be useful if an import fails\n\n somewhere in the middle of the import process. Using this setting,\n\n you can skip import files that have already been successfully\n\n imported.\n\nseparator The separator character dividing the columns in the CSV file to be\n\n imported. Defaults to ','.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.axiell.com\/de\/loesungen\/produkt\/adlib\/"]},{"title":"AdlibLiteratureXml","comment":"Parser for XML exports of the literature module of Adlib \/ Axiell Collections.\n\nThis parser imports from the literature module to the literature module.\n\nThe parser has the following settings.\n\nstart_at Setting this option to any number other than\n\n 0 makes the importer skip the first X files.\n\n This can be useful if an import fails somewhere\n\n in the middle of the import process. Using this\n\n setting, you can skip import files that have\n\n already been successfully imported.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.axiell.com\/de\/loesungen\/produkt\/adlib\/"]},{"title":"AdlibLiteratureXmlToObjects","comment":"Parser for XML exports of the literature module of Adlib \/ Axiell Collections.\n\nThis parser imports from the literature module to the object module.\n\nThe parser has the following settings.\n\nstart_at Setting this option to any number other than\n\n 0 makes the importer skip the first X files.\n\n This can be useful if an import fails somewhere\n\n in the middle of the import process. Using this\n\n setting, you can skip import files that have\n\n already been successfully imported.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.axiell.com\/de\/loesungen\/produkt\/adlib\/"]},{"title":"AdlibXml","comment":"Parser for XML exports from Adlib \/ Axiell Collections. Initially optimized and\n\ntested with export data from the Schwules Museum Berlin (https:\/\/www.schwulesmuseum.de\/ \/\n\nhttps:\/\/berlin.museum-digital.de\/institution\/33), the parser has now been extended\n\nto cover exports from a number of museums using different versions of the software.\n\nHas the following settings:\n\nstart_at Setting this option to any number other than\n\n 0 makes the importer skip the first X files.\n\n This can be useful if an import fails somewhere\n\n in the middle of the import process. Using this\n\n setting, you can skip import files that have\n\n already been successfully imported.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.axiell.com\/de\/loesungen\/produkt\/adlib\/"]},{"title":"BeeCollectDtmb","comment":"Parser for XML generated through CSVXML.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>","Stefan Rohde-Enslin <s.rohde-enslin@museum-digital.de>"],"links":["https:\/\/imports.museum-digital.org\/importer\/parsers\/csvxml.php"]},{"title":"BeeCollectIndustriemuseenSachsen","comment":"Parser for exports from BeeCollect formulated for the industrial heritage\n\nmuseums in Saxony.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.solvatec.com\/"]},{"title":"BeeCollectStadtmuseumDresden","comment":"Parser for exports from BeeCollect formulated for the export settings of the\n\nCity Museum of Dresden.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/www.solvatec.com\/"]},{"title":"CsvMuseenKoeln","comment":"Parser to import images using very simple CSV files with only two columns:\n\n\"inventory_number\" and \"image_name1\".\n\nstart_at Setting this option to any number other than 0 makes the importer\n\n skip the first X files. This can be useful if an import fails\n\n somewhere in the middle of the import process. Using this setting,\n\n you can skip import files that have already been successfully\n\n imported.\n\nseparator The separator character dividing the columns in the CSV file to be\n\n imported. Defaults to ';'.\n\nsub_separator Separator for tags, etc.","authors":["Joshua Ramon Enslin <joshua@museum-digital.de>"],"links":["https:\/\/csvxml.imports.museum-digital.org\/"]},{"title":"Csvxml","comment":"Parser for XML generated through CLine truncated