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,20 +2,23 @@ package net.underdesk.circolapp.data
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.underdesk.circolapp.server.DataFetcher
import java.io.IOException
import net.underdesk.circolapp.server.ServerAPI
class CircularRepository(
val circularDao: CircularDao,
private val fetcher: DataFetcher = DataFetcher()
private val serverAPI: ServerAPI
) {
suspend fun updateCirculars(returnNewCirculars: Boolean = true): Pair<List<Circular>, Boolean> {
var onlyNewCirculars = listOf<Circular>()
try {
withContext(Dispatchers.IO) {
return withContext(Dispatchers.IO) {
val result = serverAPI.getCircularsFromServer()
if (result.second == ServerAPI.Companion.Result.ERROR)
return@withContext Pair(emptyList(), false)
val oldCirculars = circularDao.getCirculars()
val newCirculars = fetcher.getCircularsFromServer()
val newCirculars = result.first
if (newCirculars.size != oldCirculars.size) {
if (newCirculars.size < oldCirculars.size) {
circularDao.deleteAll()
@@ -31,21 +34,17 @@ class CircularRepository(
circularDao.insertAll(newCirculars)
}
Pair(onlyNewCirculars, true)
}
} catch (exception: IOException) {
return Pair(onlyNewCirculars, false)
}
return Pair(onlyNewCirculars, true)
}
companion object {
@Volatile
private var instance: CircularRepository? = null
fun getInstance(circularDao: CircularDao) =
fun getInstance(circularDao: CircularDao, serverAPI: ServerAPI) =
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.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.CircularLetterViewModel
import net.underdesk.circolapp.viewmodels.CircularLetterViewModelFactory
@@ -45,7 +46,8 @@ class CircularLetterFragment :
private val circularLetterViewModel: CircularLetterViewModel by viewModels {
CircularLetterViewModelFactory(
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.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.FavouritesViewModel
import net.underdesk.circolapp.viewmodels.FavouritesViewModelFactory
@@ -39,7 +40,8 @@ class FavouritesFragment : Fragment(), MainActivity.SearchCallback {
private val favouritesViewModel: FavouritesViewModel by viewModels {
FavouritesViewModelFactory(
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.data.AppDatabase
import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import net.underdesk.circolapp.viewmodels.RemindersViewModel
import net.underdesk.circolapp.viewmodels.RemindersViewModelFactory
@@ -39,7 +40,8 @@ class RemindersFragment : Fragment(), MainActivity.SearchCallback {
private val remindersViewModel: RemindersViewModel by viewModels {
RemindersViewModelFactory(
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

View File

@@ -1,4 +1,4 @@
package net.underdesk.circolapp.server.pojo
package net.underdesk.circolapp.server.curie.pojo
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.Circular
import net.underdesk.circolapp.data.CircularRepository
import net.underdesk.circolapp.server.ServerAPI
import java.util.concurrent.TimeUnit
class PollWork(appContext: Context, workerParams: WorkerParameters) :
@@ -85,7 +86,8 @@ class PollWork(appContext: Context, workerParams: WorkerParameters) :
override suspend fun doWork(): Result = coroutineScope {
val circularRepository = CircularRepository.getInstance(
AppDatabase.getInstance(applicationContext).circularDao()
AppDatabase.getInstance(applicationContext).circularDao(),
ServerAPI.getInstance(ServerAPI.Companion.Servers.CURIE)
)
val result = circularRepository.updateCirculars()