[APIv2] Update API, add endpoint choosing algorithm

This commit is contained in:
Kuba Szczodrzyński 2019-10-01 07:03:12 +02:00
parent 7da3101678
commit d2f06a256f
19 changed files with 346 additions and 183 deletions

View File

@ -1 +0,0 @@
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":2600,"versionName":"2.6","enabled":true,"outputFile":"Edziennik_2600_debug.apk","fullName":"debug","baseName":"debug"},"path":"Edziennik_2600_debug.apk","properties":{}}]

View File

@ -16,6 +16,5 @@ open class Api(open val data: Data) {
Crashlytics.logException(e) Crashlytics.logException(e)
} }
data.callback.onError(null, error)
} }
} }

View File

@ -4,6 +4,9 @@
package pl.szczodrzynski.edziennik.api.v2 package pl.szczodrzynski.edziennik.api.v2
const val GET = 0
const val POST = 1
const val LIBRUS_USER_AGENT = "Dalvik/2.1.0 Android LibrusMobileApp" const val LIBRUS_USER_AGENT = "Dalvik/2.1.0 Android LibrusMobileApp"
const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0" const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0"
const val LIBRUS_CLIENT_ID = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv" const val LIBRUS_CLIENT_ID = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv"

View File

@ -54,7 +54,7 @@ val endpoints = listOf(
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf(
ENDPOINT_LIBRUS_API_TIMETABLES, ENDPOINT_LIBRUS_API_TIMETABLES,
ENDPOINT_LIBRUS_API_SUBSTITUTIONS ENDPOINT_LIBRUS_API_SUBSTITUTIONS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf(
ENDPOINT_LIBRUS_API_EVENTS, ENDPOINT_LIBRUS_API_EVENTS,
ENDPOINT_LIBRUS_API_EVENT_TYPES, ENDPOINT_LIBRUS_API_EVENT_TYPES,
@ -62,7 +62,7 @@ val endpoints = listOf(
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS, ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS,
ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS, ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS,
ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
ENDPOINT_LIBRUS_API_NORMAL_GC, ENDPOINT_LIBRUS_API_NORMAL_GC,
ENDPOINT_LIBRUS_API_POINT_GC, ENDPOINT_LIBRUS_API_POINT_GC,
@ -76,58 +76,65 @@ val endpoints = listOf(
ENDPOINT_LIBRUS_API_TEXT_GRADES, ENDPOINT_LIBRUS_API_TEXT_GRADES,
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES, ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES,
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
ENDPOINT_LIBRUS_API_HOMEWORK ENDPOINT_LIBRUS_API_HOMEWORK
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_NOTICES, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_NOTICES, listOf(
ENDPOINT_LIBRUS_API_NOTICES ENDPOINT_LIBRUS_API_NOTICES
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCES, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCES, listOf(
ENDPOINT_LIBRUS_API_ATTENDANCE, ENDPOINT_LIBRUS_API_ATTENDANCE,
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf(
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
ENDPOINT_LIBRUS_API_ME ENDPOINT_LIBRUS_API_ME
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf(
ENDPOINT_LIBRUS_API_SCHOOLS, ENDPOINT_LIBRUS_API_SCHOOLS,
ENDPOINT_LIBRUS_API_UNITS ENDPOINT_LIBRUS_API_UNITS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf(
ENDPOINT_LIBRUS_API_CLASSES ENDPOINT_LIBRUS_API_CLASSES
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf(
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf(
ENDPOINT_LIBRUS_API_LUCKY_NUMBER ENDPOINT_LIBRUS_API_LUCKY_NUMBER
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf(
ENDPOINT_LIBRUS_API_USERS ENDPOINT_LIBRUS_API_USERS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf(
ENDPOINT_LIBRUS_API_SUBJECTS ENDPOINT_LIBRUS_API_SUBJECTS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf(
ENDPOINT_LIBRUS_API_CLASSROOMS ENDPOINT_LIBRUS_API_CLASSROOMS
), LOGIN_METHOD_LIBRUS_API), ), listOf(LOGIN_METHOD_LIBRUS_API)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
ENDPOINT_LIBRUS_SYNERGIA_INFO ENDPOINT_LIBRUS_SYNERGIA_INFO
), LOGIN_METHOD_LIBRUS_SYNERGIA), ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf( Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf(
ENDPOINT_LIBRUS_SYNERGIA_INFO ENDPOINT_LIBRUS_SYNERGIA_INFO
), LOGIN_METHOD_LIBRUS_SYNERGIA), ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( /*Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
ENDPOINT_LIBRUS_SYNERGIA_GRADES ENDPOINT_LIBRUS_SYNERGIA_GRADES
), LOGIN_METHOD_LIBRUS_SYNERGIA), ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),*/
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_RECEIVED), LOGIN_METHOD_LIBRUS_MESSAGES),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_OUTBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_SENT), LOGIN_METHOD_LIBRUS_MESSAGES) Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
ENDPOINT_LIBRUS_API_NORMAL_GC,
ENDPOINT_LIBRUS_API_NORMAL_GRADES,
ENDPOINT_LIBRUS_SYNERGIA_GRADES
), listOf(LOGIN_METHOD_LIBRUS_API, LOGIN_METHOD_LIBRUS_SYNERGIA)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_RECEIVED), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)),
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_OUTBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_SENT), listOf(LOGIN_METHOD_LIBRUS_MESSAGES))
) )
/* /*

View File

@ -5,18 +5,28 @@
package pl.szczodrzynski.edziennik.api.v2.librus package pl.szczodrzynski.edziennik.api.v2.librus
import android.content.Context import android.content.Context
import android.util.Log
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.api.AppError import pl.szczodrzynski.edziennik.api.AppError
import pl.szczodrzynski.edziennik.api.Edziennik
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410 import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
import pl.szczodrzynski.edziennik.api.v2.endpoints
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.librusLoginMethods
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.models.Endpoint
import pl.szczodrzynski.edziennik.datamodels.LoginStore import pl.szczodrzynski.edziennik.datamodels.LoginStore
import pl.szczodrzynski.edziennik.datamodels.Profile import pl.szczodrzynski.edziennik.datamodels.Profile
import pl.szczodrzynski.edziennik.datamodels.ProfileFull import pl.szczodrzynski.edziennik.datamodels.ProfileFull
import kotlin.math.max
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface { class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object {
const val TAG = "Librus"
}
val internalErrorList = mutableListOf<Int>() val internalErrorList = mutableListOf<Int>()
val data: DataLibrus val data: DataLibrus
@ -29,43 +39,97 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
} }
override fun sync(featureIds: List<Int>) { override fun sync(featureIds: List<Int>) {
val possibleLoginMethods = data.loginMethods.toMutableList()
for (loginMethod in librusLoginMethods) {
if (loginMethod.isPossible(profile, loginStore))
possibleLoginMethods += loginMethod.loginMethodId
}
var highestLoginMethod = 0
var targetEndpointList = mutableListOf<Endpoint>()
for (featureId in featureIds) {
endpoints.filter { it.featureId == featureId }.forEach { endpoint ->
if (possibleLoginMethods.containsAll(endpoint.requiredLoginMethods)) {
targetEndpointList.add(endpoint)
highestLoginMethod = max(highestLoginMethod, endpoint.requiredLoginMethods.max() ?: 0)
}
}
}
targetEndpointList = targetEndpointList
.sortedWith(compareBy(Endpoint::featureId, Endpoint::priority))
.distinctBy { it.featureId }
.toMutableList()
Log.d(TAG, targetEndpointList.toString())
/*
INPUT: [
FEATURE_GRADES,
FEATURE_STUDENT_INFO,
FEATURE_STUDENT_NUMBER
]
OUTPUT: [
Endpoint(loginType=2,
featureId=FEATURE_GRADES, endpointIds=[
ENDPOINT_LIBRUS_API_NORMAL_GC,
ENDPOINT_LIBRUS_API_NORMAL_GRADES,
ENDPOINT_LIBRUS_SYNERGIA_GRADES
], requiredLoginMethods=[
LOGIN_METHOD_LIBRUS_API,
LOGIN_METHOD_LIBRUS_SYNERGIA
]),
Endpoint(loginType=2,
featureId=FEATURE_STUDENT_INFO, endpointIds=[
ENDPOINT_LIBRUS_API_ME
], requiredLoginMethods=[
LOGIN_METHOD_LIBRUS_API
]),
Endpoint(loginType=2,
featureId=FEATURE_STUDENT_NUMBER, endpointIds=[
ENDPOINT_LIBRUS_SYNERGIA_INFO
], requiredLoginMethods=[
LOGIN_METHOD_LIBRUS_SYNERGIA
])
]
*/
} }
override fun getMessage(messageId: Int) { override fun getMessage(messageId: Int) {
} }
private fun wrapCallback(callback: SyncCallback): SyncCallback { private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : SyncCallback { return object : EdziennikCallback {
override fun onSuccess(activityContext: Context?, profileFull: ProfileFull?) { override fun onCompleted() {
callback.onSuccess(activityContext, profileFull) callback.onCompleted()
} }
override fun onProgress(progressStep: Int) { override fun onProgress(step: Int) {
callback.onProgress(progressStep) callback.onProgress(step)
} }
override fun onActionStarted(stringResId: Int) { override fun onStartProgress(stringRes: Int) {
callback.onActionStarted(stringResId) callback.onStartProgress(stringRes)
} }
override fun onLoginFirst(profileList: MutableList<Profile>?, loginStore: LoginStore?) { override fun onError(apiError: ApiError) {
callback.onLoginFirst(profileList, loginStore) when (apiError.errorCode) {
}
override fun onError(activityContext: Context?, error: AppError) {
when (error.errorCode) {
in internalErrorList -> { in internalErrorList -> {
// finish immediately if the same error occurs twice during the same sync // finish immediately if the same error occurs twice during the same sync
callback.onError(activityContext, error) callback.onError(apiError)
} }
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> { CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
internalErrorList.add(error.errorCode) internalErrorList.add(apiError.errorCode)
loginStore.removeLoginData("refreshToken") // force a clean login loginStore.removeLoginData("refreshToken") // force a clean login
//loginLibrus() //loginLibrus()
} }
else -> callback.onError(activityContext, error) else -> callback.onError(apiError)
} }
} }
} }

