mirror of
https://github.com/Matte23/circolapp.git
synced 2025-12-06 07:29:10 +00:00
Add shared module
This commit is contained in:
2
shared/src/androidMain/AndroidManifest.xml
Normal file
2
shared/src/androidMain/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="net.underdesk.circolapp.shared.android" />
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.underdesk.circolapp.shared
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
actual object PlatformDispatcher {
|
||||
actual val IO = Dispatchers.IO
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
|
||||
actual class DatabaseDriverFactory(private val context: Context) {
|
||||
actual fun createDriver(): SqlDriver {
|
||||
return AndroidSqliteDriver(AppDatabase.Schema, context, "circolapp.db")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.underdesk.circolapp.shared.server
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.okhttp.*
|
||||
import io.ktor.client.features.json.*
|
||||
import io.ktor.client.features.json.serializer.*
|
||||
|
||||
actual class KtorFactory actual constructor() {
|
||||
actual fun createClient() = HttpClient(OkHttp) {
|
||||
install(JsonFeature) {
|
||||
serializer = KotlinxSerializer(
|
||||
kotlinx.serialization.json.Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.underdesk.circolapp.shared.server.curie
|
||||
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
actual class SpecificCurieServer actual constructor(private val curieServer: CurieServer) {
|
||||
actual fun parseHtml(string: String): List<Circular> {
|
||||
val document = Jsoup.parseBodyFragment(string)
|
||||
val htmlList = document.getElementsByTag("ul")[0].getElementsByTag("a")
|
||||
|
||||
val list = ArrayList<Circular>()
|
||||
|
||||
htmlList.forEach { element ->
|
||||
if (element.parents().size == 6) {
|
||||
list.last().attachmentsNames.add(element.text())
|
||||
list.last().attachmentsUrls.add(element.attr("href"))
|
||||
} else if (element.parents().size == 4) {
|
||||
list.add(curieServer.generateFromString(element.text(), element.attr("href")))
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.underdesk.circolapp.shared.server.porporato
|
||||
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
actual class SpecificPorporatoServer actual constructor(private val porporatoServer: PorporatoServer) {
|
||||
actual fun parseHtml(string: String): List<Circular> {
|
||||
val document = Jsoup.parseBodyFragment(string)
|
||||
val htmlList = document.getElementsByTag("table")[2]
|
||||
.getElementsByTag("td")[2]
|
||||
.getElementsByTag("a")
|
||||
|
||||
val list = ArrayList<Circular>()
|
||||
|
||||
for (i in 0 until htmlList.size) {
|
||||
list.add(
|
||||
porporatoServer.generateFromString(
|
||||
htmlList[i].text(),
|
||||
htmlList[i].attr("href"),
|
||||
i.toLong()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.underdesk.circolapp.shared
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
|
||||
expect object PlatformDispatcher {
|
||||
val IO: CoroutineDispatcher
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Circolapp
|
||||
* Copyright (C) 2019-2020 Matteo Schiff
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
data class Circular(
|
||||
val id: Long,
|
||||
val school: Int,
|
||||
val name: String,
|
||||
val url: String,
|
||||
val date: String,
|
||||
var favourite: Boolean = false,
|
||||
var reminder: Boolean = false,
|
||||
val attachmentsNames: MutableList<String> = mutableListOf(),
|
||||
val attachmentsUrls: MutableList<String> = mutableListOf()
|
||||
)
|
||||
@@ -0,0 +1,87 @@
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.underdesk.circolapp.shared.PlatformDispatcher
|
||||
import net.underdesk.circolapp.shared.utils.SqlUtils.joinToString
|
||||
import net.underdesk.circolapp.shared.utils.SqlUtils.toBoolean
|
||||
import net.underdesk.circolapp.shared.utils.SqlUtils.toList
|
||||
import net.underdesk.circolapp.shared.utils.SqlUtils.toLong
|
||||
|
||||
class CircularDao(
|
||||
database: AppDatabase
|
||||
) {
|
||||
private val appDatabaseQueries = database.appDatabaseQueries
|
||||
|
||||
private val circularMapper =
|
||||
{ id: Long, school: Long, name: String, url: String, date: String, favourite: Long, reminder: Long, attachmentsNames: String, attachmentsUrls: String ->
|
||||
Circular(
|
||||
id,
|
||||
school.toInt(),
|
||||
name,
|
||||
url,
|
||||
date,
|
||||
favourite.toBoolean(),
|
||||
reminder.toBoolean(),
|
||||
attachmentsNames.toList(),
|
||||
attachmentsUrls.toList()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun insertAll(circulars: List<Circular>) = withContext(PlatformDispatcher.IO) {
|
||||
circulars.forEach {
|
||||
appDatabaseQueries.insertCircular(
|
||||
it.id,
|
||||
it.school.toLong(),
|
||||
it.name,
|
||||
it.url,
|
||||
it.date,
|
||||
it.favourite.toLong(),
|
||||
it.reminder.toLong(),
|
||||
it.attachmentsNames.joinToString(),
|
||||
it.attachmentsUrls.joinToString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun update(id: Long, school: Int, favourite: Boolean, reminder: Boolean) =
|
||||
withContext(PlatformDispatcher.IO) {
|
||||
appDatabaseQueries.updateCircular(
|
||||
favourite.toLong(),
|
||||
reminder.toLong(),
|
||||
id,
|
||||
school.toLong()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun deleteAll() = withContext(PlatformDispatcher.IO) {
|
||||
appDatabaseQueries.deleteAllCirculars()
|
||||
}
|
||||
|
||||
fun getCircular(id: Long, school: Int) = appDatabaseQueries.getCircular(id, school.toLong(), circularMapper).executeAsOne()
|
||||
|
||||
fun getCirculars(school: Int) =
|
||||
appDatabaseQueries.getCirculars(school.toLong(), circularMapper).executeAsList()
|
||||
|
||||
fun getFlowCirculars(school: Int) =
|
||||
appDatabaseQueries.getCirculars(school.toLong(), circularMapper).asFlow().mapToList()
|
||||
|
||||
fun searchCirculars(query: String, school: Int) =
|
||||
appDatabaseQueries.searchCirculars(school.toLong(), query, circularMapper).asFlow()
|
||||
.mapToList()
|
||||
|
||||
fun getFavourites(school: Int) =
|
||||
appDatabaseQueries.getFavourites(school.toLong(), circularMapper).asFlow().mapToList()
|
||||
|
||||
fun searchFavourites(query: String, school: Int) =
|
||||
appDatabaseQueries.searchFavourites(school.toLong(), query, circularMapper).asFlow()
|
||||
.mapToList()
|
||||
|
||||
fun getReminders(school: Int) =
|
||||
appDatabaseQueries.getReminders(school.toLong(), circularMapper).asFlow().mapToList()
|
||||
|
||||
fun searchReminders(query: String, school: Int) =
|
||||
appDatabaseQueries.searchReminders(school.toLong(), query, circularMapper).asFlow()
|
||||
.mapToList()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
import net.underdesk.circolapp.shared.server.ServerAPI
|
||||
|
||||
class CircularRepository(
|
||||
val circularDao: CircularDao,
|
||||
private val serverAPI: ServerAPI
|
||||
) {
|
||||
suspend fun updateCirculars(returnNewCirculars: Boolean = true): Pair<List<Circular>, Boolean> {
|
||||
var onlyNewCirculars = listOf<Circular>()
|
||||
|
||||
val result = serverAPI.getCircularsFromServer()
|
||||
if (result.second == ServerAPI.Companion.Result.ERROR)
|
||||
return Pair(emptyList(), false)
|
||||
|
||||
val oldCirculars = circularDao.getCirculars(serverAPI.serverID())
|
||||
val newCirculars = result.first
|
||||
|
||||
if (newCirculars.size != oldCirculars.size) {
|
||||
if (newCirculars.size < oldCirculars.size) {
|
||||
circularDao.deleteAll()
|
||||
}
|
||||
|
||||
if (returnNewCirculars) {
|
||||
val oldCircularsSize =
|
||||
if (newCirculars.size < oldCirculars.size) 0 else oldCirculars.size
|
||||
|
||||
val circularCount = newCirculars.size - oldCircularsSize
|
||||
onlyNewCirculars = newCirculars.subList(0, circularCount)
|
||||
}
|
||||
|
||||
circularDao.insertAll(newCirculars)
|
||||
}
|
||||
return Pair(onlyNewCirculars, true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
|
||||
expect class DatabaseDriverFactory {
|
||||
fun createDriver(): SqlDriver
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.underdesk.circolapp.shared.server
|
||||
|
||||
import io.ktor.client.*
|
||||
|
||||
expect class KtorFactory() {
|
||||
fun createClient(): HttpClient
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Circolapp
|
||||
* Copyright (C) 2019-2020 Matteo Schiff
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.underdesk.circolapp.shared.server
|
||||
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
|
||||
abstract class Server {
|
||||
abstract val serverID: Int
|
||||
abstract suspend fun getCircularsFromServer(): Pair<List<Circular>, ServerAPI.Companion.Result>
|
||||
abstract suspend fun newCircularsAvailable(): Pair<Boolean, ServerAPI.Companion.Result>
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Circolapp
|
||||
* Copyright (C) 2019-2020 Matteo Schiff
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.underdesk.circolapp.shared.server
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.underdesk.circolapp.shared.PlatformDispatcher
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
import net.underdesk.circolapp.shared.server.curie.CurieServer
|
||||
import net.underdesk.circolapp.shared.server.porporato.PorporatoServer
|
||||
|
||||
class ServerAPI(
|
||||
private var server: Server
|
||||
) {
|
||||
fun serverID(): Int = server.serverID
|
||||
|
||||
suspend fun getCircularsFromServer(): Pair<List<Circular>, Result> = withContext(PlatformDispatcher.IO) {
|
||||
val newCircularsAvailable = server.newCircularsAvailable()
|
||||
|
||||
if (newCircularsAvailable.second == Result.ERROR)
|
||||
return@withContext Pair(emptyList(), Result.ERROR)
|
||||
|
||||
if (!newCircularsAvailable.first)
|
||||
return@withContext Pair(emptyList(), Result.SUCCESS)
|
||||
|
||||
server.getCircularsFromServer()
|
||||
}
|
||||
|
||||
fun changeServer(server: Server) {
|
||||
this.server = server
|
||||
}
|
||||
|
||||
companion object {
|
||||
enum class Servers {
|
||||
CURIE, PORPORATO
|
||||
}
|
||||
|
||||
enum class Result {
|
||||
SUCCESS, ERROR
|
||||
}
|
||||
|
||||
fun getServerId(server: Servers): Int {
|
||||
return Servers.values().indexOf(server)
|
||||
}
|
||||
|
||||
fun getServerName(server: Servers) = when (server) {
|
||||
Servers.CURIE -> "Liceo scientifico Maria Curie"
|
||||
Servers.PORPORATO -> "Liceo G.F. Porporato"
|
||||
}
|
||||
|
||||
fun createServer(server: Servers) = when (server) {
|
||||
Servers.CURIE -> CurieServer()
|
||||
Servers.PORPORATO -> PorporatoServer()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package net.underdesk.circolapp.shared.server.curie
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.utils.io.errors.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
import net.underdesk.circolapp.shared.server.KtorFactory
|
||||
import net.underdesk.circolapp.shared.server.Server
|
||||
import net.underdesk.circolapp.shared.server.ServerAPI
|
||||
import net.underdesk.circolapp.shared.server.pojo.Response
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
class CurieServer : Server() {
|
||||
private val client = KtorFactory().createClient()
|
||||
|
||||
override val serverID = ServerAPI.getServerId(ServerAPI.Companion.Servers.CURIE)
|
||||
|
||||
override suspend fun getCircularsFromServer(): Pair<List<Circular>, ServerAPI.Companion.Result> {
|
||||
return try {
|
||||
withContext(Dispatchers.Default) {
|
||||
val json = retrieveDataFromServer()
|
||||
val list = SpecificCurieServer(this@CurieServer).parseHtml(json.content.rendered)
|
||||
Pair(list, ServerAPI.Companion.Result.SUCCESS)
|
||||
}
|
||||
} catch (exception: IOException) {
|
||||
Pair(emptyList(), ServerAPI.Companion.Result.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun newCircularsAvailable(): Pair<Boolean, ServerAPI.Companion.Result> {
|
||||
return Pair(true, ServerAPI.Companion.Result.SUCCESS)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@Throws(IOException::class, CancellationException::class)
|
||||
private suspend fun retrieveDataFromServer(): Response {
|
||||
return client.get(ENDPOINT_URL)
|
||||
}
|
||||
|
||||
fun generateFromString(string: String, url: String): Circular {
|
||||
val idRegex =
|
||||
"""(\d+)""".toRegex()
|
||||
val idMatcher = idRegex.find(string)
|
||||
|
||||
val id = idMatcher?.value?.toLong() ?: -1L
|
||||
|
||||
val dateRegex =
|
||||
"""(\d{2}/\d{2}/\d{4})""".toRegex()
|
||||
val dateMatcher = dateRegex.find(string)
|
||||
|
||||
var title = string.removeSuffix("-signed")
|
||||
|
||||
return if (dateMatcher != null) {
|
||||
title = title.removeRange(0, dateMatcher.range.last + 1)
|
||||
.removePrefix(" ")
|
||||
.removePrefix("_")
|
||||
.removePrefix(" ")
|
||||
|
||||
Circular(id, serverID, title, url, dateMatcher.value)
|
||||
} else {
|
||||
Circular(id, serverID, title, url, "")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ENDPOINT_URL = "https://www.curiepinerolo.edu.it/wp-json/wp/v2/pages/5958"
|
||||
}
|
||||
}
|
||||
|
||||
expect class SpecificCurieServer(curieServer: CurieServer) {
|
||||
fun parseHtml(string: String): List<Circular>
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.underdesk.circolapp.shared.server.pojo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Response(
|
||||
val content: Content
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Content(
|
||||
val rendered: String
|
||||
)
|
||||
@@ -0,0 +1,140 @@
|
||||
package net.underdesk.circolapp.shared.server.porporato
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.utils.io.charsets.*
|
||||
import io.ktor.utils.io.errors.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
import net.underdesk.circolapp.shared.server.KtorFactory
|
||||
import net.underdesk.circolapp.shared.server.Server
|
||||
import net.underdesk.circolapp.shared.server.ServerAPI
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
class PorporatoServer : Server() {
|
||||
private val client = KtorFactory().createClient()
|
||||
|
||||
private val baseUrl = "https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/"
|
||||
private val endpointUrls = listOf(
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-01-Settembre/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-02-Ottobre/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-03-Novembre/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-04-Dicembre/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-05-Gennaio/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-06-Febbraio/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-07-Marzo/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-08-Aprile/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-09-Maggio/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-10-Giugno/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-11-Luglio/",
|
||||
"https://www.liceoporporato.edu.it/ARCHIVIO/PR/VP/circolari.php?dirname=CIRCOLARIP/- CIRCOLARI 2020-21/-12-Agosto/"
|
||||
)
|
||||
|
||||
override val serverID = ServerAPI.getServerId(ServerAPI.Companion.Servers.PORPORATO)
|
||||
|
||||
override suspend fun getCircularsFromServer(): Pair<List<Circular>, ServerAPI.Companion.Result> {
|
||||
return try {
|
||||
val list = arrayListOf<Circular>()
|
||||
|
||||
for (url in endpointUrls) {
|
||||
list.addAll(parsePage(url))
|
||||
}
|
||||
|
||||
list.sortByDescending { it.id }
|
||||
|
||||
Pair(list, ServerAPI.Companion.Result.SUCCESS)
|
||||
} catch (exception: IOException) {
|
||||
Pair(emptyList(), ServerAPI.Companion.Result.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun newCircularsAvailable(): Pair<Boolean, ServerAPI.Companion.Result> {
|
||||
return Pair(true, ServerAPI.Companion.Result.SUCCESS)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@Throws(IOException::class, CancellationException::class)
|
||||
private suspend fun parsePage(url: String): List<Circular> {
|
||||
val response = retrieveDataFromServer(url)
|
||||
|
||||
return withContext(Dispatchers.Default) {
|
||||
val list = SpecificPorporatoServer(this@PorporatoServer).parseHtml(response).toMutableList()
|
||||
|
||||
// Identify and group all attachments
|
||||
list.removeAll { attachment ->
|
||||
if (attachment.name.startsWith("All", true)) {
|
||||
val parent = list.find { it.id == attachment.id && !it.name.startsWith("All") }
|
||||
parent?.attachmentsNames?.add(attachment.name)
|
||||
parent?.attachmentsUrls?.add(attachment.url)
|
||||
|
||||
return@removeAll true
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
// Identify and group attachments not marked with "All"
|
||||
var lastIndex = -1
|
||||
var lastId = -1L
|
||||
|
||||
list.removeAll { attachment ->
|
||||
if (lastId == attachment.id) {
|
||||
val parent = list[lastIndex]
|
||||
parent.attachmentsNames.add(attachment.name)
|
||||
parent.attachmentsUrls.add(attachment.url)
|
||||
|
||||
return@removeAll true
|
||||
}
|
||||
lastId = attachment.id
|
||||
lastIndex = list.indexOf(attachment)
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@Throws(IOException::class, CancellationException::class)
|
||||
private suspend fun retrieveDataFromServer(url: String): String {
|
||||
return client.request<HttpResponse>(url).readText(Charsets.ISO_8859_1)
|
||||
}
|
||||
|
||||
fun generateFromString(string: String, path: String, index: Long): Circular {
|
||||
val fullUrl = baseUrl + path
|
||||
var title = string
|
||||
|
||||
val idRegex =
|
||||
"""(\d+)""".toRegex()
|
||||
val idMatcher = idRegex.find(string)
|
||||
val id = if (!string.startsWith("Avviso") && idMatcher != null) {
|
||||
title = title.removeRange(idMatcher.range)
|
||||
.removePrefix(" ")
|
||||
.removePrefix("-")
|
||||
.removePrefix(" ")
|
||||
|
||||
idMatcher.value.toLong()
|
||||
} else {
|
||||
-index
|
||||
}
|
||||
|
||||
val dateRegex =
|
||||
"""(\d{2}-\d{2}-\d{4})""".toRegex()
|
||||
val dateMatcher = dateRegex.find(title)
|
||||
|
||||
return if (dateMatcher != null) {
|
||||
title = title.removeRange(dateMatcher.range)
|
||||
.removeSuffix(" (pubb.: )")
|
||||
|
||||
Circular(id, serverID, title, fullUrl, dateMatcher.value.replace("-", "/"))
|
||||
} else {
|
||||
Circular(id, serverID, title, fullUrl, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect class SpecificPorporatoServer(porporatoServer: PorporatoServer) {
|
||||
fun parseHtml(string: String): List<Circular>
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.underdesk.circolapp.shared.utils
|
||||
|
||||
object SqlUtils {
|
||||
fun Boolean.toLong() = if (this) 1L else 0L
|
||||
|
||||
fun Long.toBoolean() = this == 1L
|
||||
|
||||
fun String?.toList(): MutableList<String> {
|
||||
val list: MutableList<String> = mutableListOf()
|
||||
|
||||
if (this != null) {
|
||||
for (attachment in this.split("˜")) {
|
||||
list.add(attachment)
|
||||
}
|
||||
}
|
||||
|
||||
return list.dropLast(1).toMutableList()
|
||||
}
|
||||
|
||||
fun List<String>.joinToString(): String {
|
||||
var string = ""
|
||||
|
||||
for (attachment in this) {
|
||||
string += "$attachment˜"
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
CREATE TABLE Circulars (
|
||||
id INTEGER NOT NULL,
|
||||
school INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
date TEXT NOT NULL,
|
||||
favourite INTEGER NOT NULL DEFAULT 0,
|
||||
reminder INTEGER NOT NULL DEFAULT 0,
|
||||
attachmentsNames TEXT NOT NULL,
|
||||
attachmentsUrls TEXT NOT NULL,
|
||||
PRIMARY KEY (id, school)
|
||||
);
|
||||
|
||||
insertCircular:
|
||||
INSERT OR IGNORE INTO Circulars(id, school, name, url, date, favourite, reminder, attachmentsNames, attachmentsUrls)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
|
||||
updateCircular:
|
||||
UPDATE Circulars
|
||||
SET favourite = ?, reminder = ?
|
||||
WHERE id = ? AND school = ?;
|
||||
|
||||
deleteAllCirculars:
|
||||
DELETE FROM Circulars;
|
||||
|
||||
getCirculars:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ?
|
||||
ORDER BY id DESC;
|
||||
|
||||
getCircular:
|
||||
SELECT * FROM Circulars
|
||||
WHERE id IS ? AND school = ?
|
||||
ORDER BY id DESC;
|
||||
|
||||
searchCirculars:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ? AND name LIKE ?
|
||||
ORDER BY id DESC;
|
||||
|
||||
getFavourites:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ? AND favourite
|
||||
ORDER BY id DESC;
|
||||
|
||||
searchFavourites:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ? AND favourite AND name LIKE ?
|
||||
ORDER BY id DESC;
|
||||
|
||||
getReminders:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ? AND reminder
|
||||
ORDER BY id DESC;
|
||||
|
||||
searchReminders:
|
||||
SELECT * FROM Circulars
|
||||
WHERE school IS ? AND reminder AND name LIKE ?
|
||||
ORDER BY id DESC;
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.underdesk.circolapp.shared
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
actual object PlatformDispatcher {
|
||||
actual val IO = Dispatchers.Default
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.underdesk.circolapp.shared.data
|
||||
|
||||
import com.squareup.sqldelight.db.SqlDriver
|
||||
import com.squareup.sqldelight.drivers.native.NativeSqliteDriver
|
||||
|
||||
actual class DatabaseDriverFactory {
|
||||
actual fun createDriver(): SqlDriver {
|
||||
return NativeSqliteDriver(AppDatabase.Schema, "circolapp.db")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.underdesk.circolapp.shared.server
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.ios.*
|
||||
import io.ktor.client.features.json.*
|
||||
import io.ktor.client.features.json.serializer.*
|
||||
|
||||
actual class KtorFactory actual constructor() {
|
||||
actual fun createClient() = HttpClient(Ios) {
|
||||
install(JsonFeature) {
|
||||
serializer = KotlinxSerializer(
|
||||
kotlinx.serialization.json.Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.underdesk.circolapp.shared.server.curie
|
||||
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
|
||||
actual class SpecificCurieServer actual constructor(val curieServer: CurieServer) {
|
||||
actual fun parseHtml(string: String): List<Circular> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.underdesk.circolapp.shared.server.porporato
|
||||
|
||||
import net.underdesk.circolapp.shared.data.Circular
|
||||
|
||||
actual class SpecificPorporatoServer actual constructor(porporatoServer: PorporatoServer) {
|
||||
actual fun parseHtml(string: String): List<Circular> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user