From aef3f66654cfe405e650f4d340e2aaaed3d16725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 20:11:54 +0100 Subject: [PATCH] [Vulcan/Hebe] Add API list helper. Separate student list code. --- .../data/api/edziennik/vulcan/DataVulcan.kt | 5 + .../api/edziennik/vulcan/data/VulcanHebe.kt | 63 ++++++- .../vulcan/data/hebe/HebeFilterType.kt | 7 + .../vulcan/data/hebe/VulcanHebeMain.kt | 157 ++++++++++++++++++ .../vulcan/firstlogin/VulcanFirstLogin.kt | 116 ++----------- .../edziennik/vulcan/login/VulcanLoginHebe.kt | 7 +- 6 files changed, 245 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index d494ec3d..1b70faff 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -243,6 +243,11 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash } set(value) { loginStore.putLoginData("hebePublicHash", value); mHebePublicHash = value } + private var mHebeContext: String? = null + var hebeContext: String? + get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext } + set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value } + val apiUrl: String? get() { val url = when (apiToken[symbol]?.substring(0, 3)) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index cd8a9b77..42e845f6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -2,6 +2,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import android.os.Build import com.google.gson.JsonArray +import com.google.gson.JsonElement import com.google.gson.JsonObject import im.wangchao.mhttp.Request import im.wangchao.mhttp.Response @@ -11,10 +12,14 @@ import io.github.wulkanowy.signer.hebe.getSignatureHeaders import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.utils.Utils.d +import pl.szczodrzynski.edziennik.utils.models.Date import java.net.HttpURLConnection import java.net.URLEncoder +import java.time.Instant +import java.time.LocalDateTime import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -35,7 +40,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { tag: String, endpoint: String, method: Int = GET, - payload: JsonObject? = null, + payload: JsonElement? = null, baseUrl: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { @@ -132,6 +137,8 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { .addHeader("vDeviceModel", Build.MODEL) .addHeader("vAPI", "1") .apply { + if (data.hebeContext != null) + addHeader("vContext", data.hebeContext) headers.forEach { addHeader(it.key, it.value) } @@ -171,7 +178,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { inline fun apiPost( tag: String, endpoint: String, - payload: JsonObject, + payload: JsonElement, baseUrl: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { @@ -184,4 +191,56 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { onSuccess = onSuccess ) } + + fun apiGetList( + tag: String, + endpoint: String, + filterType: HebeFilterType? = null, + dateFrom: Date? = null, + dateTo: Date? = null, + lastSync: Long? = null, + folder: Int? = null, + params: Map = mapOf(), + includeFilterType: Boolean = true, + onSuccess: (data: List, response: Response?) -> Unit + ) { + val url = if (includeFilterType && filterType != null) + "$endpoint/${filterType.endpoint}" + else endpoint + + val query = params.toMutableMap() + + when (filterType) { + HebeFilterType.BY_PUPIL -> { + // query["unitId"] = data.studentUnitId + query["pupilId"] = data.studentId.toString() + query["periodId"] = data.studentSemesterId.toString() + } + HebeFilterType.BY_PERSON -> { + query["loginId"] = data.studentLoginId.toString() + } + HebeFilterType.BY_PERIOD -> { + query["periodId"] = data.studentSemesterId.toString() + query["pupilId"] = data.studentId.toString() + } + } + + if (dateFrom != null) + query["dateFrom"] = dateFrom.stringY_m_d + if (dateTo != null) + query["dateTo"] = dateTo.stringY_m_d + + if (folder != null) + query["folder"] = folder.toString() + + query["lastId"] = "-2147483648" // don't ask, it's just Vulcan + query["pageSize"] = "500" + query["lastSyncDate"] = LocalDateTime + .ofInstant(Instant.ofEpochMilli(lastSync ?: 0), ZoneId.systemDefault()) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + + apiGet(tag, url, query) { json: JsonArray, response -> + onSuccess(json.map { it.asJsonObject }, response) + } + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt new file mode 100644 index 00000000..6734ab71 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt @@ -0,0 +1,7 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +enum class HebeFilterType(val endpoint: String) { + BY_PUPIL("byPupil"), + BY_PERSON("byPerson"), + BY_PERIOD("byPeriod") +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt new file mode 100644 index 00000000..4b37bf5e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -0,0 +1,157 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import com.google.gson.JsonArray +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MAIN +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_PUSH_CONFIG +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.utils.models.Date + +class VulcanHebeMain( + override val data: DataVulcan, + override val lastSync: Long? = null +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeMain" + } + + fun getStudents( + profile: Profile?, + profileList: MutableList?, + loginStoreId: Int? = null, + firstProfileId: Int? = null, + onEmpty: (() -> Unit)? = null, + onSuccess: () -> Unit + ) { + if (profile == null && (profileList == null || loginStoreId == null || firstProfileId == null)) + throw IllegalArgumentException() + + apiGet( + TAG, + VULCAN_HEBE_ENDPOINT_MAIN, + query = mapOf("lastSyncDate" to "null"), + baseUrl = profile == null + ) { students: JsonArray, _ -> + if (students.isEmpty()) { + if (onEmpty != null) + onEmpty() + else + onSuccess() + return@apiGet + } + + // safe to assume this will be non-null when creating a profile + var profileId = firstProfileId ?: loginStoreId ?: 1 + + students.forEach { studentEl -> + val student = studentEl.asJsonObject + + val pupil = student.getJsonObject("Pupil") + val studentId = pupil.getInt("Id") ?: return@forEach + + // check the student ID in case of not first login + if (profile != null && data.studentId != studentId) + return@forEach + + val unit = student.getJsonObject("Unit") + //val constituentUnit = student.getJsonObject("ConstituentUnit") + val login = student.getJsonObject("Login") + val periods = student.getJsonArray("Periods")?.map { + it.asJsonObject + } ?: listOf() + + val period = periods.firstOrNull { + it.getBoolean("Current", false) + } ?: return@forEach + + val periodLevel = period.getInt("Level") ?: return@forEach + val semester1 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 1 + } + val semester2 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 2 + } + + val schoolSymbol = unit.getString("Symbol") ?: return@forEach + val schoolShort = unit.getString("Short") ?: return@forEach + val schoolCode = "${data.symbol}_$schoolSymbol" + + val studentLoginId = login.getInt("Id") ?: return@forEach + //val studentClassId = student.getInt("IdOddzial") ?: return@forEach + val studentClassName = student.getString("ClassDisplay") ?: return@forEach + val studentFirstName = pupil.getString("FirstName") ?: "" + val studentLastName = pupil.getString("Surname") ?: "" + val studentNameLong = "$studentFirstName $studentLastName".fixName() + val studentNameShort = "$studentFirstName ${studentLastName[0]}.".fixName() + val userLogin = login.getString("Value") ?: "" + + val studentSemesterId = period.getInt("Id") ?: return@forEach + val studentSemesterNumber = period.getInt("Number") ?: return@forEach + + val hebeContext = student.getString("Context") + + val isParent = login.getString("LoginRole").equals("opiekun", ignoreCase = true) + val accountName = if (isParent) + login.getString("DisplayName")?.fixName() + else null + + val dateSemester1Start = semester1 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateSemester2Start = semester2 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateYearEnd = semester2 + ?.getJsonObject("End") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + + val newProfile = profile ?: Profile( + profileId++, + loginStoreId!!, + LOGIN_TYPE_VULCAN, + studentNameLong, + userLogin, + studentNameLong, + studentNameShort, + accountName + ) + + newProfile.apply { + this.studentClassName = studentClassName + studentData["symbol"] = data.symbol + + studentData["studentId"] = studentId + studentData["studentLoginId"] = studentLoginId + studentData["studentSemesterId"] = studentSemesterId + studentData["studentSemesterNumber"] = studentSemesterNumber + studentData["semester1Id"] = semester1?.getInt("Id") ?: 0 + studentData["semester2Id"] = semester2?.getInt("Id") ?: 0 + studentData["schoolSymbol"] = schoolSymbol + studentData["schoolShort"] = schoolShort + studentData["schoolName"] = schoolCode + studentData["hebeContext"] = hebeContext + } + dateSemester1Start?.let { + newProfile.dateSemester1Start = it + newProfile.studentSchoolYearStart = it.year + } + dateSemester2Start?.let { newProfile.dateSemester2Start = it } + dateYearEnd?.let { newProfile.dateYearEnd = it } + + if (profile != null) + data.setSyncNext(ENDPOINT_VULCAN_API_PUSH_CONFIG, SYNC_ALWAYS) + + profileList?.add(newProfile) + } + + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt index b670b12a..02d8b9bd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin -import com.google.gson.JsonArray import org.greenrobot.eventbus.EventBus import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* @@ -12,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanWebMain +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMain import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.CufsCertificate import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe @@ -210,110 +210,18 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { private fun registerDeviceHebe(onSuccess: () -> Unit) { VulcanLoginHebe(data) { - hebe.apiGet( - TAG, - VULCAN_HEBE_ENDPOINT_MAIN, - query = mapOf("lastSyncDate" to "null"), - baseUrl = true - ) { students: JsonArray, _ -> - if (students.isEmpty()) { - EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore)) + VulcanHebeMain(data).getStudents( + profile = null, + profileList, + loginStoreId, + firstProfileId, + onEmpty = { + EventBus.getDefault() + .postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore)) onSuccess() - return@apiGet - } - - students.forEach { studentEl -> - val student = studentEl.asJsonObject - - val unit = student.getJsonObject("Unit") - //val constituentUnit = student.getJsonObject("ConstituentUnit") - val pupil = student.getJsonObject("Pupil") - val login = student.getJsonObject("Login") - val periods = student.getJsonArray("Periods")?.map { - it.asJsonObject - } ?: listOf() - - val period = periods.firstOrNull { - it.getBoolean("Current", false) - } ?: return@forEach - - val periodLevel = period.getInt("Level") ?: return@forEach - val semester1 = periods.firstOrNull { - it.getInt("Level") == periodLevel && it.getInt("Number") == 1 - } - val semester2 = periods.firstOrNull { - it.getInt("Level") == periodLevel && it.getInt("Number") == 2 - } - - val schoolSymbol = unit.getString("Symbol") ?: return@forEach - val schoolShort = unit.getString("Short") ?: return@forEach - val schoolCode = "${data.symbol}_$schoolSymbol" - val studentId = pupil.getInt("Id") ?: return@forEach - val studentLoginId = login.getInt("Id") ?: return@forEach - //val studentClassId = student.getInt("IdOddzial") ?: return@forEach - val studentClassName = student.getString("ClassDisplay") ?: return@forEach - val studentFirstName = pupil.getString("FirstName") ?: "" - val studentLastName = pupil.getString("Surname") ?: "" - val studentNameLong = "$studentFirstName $studentLastName".fixName() - val studentNameShort = "$studentFirstName ${studentLastName[0]}.".fixName() - val userLogin = login.getString("Value") ?: "" - - val studentSemesterId = period.getInt("Id") ?: return@forEach - val studentSemesterNumber = period.getInt("Number") ?: return@forEach - - val isParent = login.getString("LoginRole").equals("opiekun", ignoreCase = true) - val accountName = if (isParent) - login.getString("DisplayName")?.fixName() - else null - - val dateSemester1Start = semester1 - ?.getJsonObject("Start") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - val dateSemester2Start = semester2 - ?.getJsonObject("Start") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - val dateYearEnd = semester2 - ?.getJsonObject("End") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - - val profile = Profile( - firstProfileId++, - loginStoreId, - LOGIN_TYPE_VULCAN, - studentNameLong, - userLogin, - studentNameLong, - studentNameShort, - accountName - ).apply { - this.studentClassName = studentClassName - studentData["symbol"] = data.symbol - - studentData["studentId"] = studentId - studentData["studentLoginId"] = studentLoginId - studentData["studentSemesterId"] = studentSemesterId - studentData["studentSemesterNumber"] = studentSemesterNumber - studentData["semester1Id"] = semester1?.getInt("Id") ?: 0 - studentData["semester2Id"] = semester2?.getInt("Id") ?: 0 - studentData["schoolSymbol"] = schoolSymbol - studentData["schoolShort"] = schoolShort - studentData["schoolName"] = schoolCode - } - dateSemester1Start?.let { - profile.dateSemester1Start = it - profile.studentSchoolYearStart = it.year - } - dateSemester2Start?.let { profile.dateSemester2Start = it } - dateYearEnd?.let { profile.dateYearEnd = it } - - profileList.add(profile) - } - - onSuccess() - } + }, + onSuccess = onSuccess + ) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt index b2c27454..750fd4ea 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt @@ -9,7 +9,6 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_REGISTER_NEW import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.isNotNullNorEmpty @@ -64,7 +63,7 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { } private fun loginWithToken() { - val szkolnyApi = SzkolnyApi(data.app) + //val szkolnyApi = SzkolnyApi(data.app) val hebe = VulcanHebe(data, null) if (data.hebePublicKey == null || data.hebePrivateKey == null || data.hebePublicHash == null) { @@ -74,11 +73,11 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { data.hebePublicHash = publicHash } - szkolnyApi.runCatching({ + /*szkolnyApi.runCatching({ data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan") }, onError = { // screw errors - }) + })*/ hebe.apiPost( TAG,