Initial commit.
This commit is contained in:
commit
39faa04174
29 changed files with 1512 additions and 0 deletions
54
src/main/kotlin/net/thauvin/erik/jokeapi/Category.kt
Normal file
54
src/main/kotlin/net/thauvin/erik/jokeapi/Category.kt
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Category.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
/**
|
||||
* Categories and aliases.
|
||||
*/
|
||||
enum class Category(val value: String) {
|
||||
ANY("Any"),
|
||||
CHRISTMAS("Christmas"),
|
||||
DARK("Dark"),
|
||||
|
||||
MISC("Misc"),
|
||||
MISCELLANEOUS(MISC.value),
|
||||
|
||||
PROGRAMMING("Programming"),
|
||||
CODING(PROGRAMMING.value),
|
||||
DEVELOPMENT(PROGRAMMING.value),
|
||||
|
||||
PUN("Pun"),
|
||||
|
||||
SPOOKY("Spooky"),
|
||||
HALLOWEEN(SPOOKY.value)
|
||||
}
|
46
src/main/kotlin/net/thauvin/erik/jokeapi/Flag.kt
Normal file
46
src/main/kotlin/net/thauvin/erik/jokeapi/Flag.kt
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Flag.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
/**
|
||||
* Blacklist flags.
|
||||
*/
|
||||
enum class Flag(val value: String) {
|
||||
NSFW("nsfw"),
|
||||
RELIGIOUS("religious"),
|
||||
POLITICAL("political"),
|
||||
RACIST("racist"),
|
||||
SEXIST("sexist"),
|
||||
EXPLICIT("explicit"),
|
||||
ALL("${NSFW.value},${RELIGIOUS.value},${POLITICAL.value},${RACIST.value},${SEXIST.value},${EXPLICIT.value}"),
|
||||
}
|
40
src/main/kotlin/net/thauvin/erik/jokeapi/Format.kt
Normal file
40
src/main/kotlin/net/thauvin/erik/jokeapi/Format.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Format.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
/**
|
||||
* Response formats.
|
||||
*/
|
||||
enum class Format(val value: String) {
|
||||
JSON("json"), XML("xml"), YAML("yaml"), TEXT("txt"), TXT(TEXT.value)
|
||||
}
|
35
src/main/kotlin/net/thauvin/erik/jokeapi/IdRange.kt
Normal file
35
src/main/kotlin/net/thauvin/erik/jokeapi/IdRange.kt
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* IdRange.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
data class IdRange(val start: Int = -1, val end: Int = -1)
|
44
src/main/kotlin/net/thauvin/erik/jokeapi/Joke.kt
Normal file
44
src/main/kotlin/net/thauvin/erik/jokeapi/Joke.kt
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Joke.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
data class Joke(
|
||||
val error: Boolean,
|
||||
val category: Category,
|
||||
val type: Type,
|
||||
val joke: Set<String>,
|
||||
val flags: Set<Flag>,
|
||||
val id: Int,
|
||||
val safe: Boolean,
|
||||
val language: Language?
|
||||
)
|
266
src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt
Normal file
266
src/main/kotlin/net/thauvin/erik/jokeapi/JokeApi.kt
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* JokeApi.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.Logger
|
||||
import java.util.stream.Collectors
|
||||
|
||||
class JokeApi {
|
||||
companion object {
|
||||
private const val API_URL = "https://v2.jokeapi.dev/joke/"
|
||||
val logger: Logger = Logger.getLogger(JokeApi::class.java.simpleName)
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun apiCall(
|
||||
categories: Set<Category> = setOf(Category.ANY),
|
||||
language: Language = Language.ENGLISH,
|
||||
flags: Set<Flag> = emptySet(),
|
||||
type: Set<Type> = emptySet(),
|
||||
format: Format = Format.JSON,
|
||||
search: String = "",
|
||||
idRange: IdRange = IdRange(),
|
||||
amount: Int = 1,
|
||||
safe: Boolean = false,
|
||||
): String {
|
||||
val urlBuilder = StringBuilder(API_URL)
|
||||
val urlParams = mutableListOf<String>()
|
||||
|
||||
// Category
|
||||
if (!categories.contains(Category.ANY)) {
|
||||
urlBuilder.append(categories.stream().map(Category::value).collect(Collectors.joining(",")))
|
||||
} else {
|
||||
urlBuilder.append(Category.ANY.value)
|
||||
}
|
||||
|
||||
// Language
|
||||
if (language != Language.ENGLISH) {
|
||||
urlParams.add("lang=${language.value}")
|
||||
}
|
||||
|
||||
// Flags
|
||||
if (flags.isNotEmpty()) {
|
||||
if (flags.contains(Flag.ALL)) {
|
||||
urlParams.add("blacklistFlags=${Flag.ALL.value}")
|
||||
} else {
|
||||
urlParams.add(
|
||||
"blacklistFlags=" + flags.stream().map(Flag::value).collect(Collectors.joining(","))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Type
|
||||
if (type.isNotEmpty()) {
|
||||
urlParams.add("type=" + type.stream().map(Type::value).collect(Collectors.joining(",")))
|
||||
}
|
||||
|
||||
// Format
|
||||
if (format != Format.JSON) {
|
||||
urlParams.add("format=${format.value}")
|
||||
}
|
||||
|
||||
// Contains
|
||||
if (search.isNotBlank()) {
|
||||
urlParams.add("contains=${URLEncoder.encode(search, StandardCharsets.UTF_8)}")
|
||||
}
|
||||
|
||||
// Range
|
||||
if (idRange.start >= 0) {
|
||||
if (idRange.end == -1 || idRange.start == idRange.end) {
|
||||
urlParams.add("idRange=${idRange.start}")
|
||||
} else if (idRange.end > idRange.start) {
|
||||
urlParams.add("idRange=${idRange.start}-${idRange.end}")
|
||||
}
|
||||
}
|
||||
|
||||
// Amount
|
||||
if (amount in 2..10) {
|
||||
urlParams.add("amount=${amount}")
|
||||
}
|
||||
|
||||
// Safe
|
||||
if (safe) {
|
||||
urlParams.add("safe-mode")
|
||||
}
|
||||
|
||||
if (urlParams.isNotEmpty()) {
|
||||
urlBuilder.append('?')
|
||||
val it = urlParams.iterator()
|
||||
while (it.hasNext()) {
|
||||
urlBuilder.append(it.next())
|
||||
if (it.hasNext()) {
|
||||
urlBuilder.append("&")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fetchUrl(urlBuilder.toString())
|
||||
}
|
||||
|
||||
@Throws(JokeException::class, IOException::class)
|
||||
private fun fetchUrl(url: String) : String {
|
||||
logger.log(Level.FINE, url)
|
||||
|
||||
val connection = URL(url).openConnection() as HttpURLConnection
|
||||
connection.setRequestProperty(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0"
|
||||
)
|
||||
|
||||
if (connection.responseCode in 200..399) {
|
||||
val body = connection.inputStream.bufferedReader().readText()
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, body)
|
||||
}
|
||||
return body
|
||||
} else {
|
||||
when (connection.responseCode) {
|
||||
400 -> throw IOException(
|
||||
"400: Bad Request",
|
||||
IOException(
|
||||
"The request you have sent to JokeAPI is formatted incorrectly and cannot be" +
|
||||
" processed"
|
||||
)
|
||||
)
|
||||
|
||||
403 -> throw IOException(
|
||||
"4o3: Forbidden",
|
||||
IOException(
|
||||
"You have been added to the blacklist due to malicious behavior and are not allowed" +
|
||||
" to send requests to JokeAPI anymore"
|
||||
)
|
||||
)
|
||||
|
||||
404 -> throw IOException(
|
||||
"404: Not Found",
|
||||
IOException("The URL you have requested couldn't be found")
|
||||
)
|
||||
|
||||
413 -> throw IOException(
|
||||
"413: Payload Too Large",
|
||||
IOException("The payload data sent to the server exceeds the maximum size of 5120 bytes")
|
||||
)
|
||||
|
||||
428 -> throw IOException(
|
||||
"429: Too Many Requests",
|
||||
IOException(
|
||||
"You have exceeded the limit of 120 requests per minute and have to wait a bit" +
|
||||
" until you are allowed to send requests again"
|
||||
)
|
||||
)
|
||||
|
||||
500 -> throw IOException(
|
||||
"500: Internal Server Error",
|
||||
IOException(
|
||||
"There was a general internal error within JokeAPI. You can get more info from" +
|
||||
" the properties in the response text"
|
||||
)
|
||||
)
|
||||
|
||||
523 -> throw IOException(
|
||||
"523: Origin Unreachable",
|
||||
IOException(
|
||||
"The server is temporarily offline due to maintenance or a dynamic IP update." +
|
||||
" Please be patient in this case."
|
||||
)
|
||||
)
|
||||
|
||||
else -> throw IOException("${connection.responseCode}: Unknown Error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(JokeException::class, IOException::class)
|
||||
fun getJoke(
|
||||
categories: Set<Category> = setOf(Category.ANY),
|
||||
language: Language = Language.ENGLISH,
|
||||
flags: Set<Flag> = emptySet(),
|
||||
type: Set<Type> = emptySet(),
|
||||
search: String = "",
|
||||
idRange: IdRange = IdRange(),
|
||||
safe: Boolean = false
|
||||
): Joke {
|
||||
val json =
|
||||
JSONObject(apiCall(categories, language, flags, type, search = search, idRange = idRange, safe = safe))
|
||||
if (json.getBoolean("error")) {
|
||||
val causedBy = json.getJSONArray("causedBy")
|
||||
val causes = MutableList<String>(causedBy.length()) { i -> causedBy.getString(i) }
|
||||
|
||||
throw JokeException(
|
||||
error = true,
|
||||
internalError = json.getBoolean("internalError"),
|
||||
code = json.getInt("code"),
|
||||
message = json.getString("message"),
|
||||
causedBy = causes,
|
||||
additionalInfo = json.getString("additionalInfo"),
|
||||
timestamp = json.getLong("timestamp")
|
||||
)
|
||||
} else {
|
||||
val jokes = mutableSetOf<String>()
|
||||
if (json.has("setup")) {
|
||||
jokes.add(json.getString("setup"))
|
||||
jokes.add(json.getString(("delivery")))
|
||||
} else {
|
||||
jokes.addAll(json.getString("joke").split("\n"))
|
||||
}
|
||||
val enabledFlags = mutableSetOf<Flag>()
|
||||
val flagObject = json.getJSONObject("flags")
|
||||
for (flag in Flag.values()) {
|
||||
if (flag != Flag.ALL && flagObject.getBoolean(flag.value)) {
|
||||
enabledFlags.add(flag)
|
||||
}
|
||||
}
|
||||
return Joke(
|
||||
error = false,
|
||||
category = Category.valueOf(json.getString("category").uppercase()),
|
||||
type = Type.valueOf(json.getString("type").uppercase()),
|
||||
joke = jokes,
|
||||
flags = enabledFlags,
|
||||
safe = json.getBoolean("safe"),
|
||||
id = json.getInt("id"),
|
||||
language = Language.valueOf(json.getString("lang").uppercase())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
src/main/kotlin/net/thauvin/erik/jokeapi/JokeException.kt
Normal file
48
src/main/kotlin/net/thauvin/erik/jokeapi/JokeException.kt
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* JokeException.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
class JokeException @JvmOverloads constructor(
|
||||
val error: Boolean,
|
||||
val internalError: Boolean,
|
||||
val code: Int,
|
||||
message: String,
|
||||
val causedBy: List<String>,
|
||||
val additionalInfo: String,
|
||||
val timestamp: Long,
|
||||
cause: Throwable? = null
|
||||
) : Exception(message, cause) {
|
||||
companion object {
|
||||
private const val serialVersionUID = 1L
|
||||
}
|
||||
}
|
51
src/main/kotlin/net/thauvin/erik/jokeapi/Language.kt
Normal file
51
src/main/kotlin/net/thauvin/erik/jokeapi/Language.kt
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Language.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
/**
|
||||
* Supported languages.
|
||||
*/
|
||||
enum class Language(val value: String) {
|
||||
ENGLISH("en"),
|
||||
EN(ENGLISH.value),
|
||||
CZECH("cs"),
|
||||
CS(CZECH.value),
|
||||
GERMAN("de"),
|
||||
DE(GERMAN.value),
|
||||
SPANISH("es"),
|
||||
ES(SPANISH.value),
|
||||
FRENCH("fr"),
|
||||
FR(FRENCH.value),
|
||||
PORTUGUESE("pt"),
|
||||
PT(PORTUGUESE.value)
|
||||
}
|
41
src/main/kotlin/net/thauvin/erik/jokeapi/Type.kt
Normal file
41
src/main/kotlin/net/thauvin/erik/jokeapi/Type.kt
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Type.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
/**
|
||||
* Joke types.
|
||||
*/
|
||||
enum class Type(val value: String) {
|
||||
SINGLE("single"),
|
||||
TWOPART("twopart")
|
||||
}
|
174
src/test/kotlin/net/thauvin/erik/jokeapi/JokeApiTest.kt
Normal file
174
src/test/kotlin/net/thauvin/erik/jokeapi/JokeApiTest.kt
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* JokeApiTest.kt
|
||||
*
|
||||
* Copyright (c) 2022, 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.jokeapi
|
||||
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.apiCall
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.getJoke
|
||||
import net.thauvin.erik.jokeapi.JokeApi.Companion.logger
|
||||
import org.junit.jupiter.api.Assertions.assertAll
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.util.logging.ConsoleHandler
|
||||
import java.util.logging.Level
|
||||
|
||||
internal class JokeApiTest {
|
||||
@Test
|
||||
fun apiTxtCallTest() {
|
||||
val response = apiCall(format = Format.TEXT)
|
||||
logger.log(Level.FINE, response)
|
||||
assertAll("plain text",
|
||||
{ assertTrue(response.isNotEmpty(), "should be not empty") },
|
||||
{ assertFalse(response.startsWith("Error "), "should not be an error") }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun apiTxtErrorCallTest() {
|
||||
val response = apiCall(format = Format.TXT, idRange = IdRange(0, 30000))
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("Error "), "should be an error")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun apiXmlCallTest() {
|
||||
val response = apiCall(format = Format.XML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("<?xml version='1.0'?>\n<data>\n <error>false</error>"), "should be xml")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun apiYamlCallTest() {
|
||||
val response = apiCall(format = Format.YAML)
|
||||
logger.log(Level.FINE, response)
|
||||
assertTrue(response.startsWith("error: false"), "should be xml")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jokeExceptionTest() {
|
||||
try {
|
||||
getJoke(categories = setOf(Category.CHRISTMAS), search = "man")
|
||||
} catch (e: JokeException) {
|
||||
assertAll("exception validation",
|
||||
{ assertEquals(106, e.code, "code should be valid") },
|
||||
{ assertTrue(e.error, "should be an error") },
|
||||
{ assertFalse(e.internalError, "should not be internal error") },
|
||||
{ assertEquals("No matching joke found", e.message, "message should match") },
|
||||
{ assertEquals(1, e.causedBy.size, "causedby size should be 1") },
|
||||
{ assertTrue(e.additionalInfo.isNotEmpty(), "additional info should not be empty") },
|
||||
{ assertTrue(e.timestamp > 0, "timestamp should be > 0") }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getJokeTest() {
|
||||
val joke = getJoke()
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("no param",
|
||||
{ assertFalse(joke.error, "error should be false") },
|
||||
{ assertTrue(joke.joke.isNotEmpty(), "joke should not be empty") },
|
||||
{ assertTrue(joke.type == Type.TWOPART || joke.type == Type.SINGLE, "type should validate") },
|
||||
{ assertTrue(joke.id >= 0, "id should be >= 0") },
|
||||
{ assertEquals(Language.EN, joke.language, "language should be english") }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getJokeIdTest() {
|
||||
val id = 172
|
||||
val joke = getJoke(idRange = IdRange(id))
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("joke by id",
|
||||
{ assertTrue(joke.flags.contains(Flag.NSFW) && joke.flags.contains(Flag.EXPLICIT), "nsfw & explicit") },
|
||||
{ assertEquals(172, joke.id, "id is $id") },
|
||||
{ assertEquals(Category.PUN, joke.category, "category should be pun") }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getJokeIdRangeTest() {
|
||||
val idRange = IdRange(1, 100)
|
||||
val joke = getJoke(idRange = idRange)
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertTrue(joke.id >= idRange.start && joke.id <= idRange.end, "id should be in range")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSafeJokeTest() {
|
||||
val joke = getJoke(safe = true)
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("safe joke",
|
||||
{ assertTrue(joke.safe, "should be safe") },
|
||||
{ assertTrue(joke.flags.isEmpty(), "flags should be empty") }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSingleJokeTest() {
|
||||
val joke = getJoke(type = setOf(Type.SINGLE))
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertEquals(Type.SINGLE, joke.type, "type should be single")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTwoPartJokeTest() {
|
||||
val joke = getJoke(type = setOf(Type.TWOPART))
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertAll("two-part joke",
|
||||
{ assertEquals(Type.TWOPART, joke.type, "type should be two-part") },
|
||||
{ assertTrue(joke.joke.size > 1, "should have multiple lines") }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getJokeSearchTest() {
|
||||
val id = 1
|
||||
val joke = getJoke(search = "man", categories = setOf(Category.PROGRAMMING), idRange = IdRange(id), safe = true)
|
||||
logger.log(Level.FINE, joke.toString())
|
||||
assertEquals(id, joke.id, "id should be 1")
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@BeforeAll
|
||||
fun beforeAll() {
|
||||
with(logger) {
|
||||
addHandler(ConsoleHandler().apply { level = Level.FINE })
|
||||
level = Level.FINE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue