Add base code for multiple server (schools) support

This commit is contained in:
Matte23
2020-10-23 18:48:40 +02:00
parent 2072a48a75
commit 40c3352f3b
11 changed files with 200 additions and 112 deletions

View File

@@ -2,50 +2,49 @@ package net.underdesk.circolapp.data
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.underdesk.circolapp.server.DataFetcher import net.underdesk.circolapp.server.ServerAPI
import java.io.IOException
class CircularRepository( class CircularRepository(
val circularDao: CircularDao, val circularDao: CircularDao,
private val fetcher: DataFetcher = DataFetcher() private val serverAPI: ServerAPI
) { ) {
suspend fun updateCirculars(returnNewCirculars: Boolean = true): Pair<List<Circular>, Boolean> { suspend fun updateCirculars(returnNewCirculars: Boolean = true): Pair<List<Circular>, Boolean> {
var onlyNewCirculars = listOf<Circular>() var onlyNewCirculars = listOf<Circular>()
try { return withContext(Dispatchers.IO) {
withContext(Dispatchers.IO) { val result = serverAPI.getCircularsFromServer()
val oldCirculars = circularDao.getCirculars() if (result.second == ServerAPI.Companion.Result.ERROR)
val newCirculars = fetcher.getCircularsFromServer() return@withContext Pair(emptyList(), false)
if (newCirculars.size != oldCirculars.size) {
if (newCirculars.size < oldCirculars.size) {
circularDao.deleteAll()
}
if (returnNewCirculars) { val oldCirculars = circularDao.getCirculars()
val oldCircularsSize = val newCirculars = result.first
if (newCirculars.size < oldCirculars.size) 0 else oldCirculars.size
val circularCount = newCirculars.size - oldCircularsSize if (newCirculars.size != oldCirculars.size) {
onlyNewCirculars = newCirculars.subList(0, circularCount) if (newCirculars.size < oldCirculars.size) {
} circularDao.deleteAll()
circularDao.insertAll(newCirculars)
} }
}
} catch (exception: IOException) {
return Pair(onlyNewCirculars, false)
}
return Pair(onlyNewCirculars, true) 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)
}
Pair(onlyNewCirculars, true)
}
} }
companion object { companion object {
@Volatile @Volatile
private var instance: CircularRepository? = null private var instance: CircularRepository? = null
fun getInstance(circularDao: CircularDao) = fun getInstance(circularDao: CircularDao, serverAPI: ServerAPI) =
instance ?: synchronized(this) { instance ?: synchronized(this) {
instance ?: CircularRepository(circularDao).also { instance = it } instance ?: CircularRepository(circularDao, serverAPI).also { instance = it }
} }
} }
} }

View File

@@ -34,6 +34,7 @@ import net.underdesk.circolapp.R
import net.underdesk.circolapp.adapters.CircularLetterAdapter import net.underdesk.circolapp.adapters.CircularLetterAdapter
import net.underdesk.circolapp.data.AppDatabase import net.underdesk.circolapp.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.CircularLetterViewModel import net.underdesk.circolapp.viewmodels.CircularLetterViewModel
import net.underdesk.circolapp.viewmodels.CircularLetterViewModelFactory import net.underdesk.circolapp.viewmodels.CircularLetterViewModelFactory
@@ -45,7 +46,8 @@ class CircularLetterFragment :
private val circularLetterViewModel: CircularLetterViewModel by viewModels { private val circularLetterViewModel: CircularLetterViewModel by viewModels {
CircularLetterViewModelFactory( CircularLetterViewModelFactory(
CircularRepository.getInstance( CircularRepository.getInstance(
AppDatabase.getInstance(requireContext()).circularDao() AppDatabase.getInstance(requireContext()).circularDao(),
ServerAPI.getInstance(ServerAPI.Companion.Servers.CURIE)
) )
) )
} }

View File

