From 318409cb2f807f5ebcd71ce4582641fee04537f7 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 3 Mar 2020 13:34:32 -0800 Subject: [PATCH] Added CallResponse and Bitlinks.update(). --- detekt-baseline.xml | 8 ++ .../kotlin/net/thauvin/erik/bitly/Bitlinks.kt | 73 +++++++++++++++++-- .../kotlin/net/thauvin/erik/bitly/Bitly.kt | 2 +- .../net/thauvin/erik/bitly/CallResponse.kt | 47 ++++++++++++ .../net/thauvin/erik/bitly/Constants.kt | 20 ++++- .../kotlin/net/thauvin/erik/bitly/Utils.kt | 7 +- .../net/thauvin/erik/bitly/BitlyTest.kt | 17 +++-- 7 files changed, 155 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/net/thauvin/erik/bitly/CallResponse.kt diff --git a/detekt-baseline.xml b/detekt-baseline.xml index 962f3f4..a4f19c8 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -2,11 +2,19 @@ + ComplexMethod:Bitlinks.kt$Bitlinks$update ComplexMethod:Utils.kt$Utils.Companion$call FunctionParameterNaming:Bitlinks.kt$Bitlinks$bitlink_id: String + FunctionParameterNaming:Bitlinks.kt$Bitlinks$client_id: String = Constants.EMPTY + FunctionParameterNaming:Bitlinks.kt$Bitlinks$created_at: String = Constants.EMPTY + FunctionParameterNaming:Bitlinks.kt$Bitlinks$created_by: String = Constants.EMPTY + FunctionParameterNaming:Bitlinks.kt$Bitlinks$custom_bitlinks: Array<String> = emptyArray() FunctionParameterNaming:Bitlinks.kt$Bitlinks$group_guid: String = Constants.EMPTY FunctionParameterNaming:Bitlinks.kt$Bitlinks$long_url: String + FunctionParameterNaming:Bitlinks.kt$Bitlinks$long_url: String = Constants.EMPTY FunctionParameterNaming:Bitlinks.kt$Bitlinks$unit_reference: String = Constants.EMPTY + MagicNumber:CallResponse.kt$CallResponse$200 + MagicNumber:CallResponse.kt$CallResponse$299 NestedBlockDepth:Utils.kt$Utils.Companion$call NestedBlockDepth:Utils.kt$Utils.Companion$parseBody diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt b/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt index a9cf4ab..1639512 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Bitlinks.kt @@ -50,9 +50,9 @@ open class Bitlinks(private val accessToken: String) { * * See the [Bitly API](https://dev.bitly.com/v4/#operation/getClicksSummaryForBitlink) for more information. * - * @param bitlink The bitlink. - * @param unit A unit of time. - * @param units An integer representing the time units to query data for. pass -1 to return all units available. + * @param bitlink A Bitlink made of the domain and hash. + * @param unit A [unit of time][Units]. + * @param units An integer representing the time units to query data for. Pass -1 to return all units available. * @param size The quantity of items to be be returned. * @param unit_reference An ISO-8601 timestamp, indicating the most recent time for which to pull metrics. * Will default to current time. @@ -72,7 +72,7 @@ open class Bitlinks(private val accessToken: String) { if (bitlink.isNotBlank()) { val response = Utils.call( accessToken, - ("/bitlinks/" + bitlink.removeHttp() + "/clicks/summary").toEndPoint(), + ("/bitlinks/${bitlink.removeHttp()}/clicks/summary").toEndPoint(), hashMapOf( Pair("unit", unit.toString().toLowerCase()), Pair("units", units.toString()), @@ -156,14 +156,14 @@ open class Bitlinks(private val accessToken: String) { default } - private fun parseJsonResponse(response: String, key: String, default: String, toJson: Boolean): String { + private fun parseJsonResponse(response: CallResponse, key: String, default: String, toJson: Boolean): String { var parsed = default - if (response.isNotEmpty()) { + if (response.body.isNotEmpty()) { if (toJson) { - parsed = response + parsed = response.body } else { try { - parsed = JSONObject(response).getString(key, default) + parsed = JSONObject(response.body).getString(key, default) } catch (jse: JSONException) { Utils.logger.log(Level.SEVERE, "An error occurred parsing the response from Bitly.", jse) } @@ -208,4 +208,61 @@ open class Bitlinks(private val accessToken: String) { return bitlink } + + /** + * Updates fields in the Bitlink. + * + * See the [Bit.ly API](https://dev.bitly.com/v4/#operation/updateBitlink) for more information. + * + * @oaran bitlink A Bitlink made of the domain and hash. + * @param toJson Returns the full JSON response if `true` + * @return `true` is the update was successful, `false` otherwise, or JSON response. + */ + @JvmOverloads + fun update( + bitlink: String, + references: Map = emptyMap(), + archived: Boolean = false, + tags: Array = emptyArray(), + created_at: String = Constants.EMPTY, + title: String = Constants.EMPTY, + deeplinks: Array> = emptyArray(), + created_by: String = Constants.EMPTY, + long_url: String = Constants.EMPTY, + client_id: String = Constants.EMPTY, + custom_bitlinks: Array = emptyArray(), + link: String = Constants.EMPTY, + id: String = Constants.EMPTY, + toJson: Boolean = false + ): String { + var result = if (toJson) Constants.EMPTY_JSON else "false" + if (bitlink.isNotBlank()) { + val response = Utils.call( + accessToken, "/bitlinks/${bitlink.removeHttp()}".toEndPoint(), mutableMapOf().apply { + if (references.isNotEmpty()) put("references", references) + if (archived) put("archived", archived) + if (tags.isNotEmpty()) put("tags", tags) + if (created_at.isNotBlank()) put("created_at", created_at) + if (title.isNotBlank()) put("title", title) + if (deeplinks.isNotEmpty()) put("deeplinks", deeplinks) + if (created_by.isNotBlank()) put("created_by", created_by) + if (long_url.isNotBlank()) put("long_url", long_url) + if (client_id.isNotBlank()) put("client_id", client_id) + if (custom_bitlinks.isNotEmpty()) put("custom_bitlinks", custom_bitlinks) + if (link.isNotBlank()) put("link", link) + if (id.isNotBlank()) put("id", id) + }, + Methods.PATCH + ) + + if (response.isSuccessful) { + result = if (toJson) { + response.body + } else { + "true" + } + } + } + return result + } } diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Bitly.kt b/src/main/kotlin/net/thauvin/erik/bitly/Bitly.kt index ae24cf9..26b3165 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Bitly.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Bitly.kt @@ -114,7 +114,7 @@ open class Bitly() { * @return The response (JSON) from the API. */ @JvmOverloads - fun call(endPoint: String, params: Map = emptyMap(), method: Methods = Methods.POST): String { + fun call(endPoint: String, params: Map = emptyMap(), method: Methods = Methods.POST): CallResponse { return Utils.call(accessToken, endPoint, params, method) } } diff --git a/src/main/kotlin/net/thauvin/erik/bitly/CallResponse.kt b/src/main/kotlin/net/thauvin/erik/bitly/CallResponse.kt new file mode 100644 index 0000000..0038b7f --- /dev/null +++ b/src/main/kotlin/net/thauvin/erik/bitly/CallResponse.kt @@ -0,0 +1,47 @@ +/* + * Response.kt + * + * Copyright (c) 2020, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.bitly + +import org.json.JSONObject + +/** + * Provides a data class to hold the JSON response. + */ +data class CallResponse(var body: String = Constants.EMPTY_JSON, var resultCode: Int = -1) { + val isSuccessful: Boolean + get() = resultCode in 200..299 + + fun toJson(): JSONObject { + return JSONObject(body) + } +} diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Constants.kt b/src/main/kotlin/net/thauvin/erik/bitly/Constants.kt index d8466df..8669d83 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Constants.kt @@ -35,13 +35,15 @@ package net.thauvin.erik.bitly /** Provides the constants for this package. */ open class Constants private constructor() { companion object Constants { - /** The Bitly API base URL. + /** + * The Bitly API base URL. * * @value `https://api-ssl.bitly.com/v4` */ const val API_BASE_URL = "https://api-ssl.bitly.com/v4" - /** The API access token environment variable. + /** + * The API access token environment variable. * * @value `BITLY_ACCESS_TOKEN` */ @@ -52,5 +54,19 @@ open class Constants private constructor() { /** Empty JSON Object. */ const val EMPTY_JSON = "{}" + + /** + * False + * + * @value `false` + */ + const val FALSE = false.toString() + + /** + * True + * + * @value `true` + */ + const val TRUE = true.toString() } } diff --git a/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt b/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt index b6b1940..973efc9 100644 --- a/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt +++ b/src/main/kotlin/net/thauvin/erik/bitly/Utils.kt @@ -67,8 +67,8 @@ open class Utils private constructor() { endPoint: String, params: Map = emptyMap(), method: Methods = Methods.POST - ): String { - var response = Constants.EMPTY + ): CallResponse { + val response = CallResponse() if (validateCall(accessToken, endPoint)) { val apiUrl = endPoint.toHttpUrlOrNull() if (apiUrl != null) { @@ -99,7 +99,8 @@ open class Utils private constructor() { }.addHeader("Authorization", "Bearer $accessToken") val result = createHttpClient().newCall(builder.build()).execute() - response = parseBody(endPoint, result) + response.body = parseBody(endPoint, result) + response.resultCode = result.code } } return response diff --git a/src/test/kotlin/net/thauvin/erik/bitly/BitlyTest.kt b/src/test/kotlin/net/thauvin/erik/bitly/BitlyTest.kt index a3d209e..c6fd8bb 100644 --- a/src/test/kotlin/net/thauvin/erik/bitly/BitlyTest.kt +++ b/src/test/kotlin/net/thauvin/erik/bitly/BitlyTest.kt @@ -34,7 +34,6 @@ package net.thauvin.erik.bitly import net.thauvin.erik.bitly.Utils.Companion.removeHttp import net.thauvin.erik.bitly.Utils.Companion.toEndPoint -import org.json.JSONObject import org.junit.Before import java.io.File import java.util.logging.Level @@ -97,16 +96,16 @@ class BitlyTest { @Test fun `get user`() { - assertTrue(bitly.call("/user".toEndPoint(), method = Methods.GET).contains("\"login\":")) + assertTrue(bitly.call("/user".toEndPoint(), method = Methods.GET).isSuccessful) } @Test fun `created by`() { assertEquals( "ethauvin", - JSONObject( - bitly.call("/bitlinks/${shortUrl.removeHttp()}".toEndPoint(), method = Methods.GET) - ).getString("created_by") + bitly.call("/bitlinks/${shortUrl.removeHttp()}".toEndPoint(), method = Methods.GET) + .toJson() + .getString("created_by") ) } @@ -138,4 +137,12 @@ class BitlyTest { ) ) } + + @Test + fun `update bitlink`() { + assertEquals( + true.toString(), + bitly.bitlinks().update(shortUrl, title = "Erik's Weblog", tags = arrayOf("blog", "weblog")) + ) + } }