[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 }
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)) {

View File

@ -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 <reified T> 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<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
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
)
}
}
}

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.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,