@@ -31,6 +31,7 @@ import net.underdesk.circolapp.R
import net.underdesk.circolapp.adapters.CircularLetterAdapter import net.underdesk.circolapp.adapters.CircularLetterAdapter
import net.underdesk.circolapp.data.AppDatabase import net.underdesk.circolapp.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.FavouritesViewModel import net.underdesk.circolapp.viewmodels.FavouritesViewModel
import net.underdesk.circolapp.viewmodels.FavouritesViewModelFactory import net.underdesk.circolapp.viewmodels.FavouritesViewModelFactory
@@ -39,7 +40,8 @@ class FavouritesFragment : Fragment(), MainActivity.SearchCallback {
private val favouritesViewModel: FavouritesViewModel by viewModels { private val favouritesViewModel: FavouritesViewModel by viewModels {
FavouritesViewModelFactory( FavouritesViewModelFactory(
CircularRepository.getInstance( CircularRepository.getInstance(
AppDatabase.getInstance(requireContext()).circularDao() AppDatabase.getInstance(requireContext()).circularDao(),
ServerAPI.getInstance(ServerAPI.Companion.Servers.CURIE)
) )
) )
} }

View File

@@ -31,6 +31,7 @@ import net.underdesk.circolapp.R
import net.underdesk.circolapp.adapters.CircularLetterAdapter import net.underdesk.circolapp.adapters.CircularLetterAdapter
import net.underdesk.circolapp.data.AppDatabase import net.underdesk.circolapp.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.RemindersViewModel import net.underdesk.circolapp.viewmodels.RemindersViewModel
import net.underdesk.circolapp.viewmodels.RemindersViewModelFactory import net.underdesk.circolapp.viewmodels.RemindersViewModelFactory
@@ -39,7 +40,8 @@ class RemindersFragment : Fragment(), MainActivity.SearchCallback {
private val remindersViewModel: RemindersViewModel by viewModels { private val remindersViewModel: RemindersViewModel by viewModels {
RemindersViewModelFactory( RemindersViewModelFactory(
CircularRepository.getInstance( CircularRepository.getInstance(
AppDatabase.getInstance(requireContext()).circularDao() AppDatabase.getInstance(requireContext()).circularDao(),
ServerAPI.getInstance(ServerAPI.Companion.Servers.CURIE)
) )
) )
} }

View File

@@ -1,80 +0,0 @@
/*
* 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.server
import com.squareup.moshi.Moshi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.underdesk.circolapp.data.Circular
import net.underdesk.circolapp.server.pojo.Response
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import java.io.IOException
class DataFetcher {
companion object {
const val ENDPOINT_URL = "https://www.curiepinerolo.edu.it/wp-json/wp/v2/pages/5958"
private val moshi = Moshi.Builder().build()
private val responseAdapter = moshi.adapter(Response::class.java)
private val client = OkHttpClient()
}
@Throws(IOException::class)
suspend fun getCircularsFromServer(): List<Circular> {
return withContext(Dispatchers.Default) {
val json = retrieveDataFromServer()
val document = Jsoup.parseBodyFragment(json.content.rendered)
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(Circular.generateFromString(element.text(), element.attr("href")))
}
}
list
}
}
@Throws(IOException::class)
private suspend fun retrieveDataFromServer(): Response {
val request = Request.Builder()
.url(ENDPOINT_URL)
.build()
return withContext(Dispatchers.IO) {
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
throw IOException("HTTP error code: ${response.code})")
}
responseAdapter.fromJson(
response.body!!.string()
)!!
}
}
}

View File

@@ -0,0 +1,26 @@
/*
* 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.server
import net.underdesk.circolapp.data.Circular
abstract class Server {
abstract suspend fun getCircularsFromServer(): Pair<List<Circular>, ServerAPI.Companion.Result>
abstract suspend fun newCircularsAvailable(): Pair<Boolean, ServerAPI.Companion.Result>
}

View File

@@ -0,0 +1,64 @@
/*
* 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.server
import net.underdesk.circolapp.data.Circular
import net.underdesk.circolapp.server.curie.CurieServer
class ServerAPI(
private val server: Server
) {
suspend fun getCircularsFromServer(): Pair<List<Circular>, Result> {
val newCircularsAvailable = server.newCircularsAvailable()
if (newCircularsAvailable.second == Result.ERROR)
return Pair(emptyList(), Result.ERROR)
if (!newCircularsAvailable.first)
return Pair(emptyList(), Result.SUCCESS)
return server.getCircularsFromServer()
}
companion object {
enum class Servers {
CURIE, PORPORATO
}
enum class Result {
SUCCESS, ERROR
}
@Volatile
private var instance: ServerAPI? = null
fun getInstance(server: Servers): ServerAPI {
return instance ?: synchronized(this) {
instance ?: createServerAPI(server).also { instance = it }
}
}
private fun createServerAPI(server: Servers): ServerAPI {
return when (server) {
Servers.CURIE -> ServerAPI(CurieServer())
Servers.PORPORATO -> TODO()
}
}
}
}

View File

@@ -0,0 +1,71 @@
package net.underdesk.circolapp.server.curie
import com.squareup.moshi.Moshi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.underdesk.circolapp.data.Circular
import net.underdesk.circolapp.server.Server
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.server.curie.pojo.Response
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import java.io.IOException
class CurieServer : Server() {
private val moshi = Moshi.Builder().build()
private val responseAdapter = moshi.adapter(Response::class.java)
private val client = OkHttpClient()
override suspend fun getCircularsFromServer(): Pair<List<Circular>, ServerAPI.Companion.Result> {
return try {
withContext(Dispatchers.Default) {
val json = retrieveDataFromServer()
val document = Jsoup.parseBodyFragment(json.content.rendered)
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(Circular.generateFromString(element.text(), element.attr("href")))
}
}
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)
}
@Throws(IOException::class)
private suspend fun retrieveDataFromServer(): Response {
val request = Request.Builder()
.url(ENDPOINT_URL)
.build()
return withContext(Dispatchers.IO) {
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
throw IOException("HTTP error code: ${response.code})")
}
responseAdapter.fromJson(
response.body!!.string()
)!!
}
}
companion object {
const val ENDPOINT_URL = "https://www.curiepinerolo.edu.it/wp-json/wp/v2/pages/5958"
}
}

View File

@@ -1,4 +1,4 @@
package net.underdesk.circolapp.server.pojo package net.underdesk.circolapp.server.curie.pojo
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass

View File

@@ -1,4 +1,4 @@
package net.underdesk.circolapp.server.pojo package net.underdesk.circolapp.server.curie.pojo
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass

View File

@@ -36,6 +36,7 @@ import net.underdesk.circolapp.R
import net.underdesk.circolapp.data.AppDatabase import net.underdesk.circolapp.data.AppDatabase
import net.underdesk.circolapp.data.Circular import net.underdesk.circolapp.data.Circular
import net.underdesk.circolapp.data.CircularRepository import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class PollWork(appContext: Context, workerParams: WorkerParameters) : class PollWork(appContext: Context, workerParams: WorkerParameters) :
@@ -85,7 +86,8 @@ class PollWork(appContext: Context, workerParams: WorkerParameters) :
override suspend fun doWork(): Result = coroutineScope { override suspend fun doWork(): Result = coroutineScope {
val circularRepository = CircularRepository.getInstance( val circularRepository = CircularRepository.getInstance(
AppDatabase.getInstance(applicationContext).circularDao() AppDatabase.getInstance(applicationContext).circularDao(),
ServerAPI.getInstance(ServerAPI.Companion.Servers.CURIE)
) )
val result = circularRepository.updateCirculars() val result = circularRepository.updateCirculars()