From 6a28dbd2c46da353ff6428e95e71dcee7c89f4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 27 Feb 2020 23:36:41 +0100 Subject: [PATCH] [API/Idziennik] Add changing the selected student/register (web) to get grades in some cases. --- .../edziennik/data/api/Constants.kt | 1 + .../edziennik/data/api/Regexes.kt | 3 ++ .../api/edziennik/idziennik/DataIdziennik.kt | 5 +++ .../edziennik/idziennik/data/IdziennikWeb.kt | 23 ++++++++++-- .../data/web/IdziennikWebSwitchRegister.kt | 36 +++++++++++++++++++ .../idziennik/login/IdziennikLoginWeb.kt | 16 ++++++--- .../edziennik/data/db/entity/LoginStore.kt | 2 ++ 7 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 67313e67..4fba7d9b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -60,6 +60,7 @@ const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik" const val IDZIENNIK_WEB_LOGIN = "login.aspx" const val IDZIENNIK_WEB_SETTINGS = "mod_panelRodzica/Ustawienia.aspx" +const val IDZIENNIK_WEB_HOME = "mod_panelRodzica/StronaGlowna.aspx" const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzPlanZajec" const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia" const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt index d44df952..5a994156 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt @@ -113,6 +113,9 @@ object Regexes { val IDZIENNIK_WEB_LUCKY_NUMBER by lazy { """dzisiaj to ([0-9]+)""".toRegex() } + val IDZIENNIK_WEB_SELECTED_REGISTER by lazy { + """selected="selected" value="([0-9]+)" data-id-ucznia""".toRegex() + } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt index 972db8a1..5b5b11ab 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt @@ -81,6 +81,11 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data( get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth } set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value } + private var mWebSelectedRegister: Int? = null + var webSelectedRegister: Int + get() { mWebSelectedRegister = mWebSelectedRegister ?: loginStore.getLoginData("webSelectedRegister", 0); return mWebSelectedRegister ?: 0 } + set(value) { loginStore.putLoginData("webSelectedRegister", value); mWebSelectedRegister = value } + /* _ /\ (_) / \ _ __ _ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt index caa0e06e..907e1f50 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt @@ -13,6 +13,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik +import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSwitchRegister import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.utils.Utils.d import java.io.File @@ -48,6 +49,17 @@ open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) return } + if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GRADES) { + // special override for accounts where displaying grades + // for another student requires switching it manually + if (data.registerId != data.webSelectedRegister) { + IdziennikWebSwitchRegister(data, data.registerId) { + webApiGet(tag, endpoint, parameters, onSuccess) + } + return + } + } + when { response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR @@ -115,7 +127,7 @@ open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) .enqueue() } - fun webGet(tag: String, endpoint: String, onSuccess: (text: String) -> Unit) { + fun webGet(tag: String, endpoint: String, parameters: Map = emptyMap(), onSuccess: (text: String) -> Unit) { d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint") val callback = object : TextCallbackHandler() { @@ -160,7 +172,14 @@ open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) Request.builder() .url("$IDZIENNIK_WEB_URL/$endpoint") .userAgent(IDZIENNIK_USER_AGENT) - .get() + .apply { + if (parameters.isEmpty()) get() + else post() + + parameters.map { (name, value) -> + addParameter(name, value) + } + } .callback(callback) .build() .enqueue() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt new file mode 100644 index 00000000..f225f177 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt @@ -0,0 +1,36 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOME +import pl.szczodrzynski.edziennik.data.api.Regexes +import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik +import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb +import pl.szczodrzynski.edziennik.get +import pl.szczodrzynski.edziennik.getString + +class IdziennikWebSwitchRegister(override val data: DataIdziennik, + val registerId: Int, + val onSuccess: () -> Unit +) : IdziennikWeb(data, null) { + companion object { + private const val TAG = "IdziennikWebSwitchRegister" + } + + init { + val hiddenFields = data.loginStore.getLoginData("hiddenFields", JsonObject()) + // TODO error checking + + webGet(TAG, IDZIENNIK_WEB_HOME, mapOf( + "__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""), + "__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""), + "__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""), + "ctl00\$dxComboUczniowie" to registerId + )) { text -> + Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let { + val registerId = it[1].toIntOrNull() ?: return@let + data.webSelectedRegister = registerId + } + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt index 3cfc4899..1a9f6bc2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt @@ -8,15 +8,12 @@ import im.wangchao.mhttp.Request import im.wangchao.mhttp.Response import im.wangchao.mhttp.callback.TextCallbackHandler import okhttp3.Cookie -import pl.szczodrzynski.edziennik.HOUR -import pl.szczodrzynski.edziennik.MINUTE +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata -import pl.szczodrzynski.edziennik.get -import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.models.Date @@ -73,6 +70,17 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) { data.loginExpiryTime = response.getUnixDate() + 30 * MINUTE /* after about 40 minutes the login didn't work already */ data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */ + val hiddenFields = JsonObject() + Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach { + hiddenFields[it[1]] = it[2] + } + data.loginStore.putLoginData("hiddenFields", hiddenFields) + + Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let { + val registerId = it[1].toIntOrNull() ?: return@let + data.webSelectedRegister = registerId + } + data.profile?.let { profile -> Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also { val number = it[1].toIntOrNull() ?: return@also diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt index a7a1f442..1ec410b5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt @@ -43,10 +43,12 @@ class LoginStore( fun getLoginData(key: String, defaultValue: Long) = data.getLong(key) ?: defaultValue fun getLoginData(key: String, defaultValue: Float) = data.getFloat(key) ?: defaultValue fun getLoginData(key: String, defaultValue: Char) = data.getChar(key) ?: defaultValue + fun getLoginData(key: String, defaultValue: JsonObject) = data.getJsonObject(key) ?: defaultValue fun putLoginData(key: String, value: Boolean) { data[key] = value } fun putLoginData(key: String, value: String?) { data[key] = value } fun putLoginData(key: String, value: Number) { data[key] = value } fun putLoginData(key: String, value: Char) { data[key] = value } + fun putLoginData(key: String, value: JsonObject) { data[key] = value } fun removeLoginData(key: String) { data.remove(key) } fun copyFrom(args: Bundle) {