[APIv2/Vulcan] Fix first login. Add Attendance, Proposed grades. Complete Dictionaries.

This commit is contained in:
Kuba Szczodrzyński 2019-11-01 21:21:25 +01:00
parent 38d0a173af
commit 0b211c4f12
10 changed files with 310 additions and 27 deletions

View File

@ -186,7 +186,6 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
lessonList.clear()
lessonChangeList.clear()
gradeCategories.clear()
gradeList.clear()
noticeList.clear()
attendanceList.clear()

View File

@ -178,6 +178,6 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
val fullApiUrl: String?
get() {
return "$apiUrl/$schoolSymbol/"
return "$apiUrl/$schoolSymbol"
}
}

View File

@ -6,10 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.vulcan.*
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiDictionaries
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiEvents
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiGrades
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiNotices
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.*
import pl.szczodrzynski.edziennik.utils.Utils
class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
@ -48,6 +45,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_grades)
VulcanApiGrades(data) { onSuccess() }
}
ENDPOINT_VULCAN_API_GRADES_SUMMARY -> {
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
VulcanApiProposedGrades(data) { onSuccess() }
}
ENDPOINT_VULCAN_API_EVENTS -> {
data.startProgress(R.string.edziennik_progress_endpoint_events)
VulcanApiEvents(data, isHomework = false) { onSuccess() }
@ -60,6 +61,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_notices)
VulcanApiNotices(data) { onSuccess() }
}
ENDPOINT_VULCAN_API_ATTENDANCE -> {
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
VulcanApiAttendance(data) { onSuccess() }
}
else -> onSuccess()
}
}

View File

@ -0,0 +1,78 @@
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_ATTENDANCE
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_ATTENDANCE
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.utils.models.Date
class VulcanApiAttendance(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
const val TAG = "VulcanApiAttendance"
}
init { data.profile?.also { profile ->
if (data.attendanceTypes.isEmpty()) {
data.db.attendanceTypeDao().getAllNow(profileId).toSparseArray(data.attendanceTypes) { it.id }
}
val startDate: String = profile.getSemesterStart(profile.currentSemester).stringY_m_d
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
apiGet(TAG, VULCAN_API_ENDPOINT_ATTENDANCE, parameters = mapOf(
"DataPoczatkowa" to startDate,
"DataKoncowa" to endDate,
"IdOddzial" to data.studentClassId,
"IdUczen" to data.studentId,
"IdOkresKlasyfikacyjny" to data.studentSemesterId
)) { json, _ ->
json.getJsonObject("Data")?.getJsonArray("Frekwencje")?.forEach { attendanceEl ->
val attendance = attendanceEl.asJsonObject
val attendanceCategory = data.attendanceTypes.get(attendance.getLong("IdKategoria") ?: return@forEach)
?: return@forEach
val type = attendanceCategory.type
val id = (attendance.getInt("Dzien") ?: 0) + (attendance.getInt("Numer") ?: 0)
val lessonDateMillis = Date.fromY_m_d(attendance.getString("DzienTekst")).inMillis
val lessonDate = Date.fromMillis(lessonDateMillis)
val lessonSemester = profile.dateToSemester(lessonDate)
val attendanceObject = Attendance(
profileId,
id.toLong(),
-1,
attendance.getLong("IdPrzedmiot") ?: -1,
lessonSemester,
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
lessonDate,
data.lessonRanges.get(attendance.getInt("IdPoraLekcji") ?: 0)?.startTime,
type)
data.attendanceList.add(attendanceObject)
if (attendanceObject.type != TYPE_PRESENT) {
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_ATTENDANCE,
attendanceObject.id,
profile.empty,
profile.empty,
attendanceObject.lessonDate.combineWith(attendanceObject.startTime)
))
}
}
data.setSyncNext(ENDPOINT_VULCAN_API_ATTENDANCE, SYNC_ALWAYS)
onSuccess()
}
} ?: onSuccess()}
}

View File

