mirror of https://github.com/micromata/borgbackup-butler.git

Kai Reinhard
18.09.2021 ea8ad4f8ce1208a08efc8557240c5499b06e4b9a
Code cleanup, json.prettyprint removed.
1 files added
14 files modified
280 ■■■■ changed files
borgbutler-core/src/main/kotlin/de/micromata/borgbutler/config/Configuration.kt 2 ●●●●● patch | view | raw | blame | history
borgbutler-docker/buildDocker.sh 10 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/BorgButlerApplication.kt 6 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/RunningMode.kt 2 ●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/ServerConfiguration.kt 4 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ArchivesRest.kt 17 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.kt 9 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ConfigurationRest.kt 27 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/I18nRest.kt 8 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/JacksonConfig.kt 36 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/JobsRest.kt 79 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/LoggingRest.kt 27 ●●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ReposRest.kt 26 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/SystemInfoRest.kt 4 ●●●● patch | view | raw | blame | history
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/VersionRest.kt 23 ●●●● patch | view | raw | blame | history
borgbutler-core/src/main/kotlin/de/micromata/borgbutler/config/Configuration.kt
@@ -30,6 +30,8 @@
    /**
     * The borg version to install from github (optional).
     */
    // @JsonIgnore needed by client: ConfigurationserverTab.jsx fails otherwise (conflicting borgVersion fields).
    @JsonIgnore
    var borgVersion: String? = null
    /**
borgbutler-docker/buildDocker.sh
@@ -11,7 +11,13 @@
echo "Building docker file..."
(cd app; docker build -t kreinhard/borgbutler .)
echo "Push: docker push kreinhard/borgbutler:tagname"
echo "Run without ssh: 'docker run -v $HOME/BorgButler:/BorgButler -p 127.0.0.1:9042:9042 --name borgbutler kreinhard/borgbutler'"
echo "docker tag ..... version"
echo "docker push kreinhard/borgbutler:version"
echo "docker push kreinhard/borgbutler:latest"
echo
echo
echo "Run without ssh: 'docker run -v $HOME/BorgButler:/BorgButler -p 127.0.0.1:9042:9042 --name borgbutler kreinhard/borgbutler'"
echo "Run with ssh: 'docker run -v $HOME/BorgButler:/BorgButler -v $HOME/.ssh:/home/borgbutler/.ssh:ro -p 127.0.0.1:9042:9042 --name borgbutler kreinhard/borgbutler'"
echo
echo 'Increase Java memory: docker run -e JAVA_OPTS="-Xms4g -Xmx4g" -v ...'
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/BorgButlerApplication.kt
@@ -112,7 +112,7 @@
            }
            val uri = URI.create(url)
            val quietMode = line.hasOption('q')
            if (!quietMode && RunningMode.desktopSupportsBrowse && RunningMode.headlessMode) {
            if (!quietMode && RunningMode.desktopSupportsBrowse) {
                try {
                    log.info { "Trying to open your local web browser: $uri" }
                    Desktop.getDesktop().browse(uri)
@@ -123,10 +123,10 @@
            } else {
                if (quietMode) {
                    log.info("Server started in quiet mode (option -q). Please open your browser manually: $uri")
                } else if (!RunningMode.desktopSupportsBrowse) {
                    log.info("Desktop not available. Please open your browser manually: $uri")
                } else if (RunningMode.headlessMode) {
                    log.info("Desktop not available in headless mode. Please open your browser manually: $uri")
                } else if (!RunningMode.desktopSupportsBrowse) {
                    log.info("Desktop not available. Please open your browser manually: $uri")
                }
            }
        } catch (ex: ParseException) {
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/RunningMode.kt
@@ -10,7 +10,7 @@
    var webDevelopment: Boolean = false
        internal set
    val headlessMode: Boolean = System.getProperty("java.awt.headless") == "true"
    val desktopSupported = Desktop.isDesktopSupported()
    val desktopSupported = !headlessMode && Desktop.isDesktopSupported()
    val desktopSupportsBrowse = desktopSupported && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)
    @JvmStatic
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/ServerConfiguration.kt
@@ -3,10 +3,6 @@
import de.micromata.borgbutler.config.Configuration
import de.micromata.borgbutler.config.ConfigurationHandler.Companion.getConfiguration
import mu.KotlinLogging
import org.apache.commons.lang3.StringUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
private val log = KotlinLogging.logger {}
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ArchivesRest.kt
@@ -34,7 +34,6 @@
    /**
     * @param repoName      Name of repository ([Repository.getName].
     * @param archiveId     Id or name of archive.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return Repository (including list of archives) as json string.
     * @see JsonUtils.toJson
     */
