package configloader import ( "os" "encoding/json" "path/filepath" "io/ioutil" ) type MDWebDavUploaderConfig struct { InstanceLink string `json:"instance"` Username string `json:"username"` Mail string `json:"mail"` WebDavAuthToken string `json:"token"` InstitutionId int `json:"institution_id"` Parser string `json:"parser"` UploadDir string `json:"upload_directory"` PublishOnImport bool `json:"visible"` Settings map[string]string `json:"settings"` } // Returns the file path of the configuration file within the supplied // directory. Moved to a dedicated function to provide a consistent // filename. func getConfigFileNameByDir(folder string) string { return filepath.Join(folder, "config.json") } // Returns a uniform directory 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. func getConfigFilepath() (string, error) { // Get the OS-dependent configuration directory. generalConfigDir, dirErr := os.UserConfigDir() if dirErr != nil { return "", dirErr } // Select a subdirectory of that directory to store application-specific // settings in. Attempt to create it and return the config filepath as // a file in that directory. configDir := filepath.Join(generalConfigDir, "museum-digital-uploader") generateConfigDirErr := os.Mkdir(configDir, 0700) // The config directory could be created, return path of the configuration // file in it. if generateConfigDirErr == nil { return getConfigFileNameByDir(configDir), nil // Use this to create files } // There has been an error creating the config directory. // This may be either that the directory already exists, which is alright // (and even expected on most runs). Or it might be, that the path is // already occupied with a file. Or something else. In those cases, // the error should be returned. // If the path is already occupied, inspect it more closely. if os.IsExist(generateConfigDirErr) { info, err := os.Stat(configDir) if err != nil { return "", err } // The directory already exists and is a directory. This is fine, // so we return the config filename in the existing config directory. if info.IsDir() { return getConfigFileNameByDir(configDir), nil // Use this to create files } } return "", generateConfigDirErr } // Wrapper around getConfigFilepath() allowing for an override for testing. func getConfigFilepathOrOverride(overridePath string) (string, error) { // Override path is not validated, as it should only be used // in test settings if overridePath != "" { return overridePath, nil } configFilePath, err := getConfigFilepath() if err != nil { return "", err } return configFilePath, nil } // Validates each of the values of MDWebDavUploaderConfig. func ValidateConfig(conf MDWebDavUploaderConfig) (MDWebDavUploaderConfig, error) { // Validate and clean instance link instanceLink, instanceErr := ValidateInstanceLink(conf.InstanceLink) if instanceErr != nil { return conf, instanceErr } conf.InstanceLink = instanceLink // Validate and clean mail mailLink, mailErr := ValidateMail(conf.Mail) if mailErr != nil { return conf, mailErr } conf.Mail = mailLink // Validate and clean institution ID institutionIdLink, institutionIdErr := ValidateInstitutionId(conf.InstitutionId, conf.InstanceLink) if institutionIdErr != nil { return conf, institutionIdErr } conf.InstitutionId = institutionIdLink // Validate and clean parser parserLink, parserErr := ValidateParser(conf.Parser) if parserErr != nil { return conf, parserErr } conf.Parser = parserLink // Validate and clean upload folder uploadDir, mFolderErr := ValidateUploadDir(conf.UploadDir) if mFolderErr != nil { return conf, mFolderErr } conf.UploadDir = uploadDir return conf, nil } // Loads configuration from the configuration file (located using // getConfigFilepath()). // The function parameter overridePath is only useful for test settings. // Outside those, set an empty string to use the default config path. // Output parameters: // 1: Config // 2: Requirement for a re-run of the setup // 3: Error func LoadFromFile(overridePath string) (MDWebDavUploaderConfig, bool, error) { // Get config file path configFile, configFileErr := getConfigFilepathOrOverride(overridePath) if configFileErr != nil { return MDWebDavUploaderConfig{}, false, configFileErr } // Read the file configFileBytes, ioErr := ioutil.ReadFile(configFile) if ioErr != nil { return MDWebDavUploaderConfig{}, true, ioErr } // Parse the file into a configuration struct var data MDWebDavUploaderConfig unmarshalErr := json.Unmarshal(configFileBytes, &data) if unmarshalErr != nil { return MDWebDavUploaderConfig{}, true, ioErr } // Validate data - the configuration file may have been altered externally config, validationErr := ValidateConfig(data) if validationErr != nil { return MDWebDavUploaderConfig{}, true, validationErr } // Config could be parsed return config, false, nil } // Stores a config from MDWebDavUploaderConfig to the config file. // As with LoadFromFile(), it is possible to provide an overridePath for testing. func StoreConfigToFile(conf MDWebDavUploaderConfig, overridePath string) error { config, validationErr := ValidateConfig(conf) if validationErr != nil { return validationErr } configFilePath, configFileErr := getConfigFilepathOrOverride(overridePath) if configFileErr != nil { return configFileErr } configJson, encodeErr := json.Marshal(config) if encodeErr != nil { return encodeErr } writeErr := ioutil.WriteFile(configFilePath, configJson, 0644) if writeErr != nil { return writeErr } return nil }