View File

@ -11,9 +11,11 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.api.AppError import pl.szczodrzynski.edziennik.api.AppError
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrus import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrus
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusPortal import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusPortal
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.datamodels.LoginStore import pl.szczodrzynski.edziennik.datamodels.LoginStore
import pl.szczodrzynski.edziennik.datamodels.Profile import pl.szczodrzynski.edziennik.datamodels.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -47,7 +49,14 @@ class LibrusTest(val app: App) {
fun go() { fun go() {
app.startService(Intent(app, ApiService::class.java)) Librus(app, profile, loginStore, object : EdziennikCallback {
override fun onCompleted() {}
override fun onError(apiError: ApiError) {}
override fun onProgress(step: Int) {}
override fun onStartProgress(stringRes: Int) {}
}).sync(listOf(FEATURE_GRADES, FEATURE_STUDENT_INFO, FEATURE_STUDENT_NUMBER))
//app.startService(Intent(app, ApiService::class.java))
/*val data = DataLibrus(app, profile, loginStore).apply { /*val data = DataLibrus(app, profile, loginStore).apply {
callback = object : ProgressCallback { callback = object : ProgressCallback {

View File

@ -9,106 +9,101 @@ import com.google.gson.JsonObject
import im.wangchao.mhttp.Request import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.JsonCallbackHandler import im.wangchao.mhttp.callback.JsonCallbackHandler
import io.fabric.sdk.android.services.network.HttpRequest.post
import pl.szczodrzynski.edziennik.api.AppError import pl.szczodrzynski.edziennik.api.AppError
import pl.szczodrzynski.edziennik.api.AppError.CODE_MAINTENANCE import pl.szczodrzynski.edziennik.api.AppError.CODE_MAINTENANCE
import pl.szczodrzynski.edziennik.api.AppError.CODE_OTHER import pl.szczodrzynski.edziennik.api.AppError.CODE_OTHER
import pl.szczodrzynski.edziennik.api.v2.Api import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusSynergia
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_API_URL import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_USER_AGENT import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.lang.Exception
import java.net.HttpURLConnection
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
open class LibrusApi(override val data: DataLibrus) : Api(data) { open class LibrusApi(open val data: DataLibrus) {
companion object { companion object {
const val TAG = "LibrusApi" const val TAG = "LibrusApi"
} }
fun apiRequest(endpoint: String, callback: (json: JsonObject?) -> Unit) {
d(TAG, "Requesting $LIBRUS_API_URL/$endpoint") fun apiGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject?) -> Unit) {
val callback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null && response?.parserErrorBody == null) {
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return
}
val error = if (response?.code() == 200) null else
json.getString("Code") ?:
json.getString("Message") ?:
response?.parserErrorBody
error?.let { code ->
when (code) {
"TokenIsExpired" -> ERROR_LIBRUS_API_TOKEN_EXPIRED
"Insufficient scopes" -> ERROR_LIBRUS_API_INSUFFICIENT_SCOPES
"Request is denied" -> ERROR_LIBRUS_API_REQUEST_DENIED
"Resource not found" -> ERROR_LIBRUS_API_RESOURCE_NOT_FOUND
"NotFound" -> ERROR_LIBRUS_API_DATA_NOT_FOUND
"AccessDeny" -> when (json.getString("Message")) {
"Student timetable is not public" -> ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC
else -> ERROR_LIBRUS_API_RESOURCE_ACCESS_DENIED
}
"LuckyNumberIsNotActive" -> ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE
"NotesIsNotActive" -> ERROR_LIBRUS_API_NOTES_NOT_ACTIVE
"InvalidRequest" -> ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS
"Nieprawidłowy węzeł." -> ERROR_LIBRUS_API_INCORRECT_ENDPOINT
else -> ERROR_LIBRUS_API_OTHER
}.let { errorCode ->
data.error(ApiError(tag, errorCode)
.withApiResponse(json)
.withResponse(response))
return
}
}
if (json == null) {
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return
}
try {
onSuccess(json)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_LIBRUS_API_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
// TODO add hotfix for Classrooms 500
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
Request.builder() Request.builder()
.url(if (data.fakeLogin) "http://szkolny.eu/librus/api/$endpoint" else "$LIBRUS_API_URL/$endpoint") .url("$LIBRUS_API_URL/$endpoint")
.userAgent(LIBRUS_USER_AGENT) .userAgent(LIBRUS_USER_AGENT)
.addHeader("Authorization", "Bearer ${data.apiAccessToken}") .addHeader("Authorization", "Bearer ${data.apiAccessToken}")
.get() .apply {
when (method) {
GET -> get()
POST -> post()
}
if (payload != null)
setJsonBody(payload)
}
.allowErrorCode(HTTP_BAD_REQUEST)
.allowErrorCode(HTTP_FORBIDDEN) .allowErrorCode(HTTP_FORBIDDEN)
.allowErrorCode(HTTP_UNAUTHORIZED) .allowErrorCode(HTTP_UNAUTHORIZED)
.allowErrorCode(HTTP_BAD_REQUEST) .callback(callback)
.callback(object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response) {
if (json == null) {
if (response.parserErrorBody != null && response.parserErrorBody == "Nieprawidłowy węzeł.") {
callback(null)
return
}
finishWithError(AppError(TAG, 453, CODE_MAINTENANCE, response))
return
}
if (json.get("Status") != null) {
val message = json.get("Message")
val code = json.get("Code")
d(TAG, "apiRequest Error " + json.get("Status").asString + " " + (if (message == null) "" else message.asString) + " " + (if (code == null) "" else code.asString) + "\n\n" + response.request().url().toString())
if (message != null && message !is JsonNull && message.asString == "Student timetable is not public") {
try {
callback(null)
} catch (e: NullPointerException) {
e.printStackTrace()
d(TAG, "apiRequest exception " + e.message)
finishWithError(AppError(TAG, 503, CODE_OTHER, response, e, json))
}
return
}
if (code != null
&& code !is JsonNull
&& (code.asString == "LuckyNumberIsNotActive"
|| code.asString == "NotesIsNotActive"
|| code.asString == "AccessDeny")) {
try {
callback(null)
} catch (e: NullPointerException) {
e.printStackTrace()
d(TAG, "apiRequest exception " + e.message)
finishWithError(AppError(TAG, 504, CODE_OTHER, response, e, json))
}
return
}
val errorText = json.get("Status").asString + " " + (if (message == null) "" else message.asString) + " " + if (code == null) "" else code.asString
if (code != null && code !is JsonNull && code.asString == "TokenIsExpired") {
finishWithError(AppError(TAG, 74, CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED, errorText, response, json))
return
}
finishWithError(AppError(TAG, 497, CODE_OTHER, errorText, response, json))
return
}
try {
callback(json)
} catch (e: NullPointerException) {
e.printStackTrace()
d(TAG, "apiRequest exception " + e.message)
finishWithError(AppError(TAG, 505, CODE_OTHER, response, e, json))
}
}
override fun onFailure(response: Response, throwable: Throwable) {
if (response.code() == 405) {
// method not allowed
finishWithError(AppError(TAG, 511, CODE_OTHER, response, throwable))
return
}
if (response.code() == 500) {
// TODO: 2019-09-10 dirty hotfix
if ("Classrooms" == endpoint) {
callback(null)
return
}
finishWithError(AppError(TAG, 516, CODE_MAINTENANCE, response, throwable))
return
}
finishWithError(AppError(TAG, 520, CODE_OTHER, response, throwable))
}
})
.build() .build()
.enqueue() .enqueue()
} }

View File

@ -12,8 +12,12 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
class LibrusApiMe(override val data: DataLibrus, class LibrusApiMe(override val data: DataLibrus,
val onSuccess: () -> Unit) : LibrusApi(data) { val onSuccess: () -> Unit) : LibrusApi(data) {
companion object {
const val TAG = "LibrusApiMe"
}
init { init {
apiRequest("Me") { json -> apiGet(TAG, "Me") { json ->
val me = json?.getJsonObject("Me") val me = json?.getJsonObject("Me")
val account = me?.getJsonObject("Account") val account = me?.getJsonObject("Account")
val user = me?.getJsonObject("User") val user = me?.getJsonObject("User")

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.api.v2.librus.login package pl.szczodrzynski.edziennik.api.v2.librus.login
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
@ -31,7 +32,7 @@ class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSucces
loginMethodList = loginMethodList.toHashSet().toMutableList() loginMethodList = loginMethodList.toHashSet().toMutableList()
loginMethodList.sort() loginMethodList.sort()
data.satisfyLoginMethods() //data.satisfyLoginMethods()
nextLoginMethod() nextLoginMethod()
} }
@ -53,24 +54,28 @@ class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSucces
d(TAG, "Using login method $loginMethodId") d(TAG, "Using login method $loginMethodId")
when (loginMethodId) { when (loginMethodId) {
LOGIN_METHOD_LIBRUS_PORTAL -> { LOGIN_METHOD_LIBRUS_PORTAL -> {
data.startProgress(R.string.edziennik_progress_login_librus_portal)
LoginLibrusPortal(data) { LoginLibrusPortal(data) {
data.loginMethods.add(loginMethodId) data.loginMethods.add(loginMethodId)
onSuccess() onSuccess()
} }
} }
LOGIN_METHOD_LIBRUS_API -> { LOGIN_METHOD_LIBRUS_API -> {
data.startProgress(R.string.edziennik_progress_login_librus_api)
LoginLibrusApi(data) { LoginLibrusApi(data) {
data.loginMethods.add(loginMethodId) data.loginMethods.add(loginMethodId)
onSuccess() onSuccess()
} }
} }
LOGIN_METHOD_LIBRUS_SYNERGIA -> { LOGIN_METHOD_LIBRUS_SYNERGIA -> {
data.startProgress(R.string.edziennik_progress_login_librus_synergia)
LoginLibrusSynergia(data) { LoginLibrusSynergia(data) {
data.loginMethods.add(loginMethodId) data.loginMethods.add(loginMethodId)
onSuccess() onSuccess()
} }
} }
LOGIN_METHOD_LIBRUS_MESSAGES -> { LOGIN_METHOD_LIBRUS_MESSAGES -> {
data.startProgress(R.string.edziennik_progress_login_librus_messages)
LoginLibrusMessages(data) { LoginLibrusMessages(data) {
data.loginMethods.add(loginMethodId) data.loginMethods.add(loginMethodId)
onSuccess() onSuccess()

View File

@ -12,6 +12,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
class LoginLibrusApi { class LoginLibrusApi {
@ -28,7 +29,7 @@ class LoginLibrusApi {
this.onSuccess = onSuccess this.onSuccess = onSuccess
if (data.profile == null) { if (data.profile == null) {
data.error(TAG, ERROR_PROFILE_MISSING) data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
return return
} }
@ -41,7 +42,7 @@ class LoginLibrusApi {
LOGIN_MODE_LIBRUS_SYNERGIA -> loginWithSynergia() LOGIN_MODE_LIBRUS_SYNERGIA -> loginWithSynergia()
LOGIN_MODE_LIBRUS_JST -> loginWithJst() LOGIN_MODE_LIBRUS_JST -> loginWithJst()
else -> { else -> {
data.error(TAG, ERROR_INVALID_LOGIN_MODE) data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
} }
} }
} }
@ -49,7 +50,7 @@ class LoginLibrusApi {
private fun loginWithPortal() { private fun loginWithPortal() {
if (!data.loginMethods.contains(LOGIN_METHOD_LIBRUS_PORTAL)) { if (!data.loginMethods.contains(LOGIN_METHOD_LIBRUS_PORTAL)) {
data.error(TAG, ERROR_LOGIN_METHOD_NOT_SATISFIED) data.error(ApiError(TAG, ERROR_LOGIN_METHOD_NOT_SATISFIED))
return return
} }
SynergiaTokenExtractor(data) { SynergiaTokenExtractor(data) {
@ -89,7 +90,7 @@ class LoginLibrusApi {
} }
else { else {
// cannot log in: token expired, no login data present // cannot log in: token expired, no login data present
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
} }
} }
@ -106,14 +107,15 @@ class LoginLibrusApi {
} }
else { else {
// cannot log in: token expired, no login data present // cannot log in: token expired, no login data present
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
} }
} }
private val tokenCallback = object : JsonCallbackHandler() { private val tokenCallback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) { override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null) { if (json == null) {
data.error(TAG, ERROR_RESPONSE_EMPTY, response) data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return return
} }
if (response?.code() != 200) json.getString("error")?.let { error -> if (response?.code() != 200) json.getString("error")?.let { error ->
@ -127,7 +129,9 @@ class LoginLibrusApi {
"invalid_grant" -> ERROR_LOGIN_LIBRUS_API_INVALID_GRANT "invalid_grant" -> ERROR_LOGIN_LIBRUS_API_INVALID_GRANT
else -> ERROR_LOGIN_LIBRUS_API_OTHER else -> ERROR_LOGIN_LIBRUS_API_OTHER
}.let { errorCode -> }.let { errorCode ->
data.error(TAG, errorCode, apiResponse = json, response = response) data.error(ApiError(TAG, errorCode)
.withApiResponse(json)
.withResponse(response))
return return
} }
} }
@ -138,12 +142,17 @@ class LoginLibrusApi {
data.apiTokenExpiryTime = response.getUnixDate() + json.getInt("expires_in", 86400) data.apiTokenExpiryTime = response.getUnixDate() + json.getInt("expires_in", 86400)
onSuccess() onSuccess()
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_API_TOKEN, response, e, json) data.error(ApiError(TAG, EXCEPTION_LOGIN_LIBRUS_API_TOKEN)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
} }
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }

View File

@ -12,6 +12,7 @@ import okhttp3.HttpUrl
import okhttp3.internal.http.HttpDate import okhttp3.internal.http.HttpDate
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.currentTimeUnix import pl.szczodrzynski.edziennik.currentTimeUnix
import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.getUnixDate
@ -22,7 +23,7 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
init { run { init { run {
if (data.profile == null) { if (data.profile == null) {
data.error(TAG, ERROR_PROFILE_MISSING) data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
return@run return@run
} }
@ -45,7 +46,7 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
loginWithCredentials() loginWithCredentials()
} }
else { else {
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
} }
} }
}} }}
@ -70,7 +71,9 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID") var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
sessionId = sessionId?.replace("-MAINT", "") sessionId = sessionId?.replace("-MAINT", "")
if (sessionId == null) { if (sessionId == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID, response, text) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
.withResponse(response)
.withApiResponse(text))
return return
} }
data.messagesSessionId = sessionId data.messagesSessionId = sessionId
@ -84,7 +87,9 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.api.AppError
import pl.szczodrzynski.edziennik.api.AppError.* import pl.szczodrzynski.edziennik.api.AppError.*
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.c import pl.szczodrzynski.edziennik.utils.Utils.c
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
import java.util.ArrayList import java.util.ArrayList
@ -24,11 +25,11 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
init { run { init { run {
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) { if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
data.error(TAG, ERROR_INVALID_LOGIN_MODE) data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
return@run return@run
} }
if (data.portalEmail == null || data.portalPassword == null) { if (data.portalEmail == null || data.portalPassword == null) {
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
return@run return@run
} }
@ -47,7 +48,6 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
}} }}
private fun authorize(url: String?) { private fun authorize(url: String?) {
data.callback.onActionStarted(R.string.sync_action_authorizing)
Request.builder() Request.builder()
.url(url) .url(url)
.userAgent(LIBRUS_USER_AGENT) .userAgent(LIBRUS_USER_AGENT)
@ -67,13 +67,17 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
if (csrfMatcher.find()) { if (csrfMatcher.find()) {
login(csrfMatcher.group(1)) login(csrfMatcher.group(1))
} else { } else {
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING, response, json) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING)
.withResponse(response)
.withApiResponse(json))
} }
} }
} }
override fun onFailure(response: Response, throwable: Throwable) { override fun onFailure(response: Response, throwable: Throwable) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
}) })
.build() .build()
@ -81,7 +85,6 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
} }
private fun login(csrfToken: String) { private fun login(csrfToken: String) {
data.callback.onActionStarted(R.string.sync_action_logging_in)
Request.builder() Request.builder()
.url(LIBRUS_LOGIN_URL) .url(LIBRUS_LOGIN_URL)
.userAgent(LIBRUS_USER_AGENT) .userAgent(LIBRUS_USER_AGENT)
@ -94,14 +97,18 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
override fun onSuccess(json: JsonObject?, response: Response) { override fun onSuccess(json: JsonObject?, response: Response) {
if (json == null) { if (json == null) {
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) { if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED, response) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
.withResponse(response))
return return
} }
data.error(TAG, ERROR_RESPONSE_EMPTY, response) data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return return
} }
if (json.get("errors") != null) { if (json.get("errors") != null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR, response, apiResponse = json) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR)
.withResponse(response)
.withApiResponse(json))
return return
} }
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL)) authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
@ -109,10 +116,14 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
override fun onFailure(response: Response, throwable: Throwable) { override fun onFailure(response: Response, throwable: Throwable) {
if (response.code() == 403 || response.code() == 401) { if (response.code() == 403 || response.code() == 401) {
data.error(TAG, ERROR_LOGIN_DATA_INVALID, response, throwable) data.error(ApiError(TAG, ERROR_LOGIN_DATA_INVALID)
.withResponse(response)
.withThrowable(throwable))
return return
} }
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
}) })
.build() .build()
@ -150,7 +161,9 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
else -> ERROR_LOGIN_LIBRUS_PORTAL_OTHER else -> ERROR_LOGIN_LIBRUS_PORTAL_OTHER
} }
}.let { errorCode -> }.let { errorCode ->
data.error(TAG, errorCode, apiResponse = json, response = response) data.error(ApiError(TAG, errorCode)
.withApiResponse(json)
.withResponse(response))
return return
} }
} }
@ -158,12 +171,17 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
try { try {
onSuccess(json, response) onSuccess(json, response)
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN, response, e, json) data.error(ApiError(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
} }
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }

View File

@ -13,6 +13,7 @@ import okhttp3.Cookie
import okhttp3.HttpUrl import okhttp3.HttpUrl
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.currentTimeUnix import pl.szczodrzynski.edziennik.currentTimeUnix
import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.getUnixDate
@ -27,7 +28,7 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
init { run { init { run {
if (data.profile == null) { if (data.profile == null) {
data.error(TAG, ERROR_PROFILE_MISSING) data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
return@run return@run
} }
@ -50,7 +51,7 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
loginWithCredentials() loginWithCredentials()
} }
else { else {
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
} }
} }
}} }}
@ -73,7 +74,8 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
val callback = object : JsonCallbackHandler() { val callback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) { override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null && response?.parserErrorBody == null) { if (json == null && response?.parserErrorBody == null) {
data.error(TAG, ERROR_RESPONSE_EMPTY, response) data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return return
} }
val error = if (response?.code() == 200) null else val error = if (response?.code() == 200) null else
@ -97,26 +99,34 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
"Nieprawidłowy węzeł." -> ERROR_LIBRUS_API_INCORRECT_ENDPOINT "Nieprawidłowy węzeł." -> ERROR_LIBRUS_API_INCORRECT_ENDPOINT
else -> ERROR_LIBRUS_API_OTHER else -> ERROR_LIBRUS_API_OTHER
}.let { errorCode -> }.let { errorCode ->
data.error(TAG, errorCode, apiResponse = json, response = response) data.error(ApiError(TAG, errorCode)
.withApiResponse(json)
.withResponse(response))
return return
} }
} }
if (json == null) { if (json == null) {
data.error(TAG, ERROR_RESPONSE_EMPTY, response) data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return return
} }
try { try {
onSuccess(json) onSuccess(json)
} catch (e: Exception) { } catch (e: Exception) {
data.error(TAG, EXCEPTION_LIBRUS_API_REQUEST, response, e, json) data.error(ApiError(TAG, EXCEPTION_LIBRUS_API_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
} }
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
// TODO add hotfix for Classrooms 500 // TODO add hotfix for Classrooms 500
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }
@ -135,7 +145,7 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
private fun loginWithToken(token: String?) { private fun loginWithToken(token: String?) {
if (token == null) { if (token == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN))
return return
} }
@ -145,7 +155,9 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
if (location?.endsWith("centrum_powiadomien") == true) { if (location?.endsWith("centrum_powiadomien") == true) {
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID") val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
if (sessionId == null) { if (sessionId == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID, response, json) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID)
.withResponse(response)
.withApiResponse(json))
return return
} }
data.synergiaSessionId = sessionId data.synergiaSessionId = sessionId
@ -153,12 +165,16 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
onSuccess() onSuccess()
} }
else { else {
data.error(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID, response, json) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID)
.withResponse(response)
.withApiResponse(json))
} }
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }

View File

@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.api.AppError
import pl.szczodrzynski.edziennik.api.AppError.* import pl.szczodrzynski.edziennik.api.AppError.*
import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
@ -20,11 +21,11 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
init { run { init { run {
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) { if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
data.error(TAG, ERROR_INVALID_LOGIN_MODE) data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
return@run return@run
} }
if (data.profile == null) { if (data.profile == null) {
data.error(TAG, ERROR_PROFILE_MISSING) data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
return@run return@run
} }
@ -33,7 +34,7 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
} }
else { else {
if (!synergiaAccount()) { if (!synergiaAccount()) {
data.error(TAG, ERROR_LOGIN_DATA_MISSING) data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
} }
} }
}} }}
@ -51,7 +52,9 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
val accountId = json.getInt("id") val accountId = json.getInt("id")
val accountToken = json.getString("accessToken") val accountToken = json.getString("accessToken")
if (accountId == null || accountToken == null) { if (accountId == null || accountToken == null) {
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING, response, apiResponse = json) data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING)
.withResponse(response)
.withApiResponse(json))
} }
else { else {
data.apiAccessToken = accountToken data.apiAccessToken = accountToken
@ -69,7 +72,8 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
val callback = object : JsonCallbackHandler() { val callback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) { override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null) { if (json == null) {
data.error(TAG, ERROR_RESPONSE_EMPTY, response) data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return return
} }
val error = if (response?.code() == 200) null else val error = if (response?.code() == 200) null else
@ -85,7 +89,9 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND "Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
else -> ERROR_LIBRUS_PORTAL_OTHER else -> ERROR_LIBRUS_PORTAL_OTHER
}.let { errorCode -> }.let { errorCode ->
data.error(TAG, errorCode, apiResponse = json, response = response) data.error(ApiError(TAG, errorCode)
.withApiResponse(json)
.withResponse(response))
return return
} }
} }
@ -94,16 +100,23 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
onSuccess(json, response) onSuccess(json, response)
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
e.printStackTrace() e.printStackTrace()
data.error(TAG, EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN, response, e, json) data.error(ApiError(TAG, EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
} }
} else { } else {
data.error(TAG, ERROR_REQUEST_FAILURE, response, apiResponse = json) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withApiResponse(json))
} }
} }
override fun onFailure(response: Response?, throwable: Throwable?) { override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable) data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
} }
} }

View File

@ -8,7 +8,8 @@ import com.google.gson.JsonObject
import im.wangchao.mhttp.Request import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response import im.wangchao.mhttp.Response
class ApiError(val profileId: Int, val tag: String, val errorCode: Int) { class ApiError(val tag: String, val errorCode: Int) {
var profileId: Int? = null
private var throwable: Throwable? = null private var throwable: Throwable? = null
private var apiResponse: String? = null private var apiResponse: String? = null
private var request: Request? = null private var request: Request? = null

View File

@ -169,7 +169,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
else -> errorCode else -> errorCode
} }
} }
callback.onError(ApiError(profile?.id ?: -1, tag, code).withResponse(response).withThrowable(throwable).withApiResponse(apiResponse)) callback.onError(ApiError(tag, code).apply { profileId = profile?.id ?: -1 }.withResponse(response).withThrowable(throwable).withApiResponse(apiResponse))
} }
fun error(tag: String, errorCode: Int, response: Response? = null, apiResponse: String? = null) { fun error(tag: String, errorCode: Int, response: Response? = null, apiResponse: String? = null) {
var code = when (null) { var code = when (null) {
@ -180,6 +180,15 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
else -> errorCode else -> errorCode
} }
} }
callback.onError(ApiError(profile?.id ?: -1, tag, code).withResponse(response).withApiResponse(apiResponse)) callback.onError(ApiError(tag, code).apply { profileId = profile?.id ?: -1 }.withResponse(response).withApiResponse(apiResponse))
}
fun error(apiError: ApiError) {
callback.onError(apiError)
}
fun progress(step: Int) {
callback.onProgress(step)
}
fun startProgress(stringRes: Int) {
callback.onStartProgress(stringRes)
} }
} }

View File

@ -16,9 +16,12 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
* @param endpointIds a [List] of [Endpoint]s that satisfy this feature ID * @param endpointIds a [List] of [Endpoint]s that satisfy this feature ID
* @param requiredLoginMethod a required login method, which will have to be executed before this endpoint. * @param requiredLoginMethod a required login method, which will have to be executed before this endpoint.
*/ */
class Endpoint( data class Endpoint(
val loginType: Int, val loginType: Int,
val featureId: Int, val featureId: Int,
val endpointIds: List<Int>, val endpointIds: List<Int>,
val requiredLoginMethod: Int val requiredLoginMethods: List<Int>
) ) {
val priority
get() = endpointIds.size
}

View File

@ -908,4 +908,8 @@
<string name="settings_about_discord_text">Serwer Discord</string> <string name="settings_about_discord_text">Serwer Discord</string>
<string name="settings_about_discord_subtext">Dołącz do naszego serwera Discord!</string> <string name="settings_about_discord_subtext">Dołącz do naszego serwera Discord!</string>
<string name="menu_debug">Debugowanie</string> <string name="menu_debug">Debugowanie</string>
<string name="edziennik_progress_login_librus_portal">Logowanie do Portalu Librus</string>
<string name="edziennik_progress_login_librus_api">Logowanie do API</string>
<string name="edziennik_progress_login_librus_synergia">Logowanie do Librus Synergia</string>
<string name="edziennik_progress_login_librus_messages">Logowanie do wiadomości Librus</string>
</resources> </resources>

View File

@ -1,4 +1,4 @@
include ':app', ':agendacalendarview', ':MaterialDrawer', ':mhttp', ':material-about-library', ':cafebar', ':szkolny-font', ':nachos' include ':app', ':agendacalendarview', ':mhttp', ':material-about-library', ':cafebar', ':szkolny-font', ':nachos'
/* /*
include ':Navigation' include ':Navigation'
project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/ project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/