@@ -42,14 +41,12 @@
    fun getArchive(
        @RequestParam("repo") repoName: String,
        @RequestParam("archiveId") archiveId: String,
        @RequestParam("force", required = false) force: Boolean,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean
    ): String {
        val archive: Archive = ButlerCache.getInstance().getArchive(repoName, archiveId, force == true)
        @RequestParam("force", required = false) force: Boolean?    ): Archive? {
        val archive = ButlerCache.getInstance().getArchive(repoName, archiveId, force == true)
        if (force == true) {
            ButlerCache.getInstance().deleteCachedArchiveContent(repoName, archiveId)
        }
        return JsonUtils.toJson(archive, prettyPrinter == true)
        return archive
    }
    /**
@@ -61,8 +58,7 @@
     * @param diffArchiveId                 If given, the differences between archiveId and diffArchiveId will be returned.
     * @param autoChangeDirectoryToLeafItem If given, this method will step automatically into single sub directories.
     * @param force                         If false (default), non cached file lists will not be loaded by borg.
     * @param prettyPrinter                 If true then the json output will be in pretty format.
     * @return Repository (including list of archives) as json string.
     * @return Repository (including list of archives) as json string or [{"mode": "notLoaded"}] if no file list loaded.
     * @see JsonUtils.toJson
     */
    @GetMapping("filelist")
