Refactor exam fetch from hebe

This commit is contained in:
Mikołaj Pich 2023-05-04 22:16:43 +02:00
parent b5028a6437
commit 432241919a
10 changed files with 100 additions and 71 deletions

View file

@ -4,7 +4,7 @@ public final class io/github/wulkanowy/sdk/hebe/Hebe {
public static synthetic fun addInterceptor$default (Lio/github/wulkanowy/sdk/hebe/Hebe;Lokhttp3/Interceptor;ZILjava/lang/Object;)V
public final fun getBaseUrl ()Ljava/lang/String;
public final fun getDeviceModel ()Ljava/lang/String;
public final fun getExams (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getExams (Ljava/time/LocalDate;Ljava/time/LocalDate;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getGrades (ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getGradesAverage (ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getGradesSummary (ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
@ -125,16 +125,16 @@ public final class io/github/wulkanowy/sdk/hebe/models/Exam$Creator$Companion {
public final class io/github/wulkanowy/sdk/hebe/models/Exam$DateCreated {
public static final field Companion Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated$Companion;
public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/lang/String;
public synthetic fun <init> (ILjava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/time/LocalDate;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()J
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;
public final fun copy (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateCreated;
public fun equals (Ljava/lang/Object;)Z
public final fun getDate ()Ljava/lang/String;
public final fun getDate ()Ljava/time/LocalDate;
public final fun getDateDisplay ()Ljava/lang/String;
public final fun getTime ()Ljava/lang/String;
public final fun getTimestamp ()J
@ -160,16 +160,16 @@ public final class io/github/wulkanowy/sdk/hebe/models/Exam$DateCreated$Companio
public final class io/github/wulkanowy/sdk/hebe/models/Exam$DateModify {
public static final field Companion Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify$Companion;
public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/lang/String;
public synthetic fun <init> (ILjava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/time/LocalDate;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()J
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;
public final fun copy (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$DateModify;
public fun equals (Ljava/lang/Object;)Z
public final fun getDate ()Ljava/lang/String;
public final fun getDate ()Ljava/time/LocalDate;
public final fun getDateDisplay ()Ljava/lang/String;
public final fun getTime ()Ljava/lang/String;
public final fun getTimestamp ()J
@ -195,16 +195,16 @@ public final class io/github/wulkanowy/sdk/hebe/models/Exam$DateModify$Companion
public final class io/github/wulkanowy/sdk/hebe/models/Exam$Deadline {
public static final field Companion Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline$Companion;
public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/lang/String;
public synthetic fun <init> (ILjava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JLkotlinx/serialization/internal/SerializationConstructorMarker;)V
public fun <init> (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/time/LocalDate;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()J
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;
public final fun copy (Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;J)Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;
public static synthetic fun copy$default (Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;Ljava/time/LocalDate;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lio/github/wulkanowy/sdk/hebe/models/Exam$Deadline;
public fun equals (Ljava/lang/Object;)Z
public final fun getDate ()Ljava/lang/String;
public final fun getDate ()Ljava/time/LocalDate;
public final fun getDateDisplay ()Ljava/lang/String;
public final fun getTime ()Ljava/lang/String;
public final fun getTimestamp ()J

View file

@ -0,0 +1,34 @@
package io.github.wulkanowy.sdk.hebe
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = LocalDate::class)
internal object CustomDateAdapter : KSerializer<LocalDate> {
private const val DATE_FORMAT_1 = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
private const val DATE_FORMAT_2 = "yyyy-MM-dd'T'HH:mm:ss.SSXXX"
private const val DATE_FORMAT_3 = "yyyy-MM-dd'T'HH:mm:ss.SXXX"
private const val DATE_FORMAT_4 = "yyyy-MM-dd'T'HH:mm:ssXXX"
private const val DATE_FORMAT_5 = "yyyy-MM-dd HH:mm:ss"
private const val DATE_FORMAT_6 = "yyyy-MM-dd"
private val formatter = DateTimeFormatter.ofPattern("[$DATE_FORMAT_1][$DATE_FORMAT_2][$DATE_FORMAT_3][$DATE_FORMAT_4][$DATE_FORMAT_5][$DATE_FORMAT_6]")
override fun deserialize(decoder: Decoder): LocalDate {
val date = decoder.decodeString()
return LocalDate.parse(date, formatter)
}
override fun serialize(encoder: Encoder, value: LocalDate) {
encoder.encodeString(value.format(formatter))
}
}

View file

@ -10,6 +10,7 @@ import io.github.wulkanowy.sdk.hebe.repository.RepositoryManager
import io.github.wulkanowy.signer.hebe.generateKeyPair
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import java.time.LocalDate
class Hebe {
@ -140,9 +141,11 @@ class Hebe {
)
}
suspend fun getExams(): List<Exam> {
suspend fun getExams(startDate: LocalDate, endDate: LocalDate): List<Exam> {
return studentRepository.getExams(
pupilId = pupilId,
startDate = startDate,
endDate = endDate,
)
}
}

View file

@ -1,7 +1,9 @@
package io.github.wulkanowy.sdk.hebe.models
import io.github.wulkanowy.sdk.hebe.CustomDateAdapter
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.time.LocalDate
@Serializable
data class Exam(
@ -41,7 +43,8 @@ data class Exam(
@Serializable
data class DateCreated(
@SerialName("Date")
val date: String,
@Serializable(with = CustomDateAdapter::class)
val date: LocalDate,
@SerialName("DateDisplay")
val dateDisplay: String,
@SerialName("Time")
@ -53,7 +56,8 @@ data class Exam(
@Serializable
data class DateModify(
@SerialName("Date")
val date: String,
@Serializable(with = CustomDateAdapter::class)
val date: LocalDate,
@SerialName("DateDisplay")
val dateDisplay: String,
@SerialName("Time")
@ -65,7 +69,8 @@ data class Exam(
@Serializable
data class Deadline(
@SerialName("Date")
val date: String,
@Serializable(with = CustomDateAdapter::class)
val date: LocalDate,
@SerialName("DateDisplay")
val dateDisplay: String,
@SerialName("Time")

View file

@ -14,10 +14,10 @@ import retrofit2.converter.scalars.ScalarsConverterFactory
import retrofit2.create
internal class RepositoryManager(
private val logLevel: HttpLoggingInterceptor.Level,
private val keyId: String,
private val privatePem: String,
private val deviceModel: String,
logLevel: HttpLoggingInterceptor.Level,
) {
private val interceptors: MutableList<Pair<Interceptor, Boolean>> = mutableListOf(
@ -67,7 +67,6 @@ internal class RepositoryManager(
.create(),
)
@OptIn(ExperimentalSerializationApi::class)
private fun getRetrofitBuilder(isJson: Boolean = true, signInterceptor: Boolean): Retrofit.Builder {
return Retrofit.Builder()
.apply {
@ -85,7 +84,6 @@ internal class RepositoryManager(
if (it.second) addNetworkInterceptor(it.first)
else addInterceptor(it.first)
}
addInterceptor(HttpLoggingInterceptor().setLevel(logLevel))
}
.build(),
)

View file

@ -6,43 +6,49 @@ import io.github.wulkanowy.sdk.hebe.models.Grade
import io.github.wulkanowy.sdk.hebe.models.GradeAverage
import io.github.wulkanowy.sdk.hebe.models.GradeSummary
import io.github.wulkanowy.sdk.hebe.service.StudentService
import java.time.LocalDate
import java.time.format.DateTimeFormatter
internal class StudentRepository(private val studentService: StudentService) {
suspend fun getGrades(pupilId: Int, periodId: Int): List<Grade> {
return studentService.getGrades(
pupilId = pupilId,
periodId = periodId,
createQueryMap(pupilId = pupilId, periodId = periodId),
).getEnvelopeOrThrowError().orEmpty()
}
suspend fun getGradesSummary(pupilId: Int, periodId: Int): List<GradeSummary> {
return studentService.getGradesSummary(
pupilId = pupilId,
periodId = periodId,
createQueryMap(pupilId = pupilId, periodId = periodId),
).getEnvelopeOrThrowError().orEmpty()
}
suspend fun getGradesAverage(pupilId: Int, periodId: Int): List<GradeAverage> {
return studentService.getGradesAverage(
pupilId = pupilId,
periodId = periodId,
createQueryMap(pupilId = pupilId, periodId = periodId),
).getEnvelopeOrThrowError().orEmpty()
}
suspend fun getExams(pupilId: Int): List<Exam> {
suspend fun getExams(pupilId: Int, startDate: LocalDate, endDate: LocalDate): List<Exam> {
return studentService.getExams(
createQueryMap(pupilId = pupilId),
).getEnvelopeOrThrowError().orEmpty()
createQueryMap(pupilId = pupilId, dateFrom = startDate),
).getEnvelopeOrThrowError().orEmpty().filter {
it.deadline.date in startDate..endDate
}
}
private fun createQueryMap(pupilId: Int, periodId: Int? = null): Map<String, Any?> {
return mapOf(
"pupilId" to pupilId,
"periodId" to periodId,
"lastSyncDate" to "1970-01-01 01:00:00",
"lastId" to Int.MIN_VALUE,
"pageSize" to 500,
)
}
private fun createQueryMap(
pupilId: Int,
periodId: Int? = null,
dateFrom: LocalDate? = null,
dateTo: LocalDate? = null,
): Map<String, Any?> = mapOf(
"pupilId" to pupilId,
"periodId" to periodId,
"lastSyncDate" to "1970-01-01 01:00:00",
"lastId" to Int.MIN_VALUE,
"pageSize" to 500,
"dateFrom" to dateFrom?.format(DateTimeFormatter.ISO_DATE),
"dateTo" to dateTo?.format(DateTimeFormatter.ISO_DATE),
).filterValues { it != null }
}

View file

@ -13,31 +13,13 @@ import retrofit2.http.QueryMap
internal interface StudentService {
@GET("api/mobile/grade/byPupil")
suspend fun getGrades(
@Query("pupilId") pupilId: Int,
@Query("periodId") periodId: Int,
@Query("lastSyncDate") lastSyncDate: String = "1970-01-01 01:00:00",
@Query("lastId") lastId: Int = Int.MIN_VALUE,
@Query("pageSize") pageSize: Int = 500,
): ApiResponse<List<Grade>>
suspend fun getGrades(@QueryMap query: Map<String, Any?>): ApiResponse<List<Grade>>
@GET("api/mobile/grade/summary/byPupil")
suspend fun getGradesSummary(
@Query("pupilId") pupilId: Int,
@Query("periodId") periodId: Int,
@Query("lastSyncDate") lastSyncDate: String = "1970-01-01 01:00:00",
@Query("lastId") lastId: Int = Int.MIN_VALUE,
@Query("pageSize") pageSize: Int = 500,
): ApiResponse<List<GradeSummary>>
suspend fun getGradesSummary(@QueryMap query: Map<String, Any?> ): ApiResponse<List<GradeSummary>>
@GET("api/mobile/grade/average/byPupil")
suspend fun getGradesAverage(
@Query("pupilId") pupilId: Int,
@Query("periodId") periodId: Int,
@Query("lastSyncDate") lastSyncDate: String = "1970-01-01 01:00:00",
@Query("lastId") lastId: Int = Int.MIN_VALUE,
@Query("pageSize") pageSize: Int = 500,
): ApiResponse<List<GradeAverage>>
suspend fun getGradesAverage(@QueryMap query: Map<String, Any?>): ApiResponse<List<GradeAverage>>
@GET("api/mobile/exam/byPupil")
suspend fun getExams(@QueryMap query: Map<String, Any?>): ApiResponse<List<Exam>>

View file

@ -7,6 +7,7 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import java.time.LocalDate
@Ignore
@OptIn(ExperimentalCoroutinesApi::class)
@ -46,19 +47,19 @@ class HebeRemoteTest {
@Test
fun `get grades`() = runTest {
val grades = hebe.getGrades(559)
val grades = hebe.getGrades(560)
assertTrue(grades.isNotEmpty())
}
@Test
fun `get grades summary`() = runTest {
val summaries = hebe.getGradesSummary(559)
val summaries = hebe.getGradesSummary(560)
assertTrue(summaries.isNotEmpty())
}
@Test
fun `get exams`() = runTest {
val exams = hebe.getExams()
val exams = hebe.getExams(LocalDate.of(2023, 4, 1), LocalDate.of(2023, 5, 1))
assertTrue(exams.isNotEmpty())
}
}

View file

@ -366,7 +366,7 @@ class Sdk {
suspend fun getExams(start: LocalDate, end: LocalDate): List<Exam> = withContext(Dispatchers.IO) {
when (mode) {
Mode.HYBRID, Mode.SCRAPPER -> scrapper.getExams(start, end).mapExams()
Mode.HEBE -> hebe.getExams().mapExams()
Mode.HEBE -> hebe.getExams(start, end).mapExams()
}
}

View file

@ -21,8 +21,8 @@ internal fun List<ScrapperExam>.mapExams() = map {
@JvmName("mapHebeExams")
internal fun List<HebeExam>.mapExams() = map {
Exam(
date = it.dateCreated.timestamp.toLocalDate(),
entryDate = it.deadline.timestamp.toLocalDate(),
date = it.dateCreated.date,
entryDate = it.deadline.date,
description = it.content,
subject = it.subject.name,
teacher = it.creator.displayName,