[API/Idziennik] Add changing the selected student/register (web) to get grades in some cases.

This commit is contained in:
Kuba Szczodrzyński 2020-02-27 23:36:41 +01:00
parent 010f7fa1fe
commit 6a28dbd2c4
7 changed files with 80 additions and 6 deletions

View File

@ -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_URL = "https://iuczniowie.progman.pl/idziennik"
const val IDZIENNIK_WEB_LOGIN = "login.aspx" const val IDZIENNIK_WEB_LOGIN = "login.aspx"
const val IDZIENNIK_WEB_SETTINGS = "mod_panelRodzica/Ustawienia.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_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzPlanZajec"
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia" 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" const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"

View File

@ -113,6 +113,9 @@ object Regexes {
val IDZIENNIK_WEB_LUCKY_NUMBER by lazy { val IDZIENNIK_WEB_LUCKY_NUMBER by lazy {
"""dzisiaj to <b>([0-9]+)</b>""".toRegex() """dzisiaj to <b>([0-9]+)</b>""".toRegex()
} }
val IDZIENNIK_WEB_SELECTED_REGISTER by lazy {
"""selected="selected" value="([0-9]+)" data-id-ucznia""".toRegex()
}

View File

@ -81,6 +81,11 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth } get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth }
set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value } 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 }
/* _ /* _
/\ (_) /\ (_)
/ \ _ __ _ / \ _ __ _

View File

@ -13,6 +13,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik 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.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.io.File import java.io.File
@ -48,6 +49,17 @@ open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?)
return 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 { when {
response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED
response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR 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() .enqueue()
} }
fun webGet(tag: String, endpoint: String, onSuccess: (text: String) -> Unit) { fun webGet(tag: String, endpoint: String, parameters: Map<String, Any> = emptyMap(), onSuccess: (text: String) -> Unit) {
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint") d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
val callback = object : TextCallbackHandler() { val callback = object : TextCallbackHandler() {
@ -160,7 +172,14 @@ open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?)
Request.builder() Request.builder()
.url("$IDZIENNIK_WEB_URL/$endpoint") .url("$IDZIENNIK_WEB_URL/$endpoint")
.userAgent(IDZIENNIK_USER_AGENT) .userAgent(IDZIENNIK_USER_AGENT)
.get() .apply {
if (parameters.isEmpty()) get()
else post()
parameters.map { (name, value) ->
addParameter(name, value)
}
}
.callback(callback) .callback(callback)
.build() .build()
.enqueue() .enqueue()

View File

@ -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()
}
}
}

View File

@ -8,15 +8,12 @@ import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie import okhttp3.Cookie
import pl.szczodrzynski.edziennik.HOUR import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MINUTE
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.entity.Metadata 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.Utils
import pl.szczodrzynski.edziennik.utils.models.Date 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.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. */ 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 -> data.profile?.let { profile ->
Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also { Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
val number = it[1].toIntOrNull() ?: return@also val number = it[1].toIntOrNull() ?: return@also

View File

@ -43,10 +43,12 @@ class LoginStore(
fun getLoginData(key: String, defaultValue: Long) = data.getLong(key) ?: defaultValue 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: Float) = data.getFloat(key) ?: defaultValue
fun getLoginData(key: String, defaultValue: Char) = data.getChar(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: Boolean) { data[key] = value }
fun putLoginData(key: String, value: String?) { 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: Number) { data[key] = value }
fun putLoginData(key: String, value: Char) { 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 removeLoginData(key: String) { data.remove(key) }
fun copyFrom(args: Bundle) { fun copyFrom(args: Bundle) {