diff --git a/jecnaapi-java/src/jvmMain/kotlin/io/github/tomhula/jecnaapi/java/JecnaClientJavaWrapper.kt b/jecnaapi-java/src/jvmMain/kotlin/io/github/tomhula/jecnaapi/java/JecnaClientJavaWrapper.kt index 4f81047..a28598a 100644 --- a/jecnaapi-java/src/jvmMain/kotlin/io/github/tomhula/jecnaapi/java/JecnaClientJavaWrapper.kt +++ b/jecnaapi-java/src/jvmMain/kotlin/io/github/tomhula/jecnaapi/java/JecnaClientJavaWrapper.kt @@ -62,7 +62,9 @@ class JecnaClientJavaWrapper(autoLogin: Boolean = false) fun getNotifications() = GlobalScope.future { wrappedClient.getNotifications() } fun getRoomsPage() = GlobalScope.future { wrappedClient.getRoomsPage() } fun getRoom(roomReference: RoomReference) = GlobalScope.future { wrappedClient.getRoom(roomReference) } - fun getRoom(roomCode: String) = GlobalScope.future { wrappedClient.getRoom(roomCode) } + fun getRoom(roomCode: String) = GlobalScope.future { wrappedClient.getRoom(roomCode) } + fun getDocumentsPage() = GlobalScope.future { wrappedClient.getDocumentsPage() } + fun getDocumentsPage(path: String) = GlobalScope.future { wrappedClient.getDocumentsPage(path) } /** A query without any authentication (autologin) handling. */ fun plainQuery(path: String, parameters: Parameters? = null) = diff --git a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/JecnaClient.kt b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/JecnaClient.kt index 33a524c..9d40c05 100644 --- a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/JecnaClient.kt +++ b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/JecnaClient.kt @@ -1,4 +1,6 @@ package io.github.tomhula.jecnaapi + +import io.github.tomhula.jecnaapi.data.document.DocumentsPage import io.github.tomhula.jecnaapi.data.absence.AbsencesPage import io.github.tomhula.jecnaapi.data.article.NewsPage import io.github.tomhula.jecnaapi.data.attendance.AttendancesPage @@ -52,6 +54,7 @@ interface JecnaClient /** @return the list of student's certificates or `null` if the student cannot have any certificates (i.e. he is not in the 4th grade) */ suspend fun getStudentCertificates(): List? + suspend fun getDocumentsPage(path: String = "/dokumenty"): DocumentsPage companion object { diff --git a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/WebJecnaClient.kt b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/WebJecnaClient.kt index 530a949..a54cdb7 100644 --- a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/WebJecnaClient.kt +++ b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/WebJecnaClient.kt @@ -3,6 +3,7 @@ package io.github.tomhula.jecnaapi import com.fleeksoft.ksoup.Ksoup import com.fleeksoft.ksoup.nodes.Document import io.github.tomhula.jecnaapi.data.cert.Certificate +import io.github.tomhula.jecnaapi.data.document.DocumentsPage import io.github.tomhula.jecnaapi.data.notification.NotificationReference import io.github.tomhula.jecnaapi.parser.parsers.* import io.github.tomhula.jecnaapi.util.JecnaPeriodEncoder @@ -92,6 +93,7 @@ class WebJecnaClient( private val roomsPageParser = RoomsPageParser private val roomParser = RoomParser(TimetableParser) private val certificatePageParser = CertificatePageParser + private val documentsPageParser = DocumentsPageParser @OptIn(ExperimentalTime::class) override suspend fun login(auth: Auth): Boolean @@ -177,9 +179,10 @@ class WebJecnaClient( if (locationHeader == "$endpoint/neopravneny-pristup") return null - + return certificatePageParser.parse(response.bodyAsText()) } + override suspend fun getDocumentsPage(path: String): DocumentsPage = documentsPageParser.parse(queryStringBody(path)) suspend fun setRole(role: Role) { diff --git a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/data/document/SchoolDocument.kt b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/data/document/SchoolDocument.kt new file mode 100644 index 0000000..d0b3deb --- /dev/null +++ b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/data/document/SchoolDocument.kt @@ -0,0 +1,29 @@ +package io.github.tomhula.jecnaapi.data.document + +import kotlinx.serialization.Serializable + +@Serializable +sealed class SchoolDocument +{ + abstract val label: String + abstract val path: String +} + +@Serializable +data class DocumentFolder( + override val label: String, + override val path: String +) : SchoolDocument() + +@Serializable +data class DocumentFile( + override val label: String, + override val path: String +) : SchoolDocument() + +@Serializable +data class DocumentsPage( + val path: String, + val parentPath: String? = null, + val documents: List +) diff --git a/src/commonMain/kotlin/io/github/tomhula/jecnaapi/parser/parsers/DocumentsPageParser.kt b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/parser/parsers/DocumentsPageParser.kt new file mode 100644 index 0000000..a922b27 --- /dev/null +++ b/src/commonMain/kotlin/io/github/tomhula/jecnaapi/parser/parsers/DocumentsPageParser.kt @@ -0,0 +1,54 @@ +package io.github.tomhula.jecnaapi.parser.parsers + +import com.fleeksoft.ksoup.Ksoup +import io.github.tomhula.jecnaapi.data.document.DocumentFile +import io.github.tomhula.jecnaapi.data.document.DocumentFolder +import io.github.tomhula.jecnaapi.data.document.DocumentsPage +import io.github.tomhula.jecnaapi.parser.ParseException + +internal object DocumentsPageParser +{ + fun parse(html: String): DocumentsPage + { + try + { + val document = Ksoup.parse(html) + val path = document.selectFirst(".documentPath") + ?.text() + ?.removePrefix("Adresa:") + ?.trim() + ?: "/dokumenty" + + var parentPath: String? = null + val documents = document + .select("ul.documents a.dir, ul.documents a.file") + .mapNotNull { linkElement -> + val label = linkElement.selectFirst(".label") + ?.text() + // Replace non-breaking space with regular space + ?.replace("\u00A0", " ") + ?: return@mapNotNull null + + val href = linkElement.attr("href") + + if (label == "..") + { + parentPath = href.takeIf { it.isNotBlank() } + return@mapNotNull null + } + + when + { + linkElement.hasClass("dir") -> DocumentFolder(label, href) + linkElement.hasClass("file") -> DocumentFile(label, href) + else -> null + } + } + + return DocumentsPage(path = path, parentPath = parentPath, documents = documents) + } catch (e: Exception) + { + throw ParseException("Failed to parse documents page.", e) + } + } +}