Add support for attendance summary via eduOne

This commit is contained in:
Mikołaj Pich 2024-03-19 20:00:19 +01:00
parent fd5eb26a9d
commit 3c7d8b9545
No known key found for this signature in database
6 changed files with 200 additions and 2 deletions

View file

@ -356,7 +356,10 @@ class Scrapper {
suspend fun getAttendanceSummary(subjectId: Int? = -1): List<AttendanceSummary> {
if (diaryId == 0) return emptyList()
return student.getAttendanceSummary(subjectId)
return when (isEduOne) {
true -> studentPlus.getAttendanceSummary(studentId, diaryId, unitId)
else -> student.getAttendanceSummary(subjectId)
}
}
suspend fun excuseForAbsence(absents: List<Absent>, content: String? = null): Boolean {

View file

@ -1,22 +1,30 @@
package io.github.wulkanowy.sdk.scrapper.attendance
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
@Serializable
@OptIn(ExperimentalSerializationApi::class)
internal class AttendanceSummaryResponse {
@SerialName("Statystyki")
@JsonNames("statystyki")
var items: List<Summary> = emptyList()
@Serializable
data class Summary(
@SerialName("Id")
@JsonNames("kategoriaFrekwencji")
val id: Int,
@SerialName("miesiace")
val months: List<AttendanceSummaryMonth> = emptyList(),
@SerialName("NazwaTypuFrekwencji")
val type: String,
val type: String = "",
@SerialName("Wrzesien")
val september: Int?,
@ -55,6 +63,15 @@ internal class AttendanceSummaryResponse {
val august: Int?,
@SerialName("Razem")
@JsonNames("razem")
val total: Int?,
)
}
@Serializable
internal data class AttendanceSummaryMonth(
@SerialName("miesiac")
val month: Int,
@SerialName("wartosc")
val value: Int,
)

View file

@ -7,6 +7,7 @@ import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusePlusRequest
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusePlusRequestItem
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusePlusResponseItem
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusesPlusResponse
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceSummary
import io.github.wulkanowy.sdk.scrapper.attendance.SentExcuseStatus
import io.github.wulkanowy.sdk.scrapper.exams.Exam
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
@ -26,6 +27,7 @@ import io.github.wulkanowy.sdk.scrapper.toFormat
import org.jsoup.Jsoup
import java.net.HttpURLConnection
import java.time.LocalDate
import java.time.Month
internal class StudentPlusRepository(
private val api: StudentPlusService,
@ -87,6 +89,36 @@ internal class StudentPlusRepository(
}
}
suspend fun getAttendanceSummary(studentId: Int, diaryId: Int, unitId: Int): List<AttendanceSummary> {
val summaries = api.getAttendanceSummary(getEncodedKey(studentId, diaryId, unitId))
val stats = summaries.items.associate { it.id to it.months }
val getMonthValue = fun(type: Int, month: Int): Int {
return stats[type]?.find { it.month == month }?.value ?: 0
}
return (1..12).map {
AttendanceSummary(
month = Month.of(it),
presence = getMonthValue(AttendanceCategory.PRESENCE.id, it),
absence = getMonthValue(AttendanceCategory.ABSENCE_UNEXCUSED.id, it),
absenceExcused = getMonthValue(AttendanceCategory.ABSENCE_EXCUSED.id, it),
absenceForSchoolReasons = getMonthValue(AttendanceCategory.ABSENCE_FOR_SCHOOL_REASONS.id, it),
lateness = getMonthValue(AttendanceCategory.UNEXCUSED_LATENESS.id, it),
latenessExcused = getMonthValue(AttendanceCategory.EXCUSED_LATENESS.id, it),
exemption = getMonthValue(AttendanceCategory.EXEMPTION.id, it),
)
}.filterNot { summary ->
summary.absence == 0 &&
summary.absenceExcused == 0 &&
summary.absenceForSchoolReasons == 0 &&
summary.exemption == 0 &&
summary.lateness == 0 &&
summary.latenessExcused == 0 &&
summary.presence == 0
}
}
private fun Attendance.getMatchingExcuse(sentExcuses: AttendanceExcusesPlusResponse): AttendanceExcusePlusResponseItem? {
return sentExcuses.excuses.find { excuse ->
excuse.dayDate == date && (excuse.lessonNumber == number || excuse.lessonNumber == null)

View file

@ -3,6 +3,7 @@ package io.github.wulkanowy.sdk.scrapper.service
import io.github.wulkanowy.sdk.scrapper.attendance.Attendance
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusePlusRequest
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceExcusesPlusResponse
import io.github.wulkanowy.sdk.scrapper.attendance.AttendanceSummaryResponse
import io.github.wulkanowy.sdk.scrapper.conferences.Conference
import io.github.wulkanowy.sdk.scrapper.exams.ExamDetailsPlus
import io.github.wulkanowy.sdk.scrapper.grades.GradeSemester
@ -50,6 +51,11 @@ internal interface StudentPlusService {
@POST("api/Usprawiedliwienia")
suspend fun excuseForAbsence(@Body body: AttendanceExcusePlusRequest): Response<Unit>
@POST("api/FrekwencjaStatystyki")
suspend fun getAttendanceSummary(
@Query("key") key: String,
): AttendanceSummaryResponse
@GET("api/ZarejestrowaneUrzadzenia")
suspend fun getRegisteredDevices(): List<Device>

View file

@ -0,0 +1,37 @@
package io.github.wulkanowy.sdk.scrapper.attendance
import io.github.wulkanowy.sdk.scrapper.BaseLocalTest
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import java.time.Month
class AttendanceSummaryPlusTest : BaseLocalTest() {
private val attendance by lazy {
runBlocking {
getStudentPlusRepo(AttendanceSummaryPlusTest::class.java, "FrekwencjaStatystyki.json")
.getAttendanceSummary(1, 2, 3)
}
}
@Test
fun getAllTest() {
val items = attendance
assertEquals(1, items.size)
}
@Test
fun attendance_march() {
with(attendance[0]) {
assertEquals(Month.MARCH, month)
assertEquals(1, presence)
assertEquals(2, absence)
assertEquals(3, absenceExcused)
assertEquals(6, absenceForSchoolReasons)
assertEquals(4, lateness)
assertEquals(5, latenessExcused)
assertEquals(2, exemption)
}
}
}

View file

@ -0,0 +1,103 @@
{
"podsumowanie": 76.19,
"statystyki": [
{
"kategoriaFrekwencji": 1,
"miesiace": [
{
"miesiac": 3,
"wartosc": 1
}
],
"okresy": [
0,
1
],
"razem": 1
},
{
"kategoriaFrekwencji": 2,
"miesiace": [
{
"miesiac": 3,
"wartosc": 2
}
],
"okresy": [
0,
2
],
"razem": 2
},
{
"kategoriaFrekwencji": 3,
"miesiace": [
{
"miesiac": 3,
"wartosc": 3
}
],
"okresy": [
0,
3
],
"razem": 3
},
{
"kategoriaFrekwencji": 6,
"miesiace": [
{
"miesiac": 3,
"wartosc": 6
}
],
"okresy": [
0,
6
],
"razem": 6
},
{
"kategoriaFrekwencji": 4,
"miesiace": [
{
"miesiac": 3,
"wartosc": 4
}
],
"okresy": [
0,
4
],
"razem": 4
},
{
"kategoriaFrekwencji": 5,
"miesiace": [
{
"miesiac": 3,
"wartosc": 5
}
],
"okresy": [
0,
5
],
"razem": 5
},
{
"kategoriaFrekwencji": 7,
"miesiace": [
{
"miesiac": 3,
"wartosc": 2
}
],
"okresy": [
0,
2
],
"razem": 2
}
]
}