Added retrieving API token from a local property or environment variable.

This commit is contained in:
Erik C. Thauvin 2017-11-08 01:03:22 -08:00
parent 87357f5127
commit e857d3d3aa
5 changed files with 139 additions and 39 deletions

View file

@ -17,7 +17,7 @@ poster.addPin("http://www.example.com/foo", "This is a test")
poster.deletePin("http:///www.example.com/bar") poster.deletePin("http:///www.example.com/bar")
``` ```
[View Example](https://github.com/ethauvin/pinboard-poster/blob/master/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt#L203) [View Example](https://github.com/ethauvin/pinboard-poster/blob/master/src/main/kotlin/net/thauvin/erik/pinboard/PinboardPoster.kt#L219)
### Java ### Java
```java ```java
@ -116,6 +116,46 @@ logger.setLevel(Level.FINE);
or using a logging properties file. or using a logging properties file.
## API Authentication Token
The token can also be located in a [properties file](https://en.wikipedia.org/wiki/.properties) or environment variable.
### Local Property
For example, using the default `PINBOARD_API_TOKEN` key value from a `local.properties` file:
```ini
# local.properties
PINBOARD_API_TOKEN=user\:TOKEN
```
```kotlin
val poster = PinboardPoster(Paths.get("local.properties"))
```
To specify your own key:
```ini
# my.properties
my.api.key=user\:TOKEN
```
```kotlin
val poster = PinboardPoster(Paths.get("my.properties"), "my.api.key")
```
### Environment Variable
If no arguments are passed to the constructor, the `PINBOARD_API_TOKEN` environment variable will be used, if any.
```sh
export PINBOARD_API_TOKEN="user:TOKEN"
```
```kotlin
val poster = PinboardPoster()
```
## API End Point ## API End Point
The API end point is automatically configured to `https://api.pinboard.in/v1/`. Since Pinboard uses the `del.ico.us` API, the library could potentially be used with another compatible service. To configure the API end point, use: The API end point is automatically configured to `https://api.pinboard.in/v1/`. Since Pinboard uses the `del.ico.us` API, the library could potentially be used with another compatible service. To configure the API end point, use:

View file

@ -11,9 +11,6 @@ import org.apache.maven.model.Developer
import org.apache.maven.model.License import org.apache.maven.model.License
import org.apache.maven.model.Model import org.apache.maven.model.Model
import org.apache.maven.model.Scm import org.apache.maven.model.Scm
import java.io.File
import java.io.FileInputStream
import java.util.*
val bs = buildScript { val bs = buildScript {
plugins("net.thauvin.erik:kobalt-versioneye:", "net.thauvin.erik:kobalt-maven-local:") plugins("net.thauvin.erik:kobalt-versioneye:", "net.thauvin.erik:kobalt-maven-local:")
@ -26,12 +23,6 @@ val p = project {
artifactId = name artifactId = name
version = "0.9.2" version = "0.9.2"
val localProperties = Properties().apply {
val f = "local.properties"
if (File(f).exists()) FileInputStream(f).use { fis -> load(fis) }
}
val apiToken = localProperties.getProperty("pinboard-api-token", "")
pom = Model().apply { pom = Model().apply {
description = project.description description = project.description
url = "https://github.com/ethauvin/pinboard-poster" url = "https://github.com/ethauvin/pinboard-poster"
@ -67,13 +58,13 @@ val p = project {
application { application {
mainClass = "net.thauvin.erik.pinboard.PinboardPosterKt" mainClass = "net.thauvin.erik.pinboard.PinboardPosterKt"
args(apiToken) ignoreErrorStream = true
} }
application { application {
taskName = "runJava" taskName = "runJava"
mainClass = "net.thauvin.erik.pinboard.JavaExample" mainClass = "net.thauvin.erik.pinboard.JavaExample"
args(apiToken) ignoreErrorStream = true
} }
install { install {

View file

@ -31,15 +31,52 @@
*/ */
package net.thauvin.erik.pinboard; package net.thauvin.erik.pinboard;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JavaExample { public class JavaExample {
public static void main(String[] args) { public static void main(String[] args) {
final String url = "http://www.example.com/pinboard"; final String url = "http://www.example.com/pinboard";
final PinboardPoster poster = new PinboardPoster(args[0]); final Path properties = Paths.get("local.properties");
final PinboardPoster poster;
if (args.length == 1) {
// API Token is an argument
poster = new PinboardPoster(args[0]);
} else if (Files.exists(properties)) {
// API Token is in local.properties (PINBOARD_API_TOKEN)
final Properties p = new Properties();
try (final InputStream stream = Files.newInputStream(properties)) {
p.load(stream);
} catch (IOException ignore) {
;
}
poster = new PinboardPoster(p);
} else {
// API Token is an environment variable (PINBOARD_API_TOKEN) or empty
poster = new PinboardPoster();
}
// Set logging levels
final ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINE);
final Logger logger = poster.getLogger();
logger.addHandler(consoleHandler);
logger.setLevel(Level.FINE);
// Add Pin
if (poster.addPin(url, "Testing", "Extended test", "test kotlin")) { if (poster.addPin(url, "Testing", "Extended test", "test kotlin")) {
System.out.println("Added: " + url); System.out.println("Added: " + url);
} }
// Delete Pin
if (poster.deletePin(url)) { if (poster.deletePin(url)) {
System.out.println("Deleted: " + url); System.out.println("Deleted: " + url);
} }

View file

@ -31,12 +31,16 @@
*/ */
package net.thauvin.erik.pinboard package net.thauvin.erik.pinboard
import net.thauvin.erik.pinboard.Constants.ENV_API_TOKEN
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.xml.sax.InputSource import org.xml.sax.InputSource
import java.io.StringReader import java.io.StringReader
import java.net.URL import java.net.URL
import java.nio.file.Files
import java.nio.file.Paths
import java.util.*
import java.util.logging.ConsoleHandler import java.util.logging.ConsoleHandler
import java.util.logging.Level import java.util.logging.Level
import java.util.logging.Logger import java.util.logging.Logger
@ -46,9 +50,21 @@ object Constants {
const val API_ENDPOINT = "https://api.pinboard.in/v1/" const val API_ENDPOINT = "https://api.pinboard.in/v1/"
const val AUTH_TOKEN = "auth_token" const val AUTH_TOKEN = "auth_token"
const val DONE = "done" const val DONE = "done"
const val ENV_API_TOKEN = "PINBOARD_API_TOKEN"
} }
open class PinboardPoster(var apiToken: String) { open class PinboardPoster() {
constructor(apiToken: String) : this() {
this.apiToken = apiToken
}
@JvmOverloads
constructor(properties: Properties, key: String = ENV_API_TOKEN) : this() {
this.apiToken = properties.getProperty(key, "")
}
var apiToken: String = if (System.getenv(ENV_API_TOKEN).isNullOrBlank()) "" else System.getenv(ENV_API_TOKEN)
var apiEndPoint: String = Constants.API_ENDPOINT var apiEndPoint: String = Constants.API_ENDPOINT
val logger: Logger by lazy { Logger.getLogger(PinboardPoster::class.java.simpleName) } val logger: Logger by lazy { Logger.getLogger(PinboardPoster::class.java.simpleName) }
@ -201,23 +217,37 @@ open class PinboardPoster(var apiToken: String) {
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
if (args.size == 1) { val url = "http://www.example.com/pinboard"
val url = "http://www.example.com/pinboard" val properties = Paths.get("local.properties")
val poster = PinboardPoster(args[0]) val poster = when {
args.size == 1 ->
// API Token is an argument
PinboardPoster(args[0])
Files.exists(properties) ->
// API Token is in a local.properties (PINBOARD_API_TOKEN)
PinboardPoster(
Properties().apply {
Files.newInputStream(properties).use { fis -> load(fis) }
}.getProperty(ENV_API_TOKEN, "")
)
else ->
// API Token is an environment variable (PINBOARD_API_TOKEN) or empty;
PinboardPoster()
}
with(poster.logger) { // Set logging levels
addHandler(ConsoleHandler().apply { level = Level.FINE }) with(poster.logger) {
level = Level.FINE addHandler(ConsoleHandler().apply { level = Level.FINE })
} level = Level.FINE
}
if (poster.addPin(url, "Testing", "Extended test", "test kotlin")) { // Add Pin
println("Added: $url") if (poster.addPin(url, "Testing", "Extended test", "test kotlin")) {
} println("Added: $url")
}
if (poster.deletePin(url)) { // Delete Pin
println("Deleted: $url") if (poster.deletePin(url)) {
} println("Deleted: $url")
} else {
println("Please specify a valid API token. (eg. user:TOKEN)")
} }
} }

View file

@ -41,16 +41,10 @@ class PinboardPosterTest {
private val url = "http://www.foo.com/" private val url = "http://www.foo.com/"
private val desc = "This is a test." private val desc = "This is a test."
private val localProps = Paths.get("local.properties") private val localProps = Paths.get("local.properties")
private val apiToken = if (Files.exists(localProps)) {
val p = Properties().apply { Files.newInputStream(localProps).use { fis -> load(fis) } }
p.getProperty("pinboard-api-token", "")
} else {
System.getenv("PINBOARD_API_TOKEN")
}
@Test @Test
fun testAddPin() { fun testAddPin() {
val poster = PinboardPoster("") var poster = PinboardPoster("")
Assert.assertFalse(poster.addPin(url, desc), "apiToken: <blank>") Assert.assertFalse(poster.addPin(url, desc), "apiToken: <blank>")
@ -60,13 +54,13 @@ class PinboardPosterTest {
//poster.apiToken = "foo:TESTING" //poster.apiToken = "foo:TESTING"
//Assert.assertFalse(poster.addPin(url, desc), "apiToken: ${poster.apiToken}") //Assert.assertFalse(poster.addPin(url, desc), "apiToken: ${poster.apiToken}")
poster.apiToken = apiToken poster = pinboardPosterInstance()
Assert.assertTrue(poster.addPin(url, desc), "apiToken: $apiToken") Assert.assertTrue(poster.addPin(url, desc), "apiToken: ${Constants.ENV_API_TOKEN}")
} }
@Test @Test
fun testDeletePin() { fun testDeletePin() {
val poster = PinboardPoster(apiToken) val poster = pinboardPosterInstance()
poster.apiEndPoint = "" poster.apiEndPoint = ""
Assert.assertFalse(poster.deletePin(url), "apiEndPoint: <blank>") Assert.assertFalse(poster.deletePin(url), "apiEndPoint: <blank>")
@ -76,4 +70,12 @@ class PinboardPosterTest {
Assert.assertFalse(poster.deletePin("foo.com"), "url: foo.com") Assert.assertFalse(poster.deletePin("foo.com"), "url: foo.com")
} }
private fun pinboardPosterInstance(): PinboardPoster {
return if (Files.exists(localProps)) {
PinboardPoster(Properties().apply { Files.newInputStream(localProps).use { fis -> load(fis) } })
} else {
PinboardPoster()
}
}
} }