diff --git a/app/src/main/java/dev/itsvic/parceltracker/api/USPSDeliveryService.kt b/app/src/main/java/dev/itsvic/parceltracker/api/USPSDeliveryService.kt new file mode 100644 index 0000000..c652d70 --- /dev/null +++ b/app/src/main/java/dev/itsvic/parceltracker/api/USPSDeliveryService.kt @@ -0,0 +1,105 @@ +package dev.itsvic.parceltracker.api + +import dev.itsvic.parceltracker.R +import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.coroutines.executeAsync +import android.util.Log +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi +import org.json.JSONObject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import retrofit2.Retrofit +import retrofit2.http.Body +import retrofit2.http.Path +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.POST +import java.time.LocalDateTime + +object USPSDeliveryService : DeliveryService { + override val nameResource: Int = R.string.service_usps + override val acceptsPostCode: Boolean = false + override val requiresPostCode: Boolean = false + + override suspend fun getParcel(trackingId: String, postCode: String?): Parcel { + // dummy stuff just so this compiles + return Parcel( + trackingId, + listOf(ParcelHistoryItem("", LocalDateTime.now(), "")), + Status.DeliveryFailure + ) + } + + private val retrofit = Retrofit.Builder().baseUrl("https://api.usps.com/").client(api_client) + .addConverterFactory(api_factory).build() + + private val service = retrofit.create(API::class.java) + + private interface API { + @POST("oauth2/v3/token") + suspend fun getOauthToken( + @Body data: GetOauthToken + ): OauthTokenResponse + + @GET("tracking/v3/tracking") + suspend fun getStatus( + @Path("trackingId") trackingId: String, + @Header("Authorization") authorization: String + ): StatusResponse + } + + @JsonClass(generateAdapter = true) + internal data class GetOauthToken( + // from https://developers.usps.com/Oauth + val clientId: String, + val clientSecret: String, + val grantType: String = "authorization_code", + val scopes: List = listOf("tracking"), + val tokenUrl: String = "https://apis.usps.com/oauth2/v3/token", + ) + + @JsonClass(generateAdapter = true) + internal data class OauthTokenResponse( + val oauthToken: String + ) + + @JsonClass(generateAdapter = true) + internal data class StatusResponse( + val expectedDeliveryDate: String, + val expectedDeliveryTime: String, + val guaranteedDeliveryDate: String, + val eventSummaries: List + ) + + @JsonClass(generateAdapter = true) + internal data class EventSummary( + val eventDescription: String + ) + +/* + @OptIn(ExperimentalCoroutinesApi::class) + private suspend fun getOauthToken(clientId: String, clientSecret: String): String { + + // this should work trust me + val tokenResp = service.getOauthToken() + + val request = Request.Builder().post(body).url(TOKEN_URL).build() + + api_client.newCall(request).executeAsync().use { response -> + Log.d("USPS", "Got Response") + var jsonWebToken = "" + if (response.code == 200) { + jsonWebToken = JSONObject(response.body.string()).optString("access_token", "") + Log.d("USPS", "Got Oauth2 token! $jsonWebToken") + // TODO: verify access token with provided public key + // if the USPS gets hacked we may have bigger problems on our hands than inaccurate package tracking + } else Log.d("USPS", "Couldn't get Oauth2 token ): response code was ${response.code}") + return jsonWebToken + } + }*/ +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 32aa6f3..973ed92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,4 +84,5 @@ API keys Ukrposhta GLS Hungary + USPS diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1a187b2..6402ddd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,7 @@ kotlinxSerializationJson = "1.7.3" room = "2.6.1" datastorePreferences = "1.1.4" retrofit = "2.11.0" +skrapeit = "1.2.2" work = "2.10.0" kotlinxCoroutinesGuava = "1.10.1" material3 = "1.4.0-alpha11" @@ -53,6 +54,7 @@ room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } converter-moshi = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "retrofit" } +skrapeit = { module = "it.skrape:skrapeit", version.ref = "skrapeit" } work-runtime = { group = "androidx.work", name = "work-runtime", version.ref = "work" } work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work" } kotlinx-coroutines-guava = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-guava", version.ref = "kotlinxCoroutinesGuava" }