@ -5,17 +5,19 @@
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_DICTIONARIES
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_DICTIONARIES
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
import pl.szczodrzynski.edziennik.data.db.modules.attendance.AttendanceType
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeType
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Time
class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
@ -28,8 +30,12 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
elements?.getJsonArray("Pracownicy")?.forEach { saveTeacher(it.asJsonObject) }
elements?.getJsonArray("Przedmioty")?.forEach { saveSubject(it.asJsonObject) }
elements?.getJsonArray("PoryLekcji")?.forEach { saveLessonRange(it.asJsonObject) }
elements?.getJsonArray("KategorieOcen")?.forEach { saveGradeCategory(it.asJsonObject) }
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, SYNC_ALWAYS)
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4*DAY)
onSuccess()
}
}
@ -65,4 +71,87 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
data.subjectList.put(id, subjectObject)
}
private fun saveLessonRange(lessonRange: JsonObject) {
val lessonNumber = lessonRange.getInt("Id") ?: return
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
val lessonRangeObject = LessonRange(
profileId,
lessonNumber,
startTime,
endTime
)
data.lessonRanges.put(lessonNumber, lessonRangeObject)
}
private fun saveGradeCategory(gradeCategory: JsonObject) {
val id = gradeCategory.getLong("Id") ?: return
val name = gradeCategory.getString("Nazwa") ?: ""
val gradeCategoryObject = GradeCategory(
profileId,
id,
0.0f,
-1,
name
)
data.gradeCategories.put(id, gradeCategoryObject)
}
private fun saveNoticeType(noticeType: JsonObject) {
val id = noticeType.getLong("Id") ?: return
val name = noticeType.getString("Nazwa") ?: ""
val noticeTypeObject = NoticeType(
profileId,
id,
name
)
data.noticeTypes.put(id, noticeTypeObject)
}
private fun saveAttendanceType(attendanceType: JsonObject) {
val id = attendanceType.getLong("Id") ?: return
val name = attendanceType.getString("Nazwa") ?: ""
val absent = attendanceType.getBoolean("Nieobecnosc") ?: false
val excused = attendanceType.getBoolean("Usprawiedliwione") ?: false
val type = if (absent) {
if (excused)
Attendance.TYPE_ABSENT_EXCUSED
else
Attendance.TYPE_ABSENT
}
else {
val belated = attendanceType.getBoolean("Spoznienie") ?: false
val released = attendanceType.getBoolean("Zwolnienie") ?: false
val present = attendanceType.getBoolean("Obecnosc") ?: true
if (belated)
if (excused)
Attendance.TYPE_ABSENT_EXCUSED
else
Attendance.TYPE_ABSENT
else if (released)
Attendance.TYPE_RELEASED
else if (present)
Attendance.TYPE_PRESENT
else
Attendance.TYPE_CUSTOM
}
val attendanceTypeObject = AttendanceType(
profileId,
id,
name,
type,
-1
)
data.attendanceTypes.put(id, attendanceTypeObject)
}
}

View File

@ -24,12 +24,25 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
const val TAG = "VulcanApiEvents"
}
init {
init { data.profile?.also { profile ->
val startDate: String = when (profile.empty) {
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
}
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
val endpoint = when (isHomework) {
true -> VULCAN_API_ENDPOINT_HOMEWORK
else -> VULCAN_API_ENDPOINT_EVENTS
}
apiGet(TAG, endpoint) { json, _ ->
apiGet(TAG, endpoint, parameters = mapOf(
"DataPoczatkowa" to startDate,
"DataKoncowa" to endDate,
"IdOddzial" to data.studentClassId,
"IdUczen" to data.studentId,
"IdOkresKlasyfikacyjny" to data.studentSemesterId
)) { json, _ ->
val events = json.getJsonArray("Data")
events?.forEach { eventEl ->
@ -71,8 +84,8 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
profileId,
if (isHomework) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
id,
profile?.empty ?: false,
profile?.empty ?: false,
profile.empty,
profile.empty,
System.currentTimeMillis()
))
}
@ -83,5 +96,5 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
}
onSuccess()
}
}
} ?: onSuccess()}
}

View File

