check qispos status and show message if unavailable
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Jannik 2020-08-16 21:30:18 +02:00
parent 2807843d25
commit 953b4825a9
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
5 changed files with 83 additions and 10 deletions

View File

@ -27,6 +27,7 @@ import android.util.Log
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jsoup.HttpStatusException
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.R
@ -51,6 +52,34 @@ class QISPOSParser(val context: Context) {
private val baseURL = "https://notenverwaltung.hs-offenburg.de" private val baseURL = "https://notenverwaltung.hs-offenburg.de"
private val loginPath = "/qispos/rds?state=user&type=1&category=auth.login&startpage=portal.vm&breadCrumbSource=portal" private val loginPath = "/qispos/rds?state=user&type=1&category=auth.login&startpage=portal.vm&breadCrumbSource=portal"
/**
* check if qispos is available
* @return a http status code, 999 if no HttpStatusException supplied
*/
fun checkQISPOSStatus(): Int {
return runBlocking {
withContext(Dispatchers.IO) {
val socketFactory = createSSLSocketFactory()
try {
val res = Jsoup.connect(baseURL + loginPath)
.sslSocketFactory(socketFactory)
.followRedirects(true)
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
.execute()
res.statusCode()
} catch (exHttp: HttpStatusException) {
exHttp.statusCode
} catch (ex: Exception) {
Log.e(className, "Error while checking status", ex)
999
}
}
}
}
/** /**
* parse the html from readGrades() * parse the html from readGrades()
* @return a SortedMap, each entry is a semester, each semester has a ArrayList with subjects * @return a SortedMap, each entry is a semester, each semester has a ArrayList with subjects

View File

@ -22,18 +22,17 @@
package org.mosad.seil0.projectlaogai.fragments package org.mosad.seil0.projectlaogai.fragments
import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.android.synthetic.main.fragment_grades.* import kotlinx.android.synthetic.main.fragment_grades.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.QISPOSParser import org.mosad.seil0.projectlaogai.controller.QISPOSParser
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
@ -49,19 +48,27 @@ class GradesFragment : Fragment() {
private lateinit var refreshLayoutGrades: SwipeRefreshLayout private lateinit var refreshLayoutGrades: SwipeRefreshLayout
private lateinit var parser: QISPOSParser
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_grades, container, false) val view: View = inflater.inflate(R.layout.fragment_grades, container, false)
refreshLayoutGrades = view.findViewById(R.id.refreshLayout_Grades) refreshLayoutGrades = view.findViewById(R.id.refreshLayout_Grades)
refreshLayoutGrades.isEnabled = false // disable swipe refreshLayoutGrades.isEnabled = false // disable swipe
if (checkCredentials()) { parser = QISPOSParser(context!!)// init the parser
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (checkCredentials() && checkQisposStatus()) {
GlobalScope.launch(Dispatchers.Default) { GlobalScope.launch(Dispatchers.Default) {
addGrades() addGrades()
} }
} }
return view
} }
/** /**
@ -92,13 +99,35 @@ class GradesFragment : Fragment() {
return credentialsPresent return credentialsPresent
} }
/**
* check if qispos is available, if not show an error
*/
private fun checkQisposStatus(): Boolean {
val statusCode = parser.checkQISPOSStatus()
val infoText = resources.getString(when(statusCode) {
503 -> R.string.qispos_unavailable
else -> R.string.qispos_generic_error
})
val img = ResourcesCompat.getDrawable(resources, R.drawable.ic_error_outline_black_24dp, null)?.apply {
bounds = Rect(0, 0, 75, 75)
}
txtView_Loading?.apply {
text = infoText
setCompoundDrawables(null, null, null, img)
}
return statusCode == 200
}
// add the grades to the layout, async // add the grades to the layout, async
private fun addGrades() = GlobalScope.launch(Dispatchers.Default) { private fun addGrades() = GlobalScope.launch(Dispatchers.Default) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
refreshLayout_Grades.isRefreshing = true refreshLayout_Grades.isRefreshing = true
} }
val parser = QISPOSParser(context!!)
val grades = parser.parseGrades() val grades = parser.parseGrades()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -137,7 +166,7 @@ class GradesFragment : Fragment() {
// disable sub-subject if not set // disable sub-subject if not set
if (subSubject == null) if (subSubject == null)
subjectLayout.disableSubSubject() subjectLayout.disableSubSubject()
// disable divider if last element // disable divider if last element
if (index == semester.value.lastIndex || semester.value.indexOf(subSubject) == semester.value.lastIndex) if (index == semester.value.lastIndex || semester.value.indexOf(subSubject) == semester.value.lastIndex)
subjectLayout.disableDivider() subjectLayout.disableDivider()
@ -151,6 +180,8 @@ class GradesFragment : Fragment() {
} }
} }
val txtViewLegal = TextView(context).apply { val txtViewLegal = TextView(context).apply {
text = resources.getString(R.string.without_guarantee) text = resources.getString(R.string.without_guarantee)
textAlignment = View.TEXT_ALIGNMENT_CENTER textAlignment = View.TEXT_ALIGNMENT_CENTER

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"
android:fillColor="#000000"/>
</vector>

View File

@ -42,6 +42,8 @@
<!-- fragment_grades --> <!-- fragment_grades -->
<string name="loading_from_hs">Lade Daten von den Hochschul Servern.\nDas kann eine Weile dauern.</string> <string name="loading_from_hs">Lade Daten von den Hochschul Servern.\nDas kann eine Weile dauern.</string>
<string name="credentials_missing">Diese Funktion benötigt deine Login-Daten. Bitte logge dich über die Einstellungen ein.</string> <string name="credentials_missing">Diese Funktion benötigt deine Login-Daten. Bitte logge dich über die Einstellungen ein.</string>
<string name="qispos_unavailable">Die Notenverwaltung ist zur Zeit nicht ereichbar.\nVersuche es später noch einmal.\n</string>
<string name="qispos_generic_error">Error.\nVersuche es später noch einmal.\n</string>
<string name="without_guarantee">Alle Angaben ohne Gewähr.</string> <string name="without_guarantee">Alle Angaben ohne Gewähr.</string>
<!-- fragment_settings --> <!-- fragment_settings -->

View File

@ -22,7 +22,7 @@
<string name="course_heading">Course</string> <string name="course_heading">Course</string>
<string name="course_desc_on">Select your current course.\nAdditional lessons can be added later.</string> <string name="course_desc_on">Select your current course.\nAdditional lessons can be added later.</string>
<string name="login_heading">Login</string> <string name="login_heading">Login</string>
<string name="login_desc_on">Project Laogai can connect to the HIS Online-Portal. Your Login-Data will be stored encrypted on your device. This feature is provided "as is", without any guarantee.</string> <string name="login_desc_on">Project Laogai can connect to the Qispos Online-Portal. Your Login-Data will be stored encrypted on your device. This feature is provided "as is", without any guarantee.</string>
<string name="email">E-Mail</string> <string name="email">E-Mail</string>
<string name="password">Password</string> <string name="password">Password</string>
<string name="login">login</string> <string name="login">login</string>
@ -44,6 +44,8 @@
<!-- fragment_grades --> <!-- fragment_grades -->
<string name="loading_from_hs">Loading data from the university servers.\nThis may take a while.</string> <string name="loading_from_hs">Loading data from the university servers.\nThis may take a while.</string>
<string name="credentials_missing">This feature needs your Login-Data to work. Please login via the settings.</string> <string name="credentials_missing">This feature needs your Login-Data to work. Please login via the settings.</string>
<string name="qispos_unavailable">The Qispos server is currently unavailable.\nPlease try again later.\n</string>
<string name="qispos_generic_error">Error.\nPlease try again later.\n</string>
<string name="without_guarantee">All information is supplied without guarantee.</string> <string name="without_guarantee">All information is supplied without guarantee.</string>
<!-- fragment_settings --> <!-- fragment_settings -->