diff --git a/build.gradle b/build.gradle index 4b85d6e..9ba12dc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,16 @@ apply plugin: 'groovy' +apply plugin: 'application' group = "org.modelcatalogue" -version = "0.1-alpha7" +version = "0.1-alpha8" description = "Groovy Discourse API" +mainClassName = 'org.modelcatalogue.discourse.util.DelegatingMainClass' + +jar { + manifest { attributes 'Main-Class': 'org.modelcatalogue.discourse.util.DelegatingMainClass' } +} + repositories { jcenter() } @@ -89,3 +96,7 @@ task javadocJar(type: Jar, dependsOn: javadoc) { artifacts { archives sourcesJar, javadocJar } + +startScripts { + applicationName = 'discourse' +} diff --git a/src/main/groovy/org/modelcatalogue/discourse/api/Backups.groovy b/src/main/groovy/org/modelcatalogue/discourse/api/Backups.groovy index 6ba3f91..6e2eda6 100644 --- a/src/main/groovy/org/modelcatalogue/discourse/api/Backups.groovy +++ b/src/main/groovy/org/modelcatalogue/discourse/api/Backups.groovy @@ -1,5 +1,6 @@ package org.modelcatalogue.discourse.api +import groovyx.net.http.ContentType import org.modelcatalogue.discourse.Discourse class Backups { @@ -23,7 +24,71 @@ class Backups { } def downloadBackup(String filename) { - discourse.getClient("/admin/backups/${filename}").get([:]) + discourse.getClient("/admin/backups/${filename}").get(contentType: ContentType.BINARY) + } + + static void main(String... args) { + if (!args || args.size() < 2) { + println "Usage: \\ndiscourse backup path/to/file.propeties path/to/backups/folder" + } + + File propsFile = new File(args[0]) + + if (!propsFile.exists()) { + println "File ${propsFile.absolutePath} does not exist!" + return + } + + Properties props = new Properties() + propsFile.withReader { + props.load(it) + } + + for (String key in ['discourse.url', 'discourse.key', 'discourse.user']) { + if (!props.getProperty(key)) { + println "Property '${key}' is missing in property file ${propsFile.absolutePath}." + return + } + } + + File destFolder = new File(args[1]) + + if (!destFolder.exists()) { + destFolder.mkdirs() + } + + if (!destFolder.directory) { + println "Destination ${destFolder.absolutePath} is not a directory!" + return + } + + + + Discourse discourse = Discourse.create(props['discourse.url'].toString(), props['discourse.key'].toString(), props['discourse.user'].toString()) + + def backups = discourse.backups.backups.data + + if (!backups) { + println "There are no backups created yet. Have you set up the scheduler?" + return + } + + + + String filename = backups[0].filename + File downloaded = new File(destFolder, filename) + + if (downloaded.exists()) { + println "Backup ${downloaded.absolutePath} already exists. It will be replaced." + downloaded.delete() + } + + println "Downloading latest backup ${filename}" + + downloaded << discourse.backups.downloadBackup(filename).data + + println "Lates backup downloaded to ${downloaded.absolutePath}" + } } diff --git a/src/main/groovy/org/modelcatalogue/discourse/util/DelegatingMainClass.groovy b/src/main/groovy/org/modelcatalogue/discourse/util/DelegatingMainClass.groovy new file mode 100644 index 0000000..458bcce --- /dev/null +++ b/src/main/groovy/org/modelcatalogue/discourse/util/DelegatingMainClass.groovy @@ -0,0 +1,39 @@ +package org.modelcatalogue.discourse.util + +import org.modelcatalogue.discourse.api.Backups + +class DelegatingMainClass { + + private static Map delegates = [backup: Backups] + + static void main(String... args) { + if (!args) { + println """ + Usage: + discourse [args] + + Available commands: ${delegates.keySet().sort().join(', ')} + """.stripIndent() + return + } + + Class clazz = delegates[args[0]] + + if (!clazz) { + println """ + No such command '${args[0]}' + + Available commands: ${delegates.keySet().sort().join(', ')} + """.stripIndent() + return + } + + if (args.size() == 1) { + clazz.main([] as String[]) + } else { + clazz.main(args[1..-1] as String[]) + } + + } + +} diff --git a/src/test/groovy/org/modelcatalogue/discourse/Sandbox.groovy b/src/test/groovy/org/modelcatalogue/discourse/Sandbox.groovy index c0ec73a..6a1afca 100644 --- a/src/test/groovy/org/modelcatalogue/discourse/Sandbox.groovy +++ b/src/test/groovy/org/modelcatalogue/discourse/Sandbox.groovy @@ -1,57 +1,87 @@ package org.modelcatalogue.discourse import groovy.json.JsonOutput +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import org.modelcatalogue.discourse.api.Backups +import org.modelcatalogue.discourse.util.DelegatingMainClass import spock.lang.Ignore import spock.lang.Specification +@Ignore class Sandbox extends Specification { - Discourse discourse = Discourse.create 'http://192.168.1.114', 'af9402ba45b8f4aff5a84bcdf6da85fc7548db746026c5095ed652d0f83fcd8b', 'discourse' + @Rule TemporaryFolder temporaryFolder = new TemporaryFolder() - @Ignore - def "get some posts"() { - def topic = discourse.posts.createPost(14, """ - one two three four five six seven eight nine ten ${System.currentTimeMillis()} - """.stripIndent().trim()) + Discourse discourse = Discourse.create 'http://discourse.metadataregistry.org.uk/', '7b6d51fd026e18e3d96a868501f4890d4cff87a6de5f4cfb26778685de534622', 'admin' - println JsonOutput.prettyPrint(JsonOutput.toJson(topic.data)) + + def "download latest backup"() { + File testFolder = temporaryFolder.newFolder('backup-tests') + + File propFile = new File(testFolder, 'discourse.properties') + Properties props = new Properties() + props.setProperty('discourse.url', 'http://discourse.metadataregistry.org.uk/') + props.setProperty('discourse.key', 'xxx') + props.setProperty('discourse.user', 'admin') + propFile.withWriter { + props.store(it, 'Test properties file') + } + + File bkpDir = new File(testFolder, 'backups') + bkpDir.mkdirs() + + Backups.main(propFile.absolutePath, bkpDir.absolutePath) expect: - topic instanceof Reader - topic - topic.data instanceof Map - topic.status == 200 + bkpDir.listFiles().size() == 1 + bkpDir.listFiles()[0].name.endsWith('tar.gz') + bkpDir.listFiles()[0].size() > 100 + } - def "test searching"() { - def result = discourse.categories.getCategory('NHIC') + def "download latest backup (using delegating class)"() { + File testFolder = temporaryFolder.newFolder('backup-tests') - println JsonOutput.prettyPrint(JsonOutput.toJson(result.data)) + File propFile = new File(testFolder, 'discourse.properties') + Properties props = new Properties() + props.setProperty('discourse.url', 'http://discourse.metadataregistry.org.uk/') + props.setProperty('discourse.key', 'xxx') + props.setProperty('discourse.user', 'admin') + propFile.withWriter { + props.store(it, 'Test properties file') + } + + File bkpDir = new File(testFolder, 'backups') + bkpDir.mkdirs() + + DelegatingMainClass.main('backup', propFile.absolutePath, bkpDir.absolutePath) expect: - result + bkpDir.listFiles().size() == 1 + bkpDir.listFiles()[0].name.endsWith('tar.gz') + } - @Ignore - def "create topic with category"() { - def result = discourse.topics.createTopic( - "this is a cool title ${System.currentTimeMillis()}", - "this is ultracool post about nothing because I don't know what to write for ${System.currentTimeMillis()}", - "Catalogue Elements" - ) + def "download backup"() { + def result = discourse.backups.backups + + println JsonOutput.prettyPrint(JsonOutput.toJson(result.data)) expect: result - } + when: - @Ignore - def "verify user does not exist"() { - def result = discourse.users.getUser('otto_von_bahnhof') + File backupsDir = temporaryFolder.newFolder('discourse-backups') + backupsDir.mkdirs() - println JsonOutput.prettyPrint(JsonOutput.toJson(result.data)) + for (backup in result.data) { + def backupFile = discourse.backups.downloadBackup(backup.filename) + new File(backupsDir, backup.filename) << backupFile.data + } - expect: - result.status == 404 + then: + true } }