@ -20,8 +20,12 @@ class VulcanApiGrades(override val data: DataVulcan, val onSuccess: () -> Unit)
const val TAG = "VulcanApiGrades"
}
init {
apiGet(TAG, VULCAN_API_ENDPOINT_GRADES) { json, _ ->
init { data.profile?.also { profile ->
apiGet(TAG, VULCAN_API_ENDPOINT_GRADES, parameters = mapOf(
"IdUczen" to data.studentId,
"IdOkresKlasyfikacyjny" to data.studentSemesterId
)) { json, _ ->
val grades = json.getJsonArray("Data")
grades?.forEach { gradeEl ->
@ -108,5 +112,5 @@ class VulcanApiGrades(override val data: DataVulcan, val onSuccess: () -> Unit)
data.setSyncNext(ENDPOINT_VULCAN_API_GRADES, SYNC_ALWAYS)
onSuccess()
}
}
} ?: onSuccess()}
}

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
import androidx.core.util.isEmpty
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_NOTICES
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_NOTICES
@ -14,15 +15,23 @@ import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.toSparseArray
import pl.szczodrzynski.edziennik.utils.models.Date
class VulcanApiNotices(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
const val TAG = "VulcanApi"
const val TAG = "VulcanApiNotices"
}
init {
apiGet(TAG, VULCAN_API_ENDPOINT_NOTICES) { json, _ ->
init { data.profile?.also { profile ->
if (data.noticeTypes.isEmpty()) {
data.db.noticeTypeDao().getAllNow(profileId).toSparseArray(data.noticeTypes) { it.id }
}
apiGet(TAG, VULCAN_API_ENDPOINT_NOTICES, parameters = mapOf(
"IdUczen" to data.studentId,
"IdOkresKlasyfikacyjny" to data.studentSemesterId
)) { json, _ ->
json.getJsonArray("Data")?.forEach { noticeEl ->
val notice = noticeEl.asJsonObject
@ -35,7 +44,7 @@ class VulcanApiNotices(override val data: DataVulcan, val onSuccess: () -> Unit)
profileId,
id,
text,
profile!!.currentSemester,
profile.currentSemester,
Notice.TYPE_NEUTRAL,
teacherId
)
@ -45,8 +54,8 @@ class VulcanApiNotices(override val data: DataVulcan, val onSuccess: () -> Unit)
profileId,
Metadata.TYPE_NOTICE,
id,
profile?.empty ?: false,
profile?.empty ?: false,
profile.empty,
profile.empty,
addedDate
))
}
@ -54,5 +63,5 @@ class VulcanApiNotices(override val data: DataVulcan, val onSuccess: () -> Unit)
data.setSyncNext(ENDPOINT_VULCAN_API_NOTICES, SYNC_ALWAYS)
onSuccess()
}
}
} ?: onSuccess()}
}

View File

@ -0,0 +1,81 @@
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
import com.google.gson.JsonArray
import pl.szczodrzynski.edziennik.HOUR
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_GRADES_SUMMARY
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.asJsonObjectList
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
import pl.szczodrzynski.edziennik.getJsonArray
import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.utils.Utils
class VulcanApiProposedGrades(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
companion object {
const val TAG = "VulcanApiProposedGrades"
}
init { data.profile?.also { profile ->
apiGet(TAG, VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS, parameters = mapOf(
"IdUczen" to data.studentId,
"IdOkresKlasyfikacyjny" to data.studentSemesterId
)) { json, _ ->
val grades = json.getJsonObject("Data")
grades.getJsonArray("OcenyPrzewidywane")?.let {
processGradeList(it, isFinal = false)
}
grades.getJsonArray("OcenyKlasyfikacyjne")?.let {
processGradeList(it, isFinal = true)
}
data.setSyncNext(ENDPOINT_VULCAN_API_GRADES_SUMMARY, 6*HOUR)
onSuccess()
}
} ?: onSuccess()}
private fun processGradeList(grades: JsonArray, isFinal: Boolean) {
grades.asJsonObjectList()?.forEach { grade ->
val name = grade.get("Wpis").asString
val value = Utils.getGradeValue(name)
val subjectId = grade.get("IdPrzedmiot").asLong
val id = subjectId * -100 - data.studentSemesterNumber
val color = Utils.getVulcanGradeColor(name)
val gradeObject = Grade(
profileId,
id,
"",
color,
"",
name,
value,
0f,
data.studentSemesterNumber,
-1,
subjectId
)
if (data.studentSemesterNumber == 1) {
gradeObject.type = if (isFinal) Grade.TYPE_SEMESTER1_FINAL else Grade.TYPE_SEMESTER1_PROPOSED
} else {
gradeObject.type = if (isFinal) Grade.TYPE_SEMESTER2_FINAL else Grade.TYPE_SEMESTER2_PROPOSED
}
data.gradeList.add(gradeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_GRADE,
gradeObject.id,
data.profile?.empty ?: false,
data.profile?.empty ?: false,
System.currentTimeMillis()
))
}
}
}

View File

@ -108,6 +108,11 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) {
data.apiCertificatePfx = cert.getString("CertyfikatPfx")
data.apiCertificateExpiryTime = 1598832000
data.apiToken = data.apiToken?.substring(0, 3)
data.apiCertificatePrivate = getPrivateKeyFromCert(
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
data.apiCertificatePfx ?: ""
)
data.loginStore.removeLoginData("certificatePfx")
data.loginStore.removeLoginData("devicePin")
onSuccess()
}