diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/HiwiTrackerMonthData.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/HiwiTrackerMonthData.kt index ea07693f48ce06de25e68409a18e9858f2a58478..58be99f037d0a212de795d3cb661178347fc91ff 100644 --- a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/HiwiTrackerMonthData.kt +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/HiwiTrackerMonthData.kt @@ -22,13 +22,13 @@ import kotlin.time.times @Serializable data class HiwiTrackerMonthData( - override val session: I11PortalData.Session, + override val session: PortalAPIResponse.Session, override val infos: List<String>, override val warnings: List<String>, override val errors: List<String>, override val navigation: JsonElement, @SerialName("ajaxui") - override val ajaxUI: I11PortalData.AjaxUI? = null, + override val ajaxUI: PortalAPIResponse.AjaxUI? = null, val calendar: Map<ISODate, CalendarEntry>, @SerialName("monthname") val monthName: String, @@ -51,7 +51,7 @@ data class HiwiTrackerMonthData( val reset: Boolean, @SerialName("hidedatecaption") val hideDateCaption: Boolean -) : I11PortalData { +) : PortalAPIResponse { @Serializable data class CalendarEntry( val disabled: Boolean, diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/I11PortalData.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/I11PortalData.kt deleted file mode 100644 index c68d11c26466d8ff371a0327d9319516ed69f7c9..0000000000000000000000000000000000000000 --- a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/I11PortalData.kt +++ /dev/null @@ -1,353 +0,0 @@ -package net.novagamestudios.kaffeekasse.model.i11_portal.api - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonElement - -interface I11PortalData { - val session: Session - val infos: List<String> - val warnings: List<String> - val errors: List<String> - val navigation: JsonElement - @SerialName("ajaxui") - val ajaxUI: AjaxUI? - @Serializable - data class Session( - val login: Boolean, - val user: String? = null, - @SerialName("displayname") - val displayName: String? = null - ) - @Serializable - data class AjaxUI( - val reload: Boolean? - ) -} - - -/* -{ - "session": { - "login": true, - "user": "broeckmann", - "displayname": "Jonas Broeckmann" - }, - "calendar": { - "2024-02-26": { - "disabled": true, - "day": 26, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-02-27": { - "disabled": true, - "day": 27, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-02-28": { - "disabled": true, - "day": 28, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-02-29": { - "disabled": true, - "day": 29, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-01": { - "disabled": false, - "day": 1, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-02": { - "disabled": false, - "day": 2, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-03": { - "disabled": false, - "day": 3, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-04": { - "disabled": false, - "day": 4, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-05": { - "disabled": false, - "day": 5, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-06": { - "disabled": false, - "day": 6, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-07": { - "disabled": false, - "day": 7, - "hasentry": true, - "vacation": false, - "holiday": false - }, - "2024-03-08": { - "disabled": false, - "day": 8, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-09": { - "disabled": false, - "day": 9, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-10": { - "disabled": false, - "day": 10, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-11": { - "disabled": false, - "day": 11, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-12": { - "disabled": false, - "day": 12, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-13": { - "disabled": false, - "day": 13, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-14": { - "disabled": false, - "day": 14, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-15": { - "disabled": false, - "day": 15, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-16": { - "disabled": false, - "day": 16, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-17": { - "disabled": false, - "day": 17, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-18": { - "disabled": false, - "day": 18, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-19": { - "disabled": false, - "day": 19, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-20": { - "disabled": false, - "day": 20, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-21": { - "disabled": false, - "day": 21, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-22": { - "disabled": false, - "day": 22, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-23": { - "disabled": false, - "day": 23, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-24": { - "disabled": false, - "day": 24, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-25": { - "disabled": false, - "day": 25, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-26": { - "disabled": false, - "day": 26, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-27": { - "disabled": false, - "day": 27, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-28": { - "disabled": false, - "day": 28, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-29": { - "disabled": false, - "day": 29, - "hasentry": false, - "vacation": false, - "holiday": "Karfreitag" - }, - "2024-03-30": { - "disabled": false, - "day": 30, - "hasentry": false, - "vacation": false, - "holiday": false - }, - "2024-03-31": { - "disabled": false, - "day": 31, - "hasentry": false, - "vacation": false, - "holiday": false - } - }, - "monthname": "März", - "today": "2024-03-08", - "nextmonthdate": "2024-04-01", - "prevmonthdate": "2024-02-01", - "selecteddate": null, - "entries": [ - { - "timetableentry_id": 71889, - "timetable_id": 463, - "date": "2024-03-07", - "begin": "10:00:00", - "end": "17:00:00", - "breaktime": "00:30:00", - "note": "psp_course_materials", - "hoursperday": "01:54:00.0000", - "name": "Broeckmann, Jonas", - "hrsweek": "09:30:00", - "hours_worked": "06:30:00.000000" - } - ], - "total_month": { - "timetable_id": 463, - "name": "Broeckmann, Jonas", - "date": "2024-03-01", - "hoursperweek": "09:30:00", - "hoursperday": "01:54:00.0000", - "workdays": 20, - "seconds_worked": 23400, - "holidays": 1, - "vacation_days": null, - "hours_worked": "06:30:00", - "hoursthismonth": "38:00:00.000000", - "hours_balance": "-31:30:00.000000", - "hours_balance_percent": -0.828947368, - "hours_balance_total_percent": -0.83 - }, - "total": { - "timetable_id": 463, - "hoursperweek": "08:30:00", - "hoursperday": "01:42:00.0000", - "workdays": 692, - "seconds_worked": 4492800, - "holidays": 26, - "last_reset": "03/2021", - "vacation_days": 43, - "date": "2024-02-29", - "hours_worked": "838:59:59", - "hours_balance": "04:48:00", - "hours_balance_percent": 1.403921568 - }, - "last_reset": { - "date": "2021-04-01" - }, - "overtime_expire": "00:00:00", - "holiday": false, - "reset": false, - "hidedatecaption": false, - "infos": [], - "warnings": [], - "errors": [], - "navigation": { - "Urlaub eintragen": { - "type": "link", - "action": "?vacations", - "subitems": [] - } - } -} - */ - - diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/PortalAPIResponse.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/PortalAPIResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..d701f992dd9ac0a88578f0aef86e789e1427bc25 --- /dev/null +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/PortalAPIResponse.kt @@ -0,0 +1,41 @@ +package net.novagamestudios.kaffeekasse.model.i11_portal.api + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import net.novagamestudios.kaffeekasse.model.i11_portal.api.PortalAPIResponse.* + +interface PortalAPIResponse { + @SerialName("session") + val session: Session + val infos: List<String> + val warnings: List<String> + val errors: List<String> + val navigation: JsonElement + @SerialName("ajaxui") + val ajaxUI: AjaxUI? + @Serializable + data class Session( + @SerialName("login") + val login: Boolean = false, + @SerialName("user") + val user: String? = null, + @SerialName("displayname") + val displayName: String? = null + ) + @Serializable + data class AjaxUI( + val reload: Boolean? + ) +} + +abstract class PortalAPIResponseBase : PortalAPIResponse { + override val session: Session = Session() + override val infos: List<String> = emptyList() + override val warnings: List<String> = emptyList() + override val errors: List<String> = emptyList() + override val navigation: JsonElement = JsonNull + override val ajaxUI: AjaxUI? = null +} + diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/DeviceAuthResponse.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/DeviceAuthResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..43faadc32e8fea8d15f109ca96d5b493cf56f64b --- /dev/null +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/DeviceAuthResponse.kt @@ -0,0 +1,18 @@ +package net.novagamestudios.kaffeekasse.model.kaffeekasse.api + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class DeviceAuthResponse( + val challenge: String? = null, + val name: String? = null, + @SerialName("item_type_id") + val itemTypeId: Int? = null +) + + + + + + diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/InfoResponse.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/InfoResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..d580a67213d54090985e74b803e2b4bd2af59dde --- /dev/null +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/InfoResponse.kt @@ -0,0 +1,66 @@ +package net.novagamestudios.kaffeekasse.model.kaffeekasse.api + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement + +@Serializable +data class UserListResponse( + @SerialName("user_list") + val userList: List<User> +) + +@Serializable +data class UserInfoResponse( + @SerialName("user_id") + val userId: Int, + val name: String, + val balance: Double, + val favorites: JsonArray = JsonArray(emptyList()), + val blacklist: List<User>? = null, + val whitelist: List<User>? = null +) + +@Serializable +data class User( + @SerialName("user_id") + val userId: Int, + val name: String, + @SerialName("empty_pin") + val noPinSet: Boolean? = null +) { + val firstName by lazy { name.split(", ")[1] } + val lastName by lazy { name.split(", ")[0] } +} + +@Serializable +data class ItemListResponse( + @SerialName("item_list") + val itemList: List<Item> +) { + @Serializable + data class Item( + @SerialName("item_id") + val itemId: Int, + val name: String, + val gtin: String? = null, + val price: Double, + @SerialName("image_url") + val imageUrl: String? = null, + val sort: Int, + @SerialName("sort_p") + val sortP: Int, + @SerialName("itemtype_id") + val itemTypeId: ItemTypeId, + val enabled: Boolean, + @SerialName("has_condition_reports") + val hasConditionReports: JsonElement + ) +} + +@Serializable +@JvmInline +value class ItemTypeId(val id: Int) + + diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPI.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPI.kt new file mode 100644 index 0000000000000000000000000000000000000000..f4606e0324f2e5aa8b016b02c17be445a13be15e --- /dev/null +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPI.kt @@ -0,0 +1,121 @@ +package net.novagamestudios.kaffeekasse.model.kaffeekasse.api + +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.forms.FormDataContent +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import io.ktor.client.statement.HttpResponse +import io.ktor.http.Parameters +import io.ktor.http.URLBuilder +import io.ktor.http.Url +import io.ktor.util.sha1 +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.decodeFromJsonElement +import net.novagamestudios.kaffeekasse.model.kaffeekasse.api.KaffeekasseAPIResponse.Error.Code as ErrorCode + +class KaffeekasseAPI( + private val apiUrl: Url, + private val client: HttpClient +) { + private val jsonFormat = Json { + ignoreUnknownKeys = true + isLenient = true + } + private inline fun <reified T> JsonElement.decode() = jsonFormat.decodeFromJsonElement<T>(this) + + private suspend fun invokeFunction(name: String, arguments: List<Pair<String, String>>): HttpResponse { + val functionUrl = URLBuilder(apiUrl).apply { + parameters.append(name, "") + }.build() + return client.post(functionUrl) { + setBody(FormDataContent(Parameters.build { arguments.forEach { (key, value) -> append(key, value) } })) + } + } + + private suspend inline fun <reified R> HttpResponse.parseResult( + validateLoggedIn: Boolean = true + ): Result<R> { + val raw = body<JsonElement>() + val response = raw.decode<KaffeekasseAPIResponse>() + return when { + response.hasError -> Result.Error(response) + validateLoggedIn && !response.session.login -> Result.NotLoggedIn(response) + else -> Result.Success(response, raw.decode<R>()) + } + } + + + suspend fun userList() = invokeFunction( + "user_list", + emptyList() + ).parseResult<UserListResponse>() + + suspend fun userInfo(userId: Int) = invokeFunction( + "user_info", + listOf("user_id" to "$userId") + ).parseResult<UserInfoResponse>() + + suspend fun itemList(itemTypeId: ItemTypeId? = null) = invokeFunction( + "item_list", + listOfNotNull(itemTypeId?.let { "item_type_id" to "${it.id}" }) + ).parseResult<ItemListResponse>() + + + + + private suspend fun loginDevice(deviceId: String, challengeResponse: String? = null) = invokeFunction( + "login_device", + listOfNotNull( + "id" to deviceId, + challengeResponse?.let { "response" to it } + ) + ).parseResult<DeviceAuthResponse>(validateLoggedIn = false) + + suspend fun performLogin(deviceId: String, apiKey: String): LoginResult { + // Phase 1 + val challenge = when (val response = loginDevice(deviceId)) { + is Result.Error -> when (response.errorCode) { + ErrorCode.InvalidFieldValue -> return LoginResult.Failure.InvalidDeviceId + ErrorCode.AccessDenied -> return LoginResult.Failure.AccessDenied + else -> return LoginResult.Failure.UnknownError(response.response) + } + is Result.NotLoggedIn -> throw AssertionError("Not logged in") + is Result.Success -> response.result.challenge + ?: return LoginResult.Failure.UnknownError(response.response) + } + + // Phase 2 (useless, but yolo) + val hash = sha1((challenge + apiKey).encodeToByteArray()).toString() + return when (val response = loginDevice(deviceId, hash)) { + is Result.Error -> when (response.errorCode) { + ErrorCode.AuthenticationFailure -> LoginResult.Failure.AuthenticationFailure + else -> LoginResult.Failure.UnknownError(response.response) + } + + is Result.NotLoggedIn -> throw AssertionError("Not logged in") + is Result.Success -> LoginResult.LoggedIn(response.result) + } + } + + sealed interface LoginResult { + sealed interface Failure : LoginResult { + data object InvalidDeviceId : LoginResult + data object AccessDenied : LoginResult + data object AuthenticationFailure : LoginResult + class UnknownError(val response: KaffeekasseAPIResponse) : LoginResult + } + class LoggedIn(val response: DeviceAuthResponse) : LoginResult + } + + sealed class Result<T>( + val response: KaffeekasseAPIResponse + ) { + val errorCode: ErrorCode? get() = response.error?.code + class Error<T>(response: KaffeekasseAPIResponse) : Result<T>(response) + class NotLoggedIn<T>(response: KaffeekasseAPIResponse) : Result<T>(response) + class Success<T>(response: KaffeekasseAPIResponse, val result: T) : Result<T>(response) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPIResponse.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPIResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..fa49d60dfbf84ae1ee149cf7a183cbc070af609d --- /dev/null +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseAPIResponse.kt @@ -0,0 +1,42 @@ +package net.novagamestudios.kaffeekasse.model.kaffeekasse.api + +import kotlinx.serialization.Serializable +import net.novagamestudios.kaffeekasse.model.i11_portal.api.PortalAPIResponseBase + + +@Serializable +data class KaffeekasseAPIResponse( + val error: Error? = null +) : PortalAPIResponseBase() { + @Serializable + data class Error( + val code: Code, + val string: String + ) { + @Serializable + @JvmInline + value class Code(val value: Long) { + companion object { + val NoError = Code(0) + val Unknown = Code(1) + val AccessDenied = Code(3) + val UnsupportedAuthMethod = Code(4) + val AuthenticationFailure = Code(5) + val MethodDisabled = Code(6) + val AuthenticationRequired = Code(7) + val InvalidFieldValue = Code(207) + val MissingFieldValue = Code(208) + val NotFound = Code(209) + val InvalidAction = Code(210) + val NotImplemented = Code(0xDEADBEEF) + val NoCodeYet = Code(0xEA7DEADBEEF) + } + } + val isError get() = code != Code.NoError + } + val hasError get() = error?.takeIf { it.isError } != null || errors.isNotEmpty() +} + + + + diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/KaffeekasseData.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseData.kt similarity index 85% rename from app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/KaffeekasseData.kt rename to app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseData.kt index 34a8dc79fcc43a90d66dcae69e517f9d133ed417..72f50268eb0447dd96c7f91c8d8f74bacb4fe9a8 100644 --- a/app/src/main/java/net/novagamestudios/kaffeekasse/model/i11_portal/api/KaffeekasseData.kt +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/model/kaffeekasse/api/KaffeekasseData.kt @@ -1,8 +1,9 @@ -package net.novagamestudios.kaffeekasse.model.i11_portal.api +package net.novagamestudios.kaffeekasse.model.kaffeekasse.api import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement +import net.novagamestudios.kaffeekasse.model.i11_portal.api.PortalAPIResponse /* {"session":{"login":false},"error":{"code":0,"string":"No error"},"infos":[],"warnings":[],"errors":["Login fehlgeschlagen."],"navigation":[]} @@ -22,22 +23,16 @@ import kotlinx.serialization.json.JsonElement */ @Serializable data class KaffeekasseData( - override val session: I11PortalData.Session, + override val session: PortalAPIResponse.Session, override val infos: List<String>, override val warnings: List<String>, override val errors: List<String>, override val navigation: JsonElement, - @SerialName("ajaxui") - override val ajaxUI: I11PortalData.AjaxUI? = null, - val error: Error? = null, + override val ajaxUI: PortalAPIResponse.AjaxUI? = null, + override val error: KaffeekasseAPIResponse.Error? = null, @SerialName("Kontostand") val balance: Balance? = null -) : I11PortalData { - @Serializable - data class Error( - val code: Int, - val string: String - ) +) : KaffeekasseAPIResponse { @Serializable data class Balance( @SerialName("mybalance") diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/I11Client.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/I11Client.kt index b4d8f26271c50d27cf380e314d3afb0d0ec1ba43..ad0b2c20ee5c03968bce2d716f1724bebcd3cce5 100644 --- a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/I11Client.kt +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/I11Client.kt @@ -60,9 +60,9 @@ import net.novagamestudios.common_utils.debug import net.novagamestudios.common_utils.info import net.novagamestudios.common_utils.warn import net.novagamestudios.kaffeekasse.model.kaffeekasse.Cart -import net.novagamestudios.kaffeekasse.model.i11_portal.api.I11PortalData +import net.novagamestudios.kaffeekasse.model.i11_portal.api.PortalAPIResponse import net.novagamestudios.kaffeekasse.model.i11_portal.api.HiwiTrackerMonthData -import net.novagamestudios.kaffeekasse.model.i11_portal.api.KaffeekasseData +import net.novagamestudios.kaffeekasse.model.kaffeekasse.api.KaffeekasseData import net.novagamestudios.kaffeekasse.model.kaffeekasse.KnownItem import net.novagamestudios.kaffeekasse.model.i11_portal.Login import net.novagamestudios.kaffeekasse.model.hiwi_tracker.MonthKey @@ -76,7 +76,6 @@ import net.novagamestudios.kaffeekasse.model.kaffeekasse.ManualBillDetails.ItemG import net.novagamestudios.kaffeekasse.model.kaffeekasse.Transaction import net.novagamestudios.kaffeekasse.model.kaffeekasse.isEmpty import net.novagamestudios.kaffeekasse.model.i11_portal.isValid -import net.novagamestudios.kaffeekasse.ui.hiwi_tracker.formatHiwiTracker import net.novagamestudios.kaffeekasse.util.RichData import net.novagamestudios.kaffeekasse.util.RichDataState import java.time.LocalDateTime @@ -180,7 +179,7 @@ class I11Client( } - abstract inner class Module<T : I11PortalData>( + abstract inner class Module<T : PortalAPIResponse>( val baseUrl: Url ) { val isLoggedIn get() = this@I11Client.isLoggedIn @@ -212,21 +211,21 @@ class I11Client( } } - inner class Portal : Module<I11PortalData>(Url("https://portal.embedded.rwth-aachen.de")) { - override suspend fun HttpResponse.toData(): I11PortalData { + inner class Portal : Module<PortalAPIResponse>(Url("https://portal.embedded.rwth-aachen.de")) { + override suspend fun HttpResponse.toData(): PortalAPIResponse { return body<I11PortalDataImpl>() } } @Serializable private data class I11PortalDataImpl( - override val session: I11PortalData.Session, + override val session: PortalAPIResponse.Session, override val infos: List<String>, override val warnings: List<String>, override val errors: List<String>, override val navigation: JsonElement, @SerialName("ajaxui") - override val ajaxUI: I11PortalData.AjaxUI? = null - ) : I11PortalData + override val ajaxUI: PortalAPIResponse.AjaxUI? = null + ) : PortalAPIResponse inner class Kaffeekasse : Module<KaffeekasseData>(Url("https://kaffeekasse.embedded.rwth-aachen.de")) { val manuaBillUrl = URLBuilder(baseUrl).apply { diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Account.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Account.kt index 382f50d31df46bce40df0813189f8942f87e8ed7..80bff50e0ec66deef67903987de50ecc3440faeb 100644 --- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Account.kt +++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Account.kt @@ -38,7 +38,7 @@ import net.novagamestudios.common_utils.compose.state.collectAsStateIn import net.novagamestudios.common_utils.format import net.novagamestudios.common_utils.warn import net.novagamestudios.kaffeekasse.App -import net.novagamestudios.kaffeekasse.model.i11_portal.api.KaffeekasseData +import net.novagamestudios.kaffeekasse.model.kaffeekasse.api.KaffeekasseData import net.novagamestudios.kaffeekasse.repositories.I11Client import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.FailureRetryScreen import net.novagamestudios.kaffeekasse.ui.util.PullToRefreshBox