@@ -74,8 +70,7 @@
        @RequestParam("maxResultSize", required = false) maxResultSize: String?,
        @RequestParam("diffArchiveId", required = false) diffArchiveId: String?,
        @RequestParam("autoChangeDirectoryToLeafItem", required = false) autoChangeDirectoryToLeafItem: Boolean?,
        @RequestParam("force", required = false) force: Boolean?,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
        @RequestParam("force", required = false) force: Boolean?
    ): String {
        val diffMode = StringUtils.isNotBlank(diffArchiveId)
        val maxSize = NumberUtils.toInt(maxResultSize, 50)
@@ -107,7 +102,7 @@
                return "[{\"mode\": \"notLoaded\"}]"
            }
        }
        return JsonUtils.toJson(items, prettyPrinter == true)
        return JsonUtils.toJson(items)
    }
    /**
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/BorgRepoConfigsRest.kt
@@ -18,17 +18,14 @@
class BorgRepoConfigsRest {
    /**
     * @param id            id or name of repo.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return [BorgRepoConfig] as json string.
     * @see JsonUtils.toJson
     */
    @GetMapping
    fun getRepoConfig(
        @RequestParam("id") id: String,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
    ): String {
        val repoConfig = ConfigurationHandler.getConfiguration().getRepoConfig(id)
        return JsonUtils.toJson(repoConfig, prettyPrinter == true)
        @RequestParam("id") id: String
    ): BorgRepoConfig? {
        return ConfigurationHandler.getConfiguration().getRepoConfig(id)
    }
    @PostMapping
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ConfigurationRest.kt
@@ -17,16 +17,12 @@
@RequestMapping("/rest/configuration")
class ConfigurationRest {
    /**
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @see JsonUtils.toJson
     */
    @GetMapping("config")
    fun getConfig(@RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?): String {
    fun getConfig(): ConfigurationInfo {
        val configurationInfo = ConfigurationInfo()
        configurationInfo.serverConfiguration = ServerConfiguration.get()
        configurationInfo.borgVersion = BorgInstallation.getInstance().getBorgVersion()
        return JsonUtils.toJson(configurationInfo, prettyPrinter)
        configurationInfo.borgVersion = BorgInstallation.getInstance().borgVersion
        return configurationInfo
    }
    @PostMapping("config")
@@ -41,25 +37,20 @@
        configurationHandler.save()
    }
    /**
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @see JsonUtils.toJson
     */
    @GetMapping("user")
    fun getUser(@RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?): String {
        val user: UserData = RestUtils.getUser()
        return JsonUtils.toJson(user, prettyPrinter)
    fun getUser(): UserData {
        return RestUtils.getUser()
    }
    @PostMapping("user")
    fun setUser(@RequestBody user: UserData) {
        if (user.getLocale() != null && StringUtils.isBlank(user.getLocale().getLanguage())) {
        if (user.locale?.language?.isBlank() == true) {
            // Don't set locale with "" as language.
            user.setLocale(null)
            user.locale = null
        }
        if (StringUtils.isBlank(user.getDateFormat())) {
        if (user.dateFormat?.isBlank() == true) {
            // Don't set dateFormat as "".
            user.setDateFormat(null)
            user.dateFormat = null
        }
        UserManager.instance().saveUser(user)
    }
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/I18nRest.kt
@@ -19,24 +19,20 @@
     * @param request For detecting the user's client locale.
     * @param locale If not given, the client's language (browser) will be used.
     * @param keysOnly If true, only the keys will be returned. Default is false.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @see JsonUtils.toJson
     */
    @GetMapping("list")
    fun getList(
        request: HttpServletRequest,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?,
        @RequestParam("keysOnly", required = false) keysOnly: Boolean?,
        @RequestParam("locale", required = false) locale: String?
    ): String {
    ): Map<String, String> {
        val localeObject: Locale?
        if (StringUtils.isNotBlank(locale)) {
            localeObject = Locale(locale)
        } else {
            localeObject = RestUtils.getUserLocale(request)
        }
        val translations: Map<String, String> =
            I18nClientMessages.getInstance().getAllMessages(localeObject, keysOnly == true)
        return JsonUtils.toJson(translations, prettyPrinter)
        return I18nClientMessages.getInstance().getAllMessages(localeObject, keysOnly == true)
    }
}
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/JacksonConfig.kt
New file
@@ -0,0 +1,36 @@
package de.micromata.borgbutler.server.rest
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import de.micromata.borgbutler.server.RunningMode
import mu.KotlinLogging
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
private val log = KotlinLogging.logger {}
@Configuration
open class JacksonConfig {
    private var objectMapper: ObjectMapper? = null
    @Bean
    @Primary
    open fun objectMapper(): ObjectMapper {
        objectMapper?.let {
            return it
        }
        val mapper = ObjectMapper()
        mapper.registerModule(KotlinModule())
        mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
        mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)
        val failOnUnknownJsonProperties = RunningMode.runningInIDE
        if (failOnUnknownJsonProperties) {
            log.warn("Unknown JSON properties are not allowed in REST call, due to configuration in projectforge.properties:projectforge.rest.json.failOnUnknownJsonProperties (OK, but Rest calls may fail).")
        }
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownJsonProperties) // Should be true in development mode!
        objectMapper = mapper
        return mapper
    }
}
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/JobsRest.kt
@@ -23,7 +23,6 @@
    /**
     * @param repo If given, only the job queue of the given repo will be returned.
     * @param testMode If true, then a test job list is created.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return Job queues as json string.
     * @see JsonUtils.toJson
     */
@@ -31,13 +30,12 @@
    fun getJobs(
        @RequestParam("repo", required = false) repo: String?,
        @RequestParam("testMode", required = false) testMode: Boolean?,
        @RequestParam("oldJobs", required = false) oldJobs: Boolean?,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
    ): String {
        @RequestParam("oldJobs", required = false) oldJobs: Boolean?
    ): List<JsonJobQueue> {
        log.debug("getJobs repo=$repo, oldJobs=$oldJobs")
        if (testMode == true) {
            // Return dynamic test queue:
            return returnTestList(oldJobs, prettyPrinter)
            return returnTestList(oldJobs)
        }
        var validRepo = false
        if (StringUtils.isNotBlank(repo) && "null" != repo && "undefined" != repo) {
@@ -46,19 +44,17 @@
        val borgQueueExecutor = BorgQueueExecutor.getInstance()
        val queueList = mutableListOf<JsonJobQueue>()
        if (validRepo) { // Get only the queue of the given repo:
            val queue = getQueue(repo, oldJobs)
            if (queue != null) {
                queueList.add(queue)
            getQueue(repo, oldJobs)?.let {
                queueList.add(it)
            }
        } else { // Get all the queues (of all repos).
            for (rep in borgQueueExecutor.getRepos()) {
                val queue = getQueue(rep, oldJobs)
                if (queue != null) {
                    queueList.add(queue)
            for (rep in borgQueueExecutor.repos) {
                getQueue(rep, oldJobs)?.let {
                    queueList.add(it)
                }
            }
        }
        return JsonUtils.toJson(queueList, prettyPrinter)
        return queueList
    }
    private fun getQueue(repo: String?, oldJobs: Boolean?): JsonJobQueue? {
@@ -66,12 +62,8 @@
        val repoConfig = ConfigurationHandler.getConfiguration().getRepoConfig(repo) ?: return null
        val borgJobList = borgQueueExecutor.getJobListCopy(repoConfig, oldJobs == true)
        if (CollectionUtils.isEmpty(borgJobList)) return null
        val queue: JsonJobQueue = JsonJobQueue().setRepo(repoConfig.getDisplayName())
        queue.setJobs(mutableListOf())
        for (borgJob in borgJobList) {
            val job = JsonJob(borgJob)
            queue.getJobs().add(job)
        }
        val queue: JsonJobQueue = JsonJobQueue().setRepo(repoConfig.displayName)
        queue.jobs = borgJobList.map { JsonJob(it) }
        return queue
    }
@@ -94,10 +86,9 @@
     * Only for test purposes and development.
     *
     * @param oldJobs
     * @param prettyPrinter
     * @return
     */
    private fun returnTestList(oldJobs: Boolean?, prettyPrinter: Boolean?): String {
    private fun returnTestList(oldJobs: Boolean?): List<JsonJobQueue> {
        var list = if (oldJobs == true) oldJobsTestList else testList
        if (list == null) {
            list = mutableListOf()
@@ -117,11 +108,11 @@
            }
        } else if (oldJobs != true) {
            for (jobQueue in list) {
                for (job in jobQueue.getJobs()) {
                    if (job.getStatus() != AbstractJob.Status.RUNNING) continue
                    var current: Long = job.getProgressInfo().getCurrent()
                    val total: Long = job.getProgressInfo().getTotal()
                    current += if (StringUtils.startsWith(job.getProgressInfo().getMessage(), "Calculating")) {
                for (job in jobQueue.jobs) {
                    if (job.status != AbstractJob.Status.RUNNING) continue
                    var current: Long = job.progressInfo.current
                    val total: Long = job.progressInfo.total
                    current += if (StringUtils.startsWith(job.progressInfo.message, "Calculating")) {
                        // Info is a faster operation:
                        (Math.random() * total / 5).toLong()
                    } else {
@@ -131,16 +122,16 @@
                    if (current > total) {
                        current = 0 // Reset to beginning.
                    }
                    job.getProgressInfo().setCurrent(current)
                    if (job.getProgressText().startsWith("Calculating")) {
                        job.getProgressInfo()
                            .setMessage("Calculating statistics...  " + Math.round((100 * current / total).toFloat()) + "%")
                    job.progressInfo.current = current
                    if (job.progressText.startsWith("Calculating")) {
                        job.progressInfo.message =
                            "Calculating statistics...  " + Math.round((100 * current / total).toFloat()) + "%"
                    }
                    job.buildProgressText()
                }
            }
        }
        return JsonUtils.toJson(list, prettyPrinter)
        return list
    }
    /**
@@ -169,28 +160,28 @@
            .setProgressInfo(progressInfo)
            .setStatus(AbstractJob.Status.QUEUED)
        if ("info" == operation) {
            progressInfo.setMessage("Calculating statistics... ")
            job.setDescription("Loading info of archive '" + host + "-2018-12-05T23:10:33' of repo '" + queue.getRepo() + "'.")
                .setCommandLineAsString("borg info --json --log-json --progress ssh://...:23/./backups/$host::$host-2018-12-05T23:10:33")
            progressInfo.message = "Calculating statistics... "
            job.setDescription("Loading info of archive '" + host + "-2018-12-05T23:10:33' of repo '" + queue.repo + "'.").commandLineAsString =
                "borg info --json --log-json --progress ssh://...:23/./backups/$host::$host-2018-12-05T23:10:33"
        } else {
            progressInfo.setMessage("Getting file list... ")
            job.setDescription("Loading list of files of archive '" + host + "-2018-12-05T17:30:38' of repo '" + queue.getRepo() + "'.")
                .setCommandLineAsString("borg list --json-lines ssh://...:23/./backups/$host::$host-2018-12-05T17:30:38")
            progressInfo.message = "Getting file list... "
            job.setDescription("Loading list of files of archive '" + host + "-2018-12-05T17:30:38' of repo '" + queue.repo + "'.").commandLineAsString =
                "borg list --json-lines ssh://...:23/./backups/$host::$host-2018-12-05T17:30:38"
        }
        job.buildProgressText()
        if (current >= 0) {
            job.setStatus(AbstractJob.Status.RUNNING)
            job.status = AbstractJob.Status.RUNNING
        } else {
            job.setStatus(AbstractJob.Status.QUEUED)
            job.status = AbstractJob.Status.QUEUED
        }
        if (queue.getJobs() == null) {
            queue.setJobs(ArrayList<JsonJob>())
        if (queue.jobs == null) {
            queue.jobs = ArrayList<JsonJob>()
        }
        job.setUniqueJobNumber(uniqueNumber)
        job.uniqueJobNumber = uniqueNumber
        if (oldJobs) {
            job.setStatus(if (uniqueNumber % 2 == 0L) AbstractJob.Status.CANCELLED else AbstractJob.Status.DONE)
            job.status = if (uniqueNumber % 2 == 0L) AbstractJob.Status.CANCELLED else AbstractJob.Status.DONE
        }
        queue.getJobs().add(job)
        queue.jobs.add(job)
        return job
    }
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/LoggingRest.kt
@@ -1,11 +1,10 @@
package de.micromata.borgbutler.server.rest
import de.micromata.borgbutler.json.JsonUtils
import de.micromata.borgbutler.server.logging.LoggerMemoryAppender
import de.micromata.borgbutler.server.logging.LogFilter
import de.micromata.borgbutler.server.logging.LogLevel
import de.micromata.borgbutler.server.logging.LoggerMemoryAppender
import de.micromata.borgbutler.server.logging.LoggingEventData
import mu.KotlinLogging
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
@@ -24,7 +23,6 @@
     * @param maxSize          Max size of the result list.
     * @param ascendingOrder   Default is false (default is descending order).
     * @param lastReceivedOrderNumber The last received order number for updating log entries (preventing querying all entries again).
     * @param prettyPrinter
     * @return
     */
    @GetMapping("query")
@@ -34,34 +32,33 @@
        @RequestParam("treshold", required = false) logLevelTreshold: String?,
        @RequestParam("maxSize", required = false) maxSize: Int?,
        @RequestParam("ascendingOrder", required = false) ascendingOrder: Boolean?,
        @RequestParam("lastReceivedOrderNumber", required = false) lastReceivedOrderNumber: Int?,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
    ): String {
        @RequestParam("lastReceivedOrderNumber", required = false) lastReceivedOrderNumber: Int?
    ): List<LoggingEventData> {
        val filter = LogFilter()
        filter.setSearch(search)
        filter.search = search
        if (logLevelTreshold != null) {
            try {
                val treshold =
                    LogLevel.valueOf(logLevelTreshold.trim { it <= ' ' }
                        .toUpperCase())
                filter.setThreshold(treshold)
                filter.threshold = treshold
            } catch (ex: IllegalArgumentException) {
                log.error("Can't parse log level treshold: " + logLevelTreshold + ". Supported values (case insensitive): " + LogLevel.getSupportedValues())
            }
        }
        if (filter.getThreshold() == null) {
            filter.setThreshold(LogLevel.INFO)
        if (filter.threshold == null) {
            filter.threshold = LogLevel.INFO
        }
        if (maxSize != null) {
            filter.setMaxSize(maxSize)
            filter.maxSize = maxSize
        }
        if (ascendingOrder != null && ascendingOrder == true) {
            filter.setAscendingOrder(true)
            filter.isAscendingOrder = true
        }
        if (lastReceivedOrderNumber != null) {
            filter.setLastReceivedLogOrderNumber(lastReceivedOrderNumber)
            filter.lastReceivedLogOrderNumber = lastReceivedOrderNumber
        }
        val loggerMemoryAppender = LoggerMemoryAppender.getInstance()
        return JsonUtils.toJson(loggerMemoryAppender.query(filter, RestUtils.getUserLocale(request!!)), prettyPrinter)
        return loggerMemoryAppender.query(filter, RestUtils.getUserLocale(request!!))
    }
}
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/ReposRest.kt
@@ -4,7 +4,6 @@
import de.micromata.borgbutler.data.Repository
import de.micromata.borgbutler.json.JsonUtils
import mu.KotlinLogging
import org.apache.commons.collections4.CollectionUtils
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
@@ -16,51 +15,40 @@
@RequestMapping("/rest/repos")
class ReposRest {
    /**
     *
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return A list of repositories of type [BorgRepository].
     * @see JsonUtils.toJson
     */
    @GetMapping("list")
    fun getList(@RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?): String {
        val repositories: List<Repository?> = ButlerCache.getInstance().getAllRepositories()
        return if (CollectionUtils.isEmpty(repositories)) {
            "[]"
        } else JsonUtils.toJson(repositories, prettyPrinter)
    fun getList(): List<Repository> {
        return ButlerCache.getInstance().allRepositories
    }
    /**
     *
     * @param id id or name of repo.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return [Repository] (without list of archives) as json string.
     * @see JsonUtils.toJson
     */
    @GetMapping("repo")
    fun getRepo(@RequestParam("id") id: String,
                @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?): String {
        val repository: Repository = ButlerCache.getInstance().getRepository(id)
        return JsonUtils.toJson(repository, prettyPrinter)
    fun getRepo(@RequestParam("id") id: String): Repository? {
        return ButlerCache.getInstance().getRepository(id)
    }
    /**
     *
     * @param id id or name of repo.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @return [Repository] (including list of archives) as json string.
     * @see JsonUtils.toJson
     */
    @GetMapping("repoArchiveList")
    fun getRepoArchiveList(
        @RequestParam("id") id: String,
        @RequestParam("force", required = false) force: Boolean?,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
    ): String {
        @RequestParam("force", required = false) force: Boolean?
    ): Repository? {
        if (force == true) {
            val repo: Repository = ButlerCache.getInstance().getRepository(id)
            ButlerCache.getInstance().clearRepoCacheAccess(repo)
        }
        val repository: Repository = ButlerCache.getInstance().getRepositoryArchives(id)
        return JsonUtils.toJson(repository, prettyPrinter)
        return ButlerCache.getInstance().getRepositoryArchives(id)
    }
}
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/SystemInfoRest.kt
@@ -16,9 +16,9 @@
     */
    @GetMapping("info")
    fun statistics(): SystemInfo {
        val borgVersion = BorgInstallation.getInstance().getBorgVersion()
        val borgVersion = BorgInstallation.getInstance().borgVersion
        val systemInfonfo = SystemInfo()
            .setQueueStatistics(BorgQueueExecutor.getInstance().getStatistics())
            .setQueueStatistics(BorgQueueExecutor.getInstance().statistics)
            .setConfigurationOK(borgVersion.isVersionOK)
            .setBorgVersion(borgVersion)
        return systemInfonfo
borgbutler-server/src/main/kotlin/de/micromata/borgbutler/server/rest/VersionRest.kt
@@ -6,7 +6,6 @@
import org.apache.commons.lang3.StringUtils
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.util.*
import javax.servlet.http.HttpServletRequest
@@ -17,28 +16,21 @@
    /**
     *
     * @param request For detecting the user's client locale.
     * @param prettyPrinter If true then the json output will be in pretty format.
     * @see JsonUtils.toJson
     */
    @GetMapping("version")
    fun getVersion(
        request: HttpServletRequest,
        @RequestParam("prettyPrinter", required = false) prettyPrinter: Boolean?
    ): String {
    fun getVersion(request: HttpServletRequest): MyVersion {
        val user = RestUtils.getUser()
        var language = Languages.asString(user.getLocale())
        if (StringUtils.isBlank(language)) {
            val locale: Locale = request.locale
            language = locale.getLanguage()
            language = locale.language
        }
        val version = MyVersion(language, RestUtils.checkLocalDesktopAvailable(request) == null)
        return JsonUtils.toJson(version, prettyPrinter)
        return MyVersion(language, RestUtils.checkLocalDesktopAvailable(request) == null)
    }
    inner class MyVersion(language: String, localDesktopAvailable: Boolean) {
        private val version: Version
        val language: String
        val isLocalDesktopAvailable: Boolean
    inner class MyVersion(val language: String, val localDesktopAvailable: Boolean) {
        private val version: Version = Version.getInstance()
        val appName: String
            get() = version.appName
@@ -57,10 +49,5 @@
        val updateVersion: String?
            get() = version.updateVersion
        init {
            version = Version.getInstance()
            this.language = language
            isLocalDesktopAvailable = localDesktopAvailable
        }
    }
}