[Vulcan/Hebe] Add API list helper. Separate student list code.

This commit is contained in:
Kuba Szczodrzyński 2021-02-20 20:11:54 +01:00
parent c7abde8f11
commit aef3f66654
6 changed files with 245 additions and 110 deletions

View File

@ -243,6 +243,11 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash } get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash }
set(value) { loginStore.putLoginData("hebePublicHash", value); mHebePublicHash = value } 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? val apiUrl: String?
get() { get() {
val url = when (apiToken[symbol]?.substring(0, 3)) { val url = when (apiToken[symbol]?.substring(0, 3)) {

View File

@ -2,6 +2,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
import android.os.Build import android.os.Build
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject import com.google.gson.JsonObject
import im.wangchao.mhttp.Request import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
@ -11,10 +12,14 @@ import io.github.wulkanowy.signer.hebe.getSignatureHeaders
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan 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.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.models.Date
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URLEncoder import java.net.URLEncoder
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.ZonedDateTime import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@ -35,7 +40,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
tag: String, tag: String,
endpoint: String, endpoint: String,
method: Int = GET, method: Int = GET,
payload: JsonObject? = null, payload: JsonElement? = null,
baseUrl: Boolean = false, baseUrl: Boolean = false,
crossinline onSuccess: (json: T, response: Response?) -> Unit 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("vDeviceModel", Build.MODEL)
.addHeader("vAPI", "1") .addHeader("vAPI", "1")
.apply { .apply {
if (data.hebeContext != null)
addHeader("vContext", data.hebeContext)
headers.forEach { headers.forEach {
addHeader(it.key, it.value) addHeader(it.key, it.value)
} }
@ -171,7 +178,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
inline fun <reified T> apiPost( inline fun <reified T> apiPost(
tag: String, tag: String,
endpoint: String, endpoint: String,
payload: JsonObject, payload: JsonElement,
baseUrl: Boolean = false, baseUrl: Boolean = false,
crossinline onSuccess: (json: T, response: Response?) -> Unit crossinline onSuccess: (json: T, response: Response?) -> Unit
) { ) {
@ -184,4 +191,56 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
onSuccess = onSuccess 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<String, String> = mapOf(),
includeFilterType: Boolean = true,
onSuccess: (data: List<JsonObject>, 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)
}
}
} }

View File

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

View File

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

View File

@ -4,7 +4,6 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin
import com.google.gson.JsonArray
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.* 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.VulcanApi
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe 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.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.CufsCertificate
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe 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) { private fun registerDeviceHebe(onSuccess: () -> Unit) {
VulcanLoginHebe(data) { VulcanLoginHebe(data) {
hebe.apiGet( VulcanHebeMain(data).getStudents(
TAG, profile = null,
VULCAN_HEBE_ENDPOINT_MAIN, profileList,
query = mapOf("lastSyncDate" to "null"),
baseUrl = true
) { students: JsonArray, _ ->
if (students.isEmpty()) {
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, loginStoreId,
LOGIN_TYPE_VULCAN, firstProfileId,
studentNameLong, onEmpty = {
userLogin, EventBus.getDefault()
studentNameLong, .postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore))
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 = onSuccess
)
} }
} }
} }

View File

@ -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.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.api.models.ApiError 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.getString
import pl.szczodrzynski.edziennik.isNotNullNorEmpty import pl.szczodrzynski.edziennik.isNotNullNorEmpty
@ -64,7 +63,7 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) {
} }
private fun loginWithToken() { private fun loginWithToken() {
val szkolnyApi = SzkolnyApi(data.app) //val szkolnyApi = SzkolnyApi(data.app)
val hebe = VulcanHebe(data, null) val hebe = VulcanHebe(data, null)
if (data.hebePublicKey == null || data.hebePrivateKey == null || data.hebePublicHash == 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 data.hebePublicHash = publicHash
} }
szkolnyApi.runCatching({ /*szkolnyApi.runCatching({
data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan") data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan")
}, onError = { }, onError = {
// screw errors // screw errors
}) })*/
hebe.apiPost( hebe.apiPost(
TAG, TAG,