mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-18 04:46:44 -06:00
[API/Usos] Add syncing Courses and Terms.
This commit is contained in:
parent
93ccdbdeb7
commit
8097e8d06d
@ -203,6 +203,7 @@ const val ERROR_PODLASIE_API_DATA_MISSING = 632
|
||||
const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702
|
||||
const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703
|
||||
const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704
|
||||
const val ERROR_USOS_API_INCOMPLETE_RESPONSE = 705
|
||||
|
||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||
|
||||
|
@ -25,7 +25,7 @@ class DataUsos(
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateUserCode() = "$schoolId:${studentNumber ?: studentId}"
|
||||
override fun generateUserCode() = "$schoolId:${profile?.studentNumber ?: studentId}"
|
||||
|
||||
var schoolId: String?
|
||||
get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId }
|
||||
@ -67,13 +67,8 @@ class DataUsos(
|
||||
set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value }
|
||||
private var mOauthTokenIsUser: Boolean? = null
|
||||
|
||||
var studentId: String?
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
||||
var studentId: Int
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
|
||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||
private var mStudentId: String? = null
|
||||
|
||||
var studentNumber: String?
|
||||
get() { mStudentNumber = mStudentNumber ?: profile?.getStudentData("studentNumber", null); return mStudentNumber }
|
||||
set(value) { profile?.putStudentData("studentNumber", value) ?: return; mStudentNumber = value }
|
||||
private var mStudentNumber: String? = null
|
||||
private var mStudentId: Int? = null
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||
@ -58,9 +59,9 @@ class Usos(
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
UsosLogin(data) {
|
||||
/*UsosData(data) {
|
||||
UsosData(data) {
|
||||
completed()
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,15 +4,26 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.usos
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED
|
||||
import pl.szczodrzynski.edziennik.data.api.FEATURE_STUDENT_INFO
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS
|
||||
import pl.szczodrzynski.edziennik.data.api.FEATURE_TEAM_INFO
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||
|
||||
const val ENDPOINT_USOS_API_USER = 7000
|
||||
const val ENDPOINT_USOS_API_TERMS = 7010
|
||||
const val ENDPOINT_USOS_API_COURSES = 7020
|
||||
|
||||
val UsosFeatures = listOf(
|
||||
Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API,
|
||||
), listOf(LOGIN_METHOD_USOS_API)),
|
||||
|
||||
Feature(LOGIN_TYPE_USOS, FEATURE_SCHOOL_INFO, listOf(
|
||||
ENDPOINT_USOS_API_TERMS to LOGIN_METHOD_USOS_API,
|
||||
), listOf(LOGIN_METHOD_USOS_API)),
|
||||
|
||||
Feature(LOGIN_TYPE_USOS, FEATURE_TEAM_INFO, listOf(
|
||||
ENDPOINT_USOS_API_COURSES to LOGIN_METHOD_USOS_API,
|
||||
), listOf(LOGIN_METHOD_USOS_API)),
|
||||
)
|
||||
|
@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.AbsCallbackHandler
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
@ -17,10 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||
import pl.szczodrzynski.edziennik.data.api.SERVER_USER_AGENT
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.ext.hmacSHA1
|
||||
import pl.szczodrzynski.edziennik.ext.toQueryString
|
||||
import pl.szczodrzynski.edziennik.ext.urlEncode
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
import java.util.UUID
|
||||
@ -42,6 +38,9 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
protected fun JsonObject.getLangString(key: String) =
|
||||
this.getJsonObject(key)?.getString("pl")
|
||||
|
||||
private fun valueToString(value: Any) = when (value) {
|
||||
is String -> value
|
||||
is Number -> value.toString()
|
||||
@ -74,15 +73,22 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
||||
fun <T> apiRequest(
|
||||
tag: String,
|
||||
service: String,
|
||||
params: Map<String, Any>,
|
||||
params: Map<String, Any>? = null,
|
||||
fields: List<Any>? = null,
|
||||
responseType: ResponseType,
|
||||
onSuccess: (data: T, response: Response?) -> Unit,
|
||||
) {
|
||||
val url = "${data.instanceUrl}services/$service"
|
||||
d(tag, "Request: Usos/Api - $url")
|
||||
val formData = params.mapValues {
|
||||
valueToString(it.value)
|
||||
}
|
||||
|
||||
val formData = mutableMapOf<String, String>()
|
||||
if (params != null)
|
||||
formData.putAll(params.mapValues {
|
||||
valueToString(it.value)
|
||||
})
|
||||
if (fields != null)
|
||||
formData["fields"] = valueToString(fields)
|
||||
|
||||
val auth = mutableMapOf(
|
||||
"realm" to url,
|
||||
"oauth_consumer_key" to (data.oauthConsumerKey ?: ""),
|
||||
|
@ -7,7 +7,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web.TemplateWebSample
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiCourses
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTerms
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class UsosData(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||
@ -39,9 +43,17 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||
d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||
when (endpointId) {
|
||||
ENDPOINT_USOS_API_USER -> {
|
||||
/*ENDPOINT_USOS_API_USER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||
// TemplateWebSample(data, lastSync, onSuccess)
|
||||
}*/
|
||||
ENDPOINT_USOS_API_TERMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
||||
UsosApiTerms(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_USOS_API_COURSES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
||||
UsosApiCourses(data, lastSync, onSuccess)
|
||||
}
|
||||
else -> onSuccess(endpointId)
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class UsosApiCourses(
|
||||
override val data: DataUsos,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit,
|
||||
) : UsosApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "UsosApiCourses"
|
||||
}
|
||||
|
||||
init {
|
||||
apiRequest<JsonObject>(
|
||||
tag = TAG,
|
||||
service = "courses/user",
|
||||
fields = listOf(
|
||||
// "terms" to listOf("id", "name", "start_date", "end_date"),
|
||||
"course_editions" to listOf(
|
||||
"course_id",
|
||||
// "course_name",
|
||||
// "term_id",
|
||||
"user_groups" to listOf(
|
||||
"course_unit_id",
|
||||
"group_number",
|
||||
"class_type",
|
||||
"class_type_id",
|
||||
// "lecturers",
|
||||
),
|
||||
),
|
||||
),
|
||||
responseType = ResponseType.OBJECT,
|
||||
) { json, response ->
|
||||
if (!processResponse(json)) {
|
||||
data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response)
|
||||
return@apiRequest
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_USOS_API_COURSES, 2 * DAY)
|
||||
onSuccess(ENDPOINT_USOS_API_COURSES)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processResponse(json: JsonObject): Boolean {
|
||||
// val term = json.getJsonArray("terms")?.firstOrNull() ?: return false
|
||||
val courseEditions = json.getJsonObject("course_editions")
|
||||
?.entrySet()
|
||||
?.flatMap { it.value.asJsonArray }
|
||||
?.map { it.asJsonObject } ?: return false
|
||||
|
||||
var hasValidTeam = false
|
||||
for (courseEdition in courseEditions) {
|
||||
val courseId = courseEdition.getString("course_id") ?: continue
|
||||
// val courseName = courseEdition.getLangString("course_name") ?: continue
|
||||
val userGroups = courseEdition.getJsonArray("user_groups")?.asJsonObjectList() ?: continue
|
||||
for (userGroup in userGroups) {
|
||||
val courseUnitId = userGroup.getLong("course_unit_id") ?: continue
|
||||
val groupNumber = userGroup.getInt("group_number") ?: continue
|
||||
val classType = userGroup.getLangString("class_type") ?: continue
|
||||
val classTypeId = userGroup.getString("class_type_id") ?: continue
|
||||
|
||||
data.teamList.put(courseUnitId, Team(
|
||||
profileId,
|
||||
courseUnitId,
|
||||
"$classType $groupNumber ($courseId)",
|
||||
2,
|
||||
"${data.schoolId}:${courseId} $classTypeId$groupNumber",
|
||||
-1,
|
||||
))
|
||||
hasValidTeam = true
|
||||
}
|
||||
}
|
||||
return hasValidTeam
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class UsosApiTerms(
|
||||
override val data: DataUsos,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit,
|
||||
) : UsosApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "UsosApiTerms"
|
||||
}
|
||||
|
||||
init {
|
||||
apiRequest<JsonArray>(
|
||||
tag = TAG,
|
||||
service = "terms/search",
|
||||
params = mapOf(
|
||||
"query" to Date.getToday().year.toString(),
|
||||
),
|
||||
responseType = ResponseType.ARRAY,
|
||||
) { json, response ->
|
||||
if (!processResponse(json)) {
|
||||
data.error(UsosApiCourses.TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response)
|
||||
return@apiRequest
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_USOS_API_TERMS, 7 * DAY)
|
||||
onSuccess(ENDPOINT_USOS_API_TERMS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processResponse(json: JsonArray): Boolean {
|
||||
val dates = mutableSetOf<Date>()
|
||||
for (term in json.asJsonObjectList()) {
|
||||
if (!term.getBoolean("is_active", false))
|
||||
continue
|
||||
val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) }
|
||||
val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) }
|
||||
if (startDate != null)
|
||||
dates += startDate
|
||||
if (finishDate != null)
|
||||
dates += finishDate
|
||||
}
|
||||
val datesSorted = dates.sorted()
|
||||
if (datesSorted.size != 3)
|
||||
return false
|
||||
profile?.studentSchoolYearStart = datesSorted[0].year
|
||||
profile?.dateSemester1Start = datesSorted[0]
|
||||
profile?.dateSemester2Start = datesSorted[1]
|
||||
profile?.dateYearEnd = datesSorted[2]
|
||||
return true
|
||||
}
|
||||
}
|
@ -68,9 +68,9 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||
accountName = null, // student account
|
||||
studentData = JsonObject(
|
||||
"studentId" to json.getInt("id"),
|
||||
"studentNumber" to json.getInt("student_number"),
|
||||
),
|
||||
).also {
|
||||
it.studentNumber = json.getInt("student_number", -1)
|
||||
it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id")
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,10 @@ open class Profile(
|
||||
MainActivity.DRAWER_ITEM_GRADES,
|
||||
MainActivity.DRAWER_ITEM_HOMEWORK
|
||||
)
|
||||
LOGIN_TYPE_USOS -> listOf(
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA
|
||||
)
|
||||
else -> listOf(
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
|
Loading…
x
Reference in New Issue
Block a user