Tests pass but logging is still required

This commit is contained in:
2024-07-19 17:21:27 +01:00
parent 982b4e8d5d
commit 5bb6ccb789
20 changed files with 468 additions and 104 deletions

View File

@@ -1,26 +1,54 @@
package api
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
class BookerApi {
private val baseUrl = "https://restful-booker.herokuapp.com/"
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
var trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
}
override fun getAcceptedIssuers(): Array<X509Certificate?> {
return arrayOfNulls<X509Certificate>(0)
}
}
)
var gson = GsonBuilder()
.setLenient()
.create()
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
val builder = OkHttpClient.Builder()
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
builder
.addInterceptor(loggingInterceptor)
.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
return builder.build()
}
@@ -30,7 +58,7 @@ class BookerApi {
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(RestfulBookerApi::class.java)
}

View File

@@ -6,19 +6,15 @@ import retrofit2.http.*
interface RestfulBookerApi {
@Headers("Content-Type:application/json")
@Headers("Content-Type:application/json", "Accept: application/json")
@POST("auth")
suspend fun createAuthToken(
@Field("username") username: String,
@Field("password") password: String,
@Body authRequest: AuthRequest
): Response<AuthResponse>
@GET("booking")
suspend fun getBookingIds(
@Field("firstname") firstname: String? = null,
@Field("lastname") lastname: String? = null,
@Field("checkin") checkin: String? = null,
@Field("checkout") checkout: String? = null,
): Response<List<BookingIdResponse>>
@GET("booking/{id}")
@@ -26,7 +22,7 @@ interface RestfulBookerApi {
@Path("id") id: String
): Response<BookingResponse>
@Headers("Content-Type:application/json")
@Headers("Content-Type:application/json", "Accept: application/json")
@POST("booking")
suspend fun createBooking(
@Body booking: BookingRequest,
@@ -45,17 +41,12 @@ interface RestfulBookerApi {
suspend fun partialUpdateBooking(
@Path("id") id: String,
@Header("Authorization") token: String,
@Field("firstname") firstname: String? = null,
@Field("lastname") lastname: String? = null,
@Field("totalprice") totalprice: Float? = null,
@Field("depositpaid") depositpaid: Boolean? = null,
@Field("checkin") checkin: String? = null,
@Field("checkout") checkout: String? = null,
@Field("additionalneeds") additionalneeds: String? = null
@Body update: UpdateBookingRequest
): Response<BookingResponse>
@DELETE("booking/{id}")
suspend fun deleteBooking(
@Path("id") id: String
@Path("id") id: String,
@Header("Authorization") token: String
): Response<Any>
}

View File

@@ -0,0 +1,6 @@
package model
data class AuthRequest(
val username: String,
val password: String
)

View File

@@ -1,5 +1,5 @@
package model
class AuthResponse {
var token: String? = null
}
data class AuthResponse (
val token: String
)

View File

@@ -1,5 +1,5 @@
package model
class BookingIdResponse {
var bookingid = 0
}
data class BookingIdResponse(
val bookingid: Int
)

View File

@@ -1,12 +1,12 @@
package model
data class BookingRequest (
var firstname: String? = null,
var lastname: String? = null,
var totalprice: Int = 0,
var depositpaid: Boolean = false,
var bookingdates: Bookingdates? = null,
var additionalneeds: String? = null,
var firstname: String,
var lastname: String,
var totalprice: Int,
var depositpaid: Boolean,
var bookingdates: Bookingdates,
var additionalneeds: String,
)

View File

@@ -1,11 +1,11 @@
package model
data class BookingResponse (
var firstname: String? = null,
var lastname: String? = null,
var totalprice: Int = 0,
var depositpaid: Boolean = false,
var bookingdates: Bookingdates? = null,
var additionalneeds: String? = null
data class BookingResponse(
var firstname: String,
var lastname: String,
var totalprice: Int,
var depositpaid: Boolean,
var bookingdates: Bookingdates,
var additionalneeds: String
)

View File

@@ -1,6 +1,6 @@
package model
data class Bookingdates (
var checkin: String? = null,
var checkout: String? = null,
var checkin: String,
var checkout: String,
)

View File

@@ -1,6 +1,6 @@
package model
class CreateBookingResponse {
var bookingid = 0
var booking: BookingResponse? = null
}
data class CreateBookingResponse(
var bookingid: Int,
var booking: BookingResponse
)

View File

@@ -0,0 +1,10 @@
package model
data class UpdateBookingRequest(
var firstname: String? = null,
var lastname: String? = null,
var totalprice: Int? = null,
var depositpaid: Boolean? = null,
var bookingdates: Bookingdates? = null,
var additionalneeds: String? = null,
)

View File

@@ -0,0 +1,92 @@
package storage
import model.BookingResponse
import model.Bookingdates
class OrdersDatabase {
private val storage = mutableMapOf<Int, BookingResponse>()
// Create
fun insertBooking(id: Int, booking: BookingResponse) {
if (storage.contains(id)) {
storage.replace(id, booking)
} else {
storage[id] = booking
}
}
// Read
fun getIdsOfBookingsAvailable() = storage.keys.toList()
fun getBookingsAvailable() = storage.values.toList()
fun getIdsAndBookings() = storage.toMap()
fun getIdsOfOrderBasedOnValues(
firstname: String? = null,
lastname: String? = null,
totalprice: Int? = null,
depositpaid: Boolean? = null,
checkin: String? = null,
checkout: String? = null,
additionalneeds: String? = null
): List<Int> {
return storage.filterValues {
firstname?.let { f -> f == it.firstname } ?: true &&
lastname?.let { f -> f == it.lastname } ?: true &&
totalprice?.let { f -> f == it.totalprice } ?: true &&
depositpaid?.let { f -> f == it.depositpaid } ?: true &&
checkin?.let { f -> f == it.bookingdates.checkin } ?: true &&
checkout?.let { f -> f == it.bookingdates.checkout } ?: true &&
additionalneeds?.let { f -> f == it.additionalneeds } ?: true
}.keys.toList()
}
fun getIdsOfOrderBasedOnValues(
id: Int
): BookingResponse? {
return storage[id]
}
// Update
fun updateCompleteOrder(id: Int, newBookingResponse: BookingResponse) {
insertBooking(id, newBookingResponse)
}
fun updateOrderPartial(
id: Int,
firstname: String? = null,
lastname: String? = null,
totalprice: Int? = null,
depositpaid: Boolean? = null,
checkin: String? = null,
checkout: String? = null,
additionalneeds: String? = null
) {
if (storage.keys.remove(id)) {
storage.compute(id) { k, v ->
val mFirstName = firstname ?: v!!.firstname
val mlastname = lastname ?: v!!.lastname
val mTotalprice = totalprice ?: v!!.totalprice
val mDepositpaid = depositpaid ?: v!!.depositpaid
val mCheckin = checkin ?: v!!.bookingdates.checkin
val mCheckout = checkout ?: v!!.bookingdates.checkout
val mAdditionalneeds = additionalneeds ?: v!!.additionalneeds
BookingResponse(
firstname = mFirstName,
lastname = mlastname,
totalprice = mTotalprice,
depositpaid = mDepositpaid,
bookingdates = Bookingdates(
checkin = mCheckin,
checkout = mCheckout
),
additionalneeds = mAdditionalneeds
)
}
}
}
// Delete
fun clearAllData() = storage.clear()
fun deleteSingleEntry(id: Int) = storage.remove(id)
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Properties>
<Property name="basePath">C:\\logs</Property>
</Properties>
<Appenders>
<RollingFile name="fileLogger" fileName="${basePath}/app-info.html"
filePattern="${basePath}/app-info-%d{yyyy-MM-dd}.html">
<HTMLLayout charset="UTF-8" title="Howtodoinjava Info Logs" locationInfo="true" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="com.howtodoinjava" level="debug" additivity="false">
<appender-ref ref="fileLogger" level="debug" />
</Logger>
<Root level="debug" additivity="false">
<appender-ref ref="console" />
</Root>
</Loggers>
</Configuration>