mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2024-11-24 10:54:36 -06:00
[APIv2/Librus] Create Login methods, update API structure
This commit is contained in:
parent
1bdee7857c
commit
76d39ac623
@ -47,11 +47,10 @@ public class AppError {
|
||||
public static final int CODE_LIBRUS_DISCONNECTED = 31;
|
||||
public static final int CODE_PROFILE_ARCHIVED = 30;
|
||||
|
||||
|
||||
public static final int CODE_INTERNAL_MISSING_DATA = 100;
|
||||
// internal errors - not for user's information.
|
||||
// these error codes are processed in API main classes
|
||||
public static final int CODE_INTERNAL_LIBRUS_ACCOUNT_410 = 120;
|
||||
public static final int CODE_INTERNAL_LIBRUS_ACCOUNT_410_ = 120;
|
||||
|
||||
public String TAG;
|
||||
public int line;
|
||||
|
@ -51,7 +51,6 @@ import pl.szczodrzynski.edziennik.api.interfaces.LoginCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.MessageGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Announcement;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Attendance;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Event;
|
||||
@ -213,8 +212,6 @@ public class Librus implements EdziennikInterface {
|
||||
this.fullSync = profile == null || profile.getEmpty() || profile.shouldFullSync(activityContext);
|
||||
this.today = Date.getToday();
|
||||
|
||||
DataStore ds = new DataStore(app.db, profileId);
|
||||
|
||||
this.librusEmail = loginStore.getLoginData("email", "");
|
||||
this.librusPassword = loginStore.getLoginData("password", "");
|
||||
if (profile == null) {
|
||||
|
21
app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Api.kt
Normal file
21
app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Api.kt
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
|
||||
open class Api(open val data: Data) {
|
||||
fun finishWithError(error: AppError) {
|
||||
try {
|
||||
data.saveData()
|
||||
} catch (e: Exception) {
|
||||
Crashlytics.logException(e)
|
||||
}
|
||||
|
||||
data.callback.onError(null, error)
|
||||
}
|
||||
}
|
@ -16,33 +16,8 @@ const val FEATURE_MESSAGES_INBOX = 7
|
||||
const val FEATURE_MESSAGES_OUTBOX = 8
|
||||
const val FEATURE_ANNOUNCEMENTS = 9
|
||||
|
||||
const val LOGIN_TYPE_MOBIDZIENNIK = 1
|
||||
const val LOGIN_TYPE_LIBRUS = 2
|
||||
const val LOGIN_TYPE_IUCZNIOWIE = 3
|
||||
const val LOGIN_TYPE_VULCAN = 4
|
||||
const val LOGIN_TYPE_DEMO = 20
|
||||
|
||||
// LOGIN MODES
|
||||
const val LOGIN_MODE_LIBRUS_EMAIL = 0
|
||||
const val LOGIN_MODE_LIBRUS_SYNERGIA = 1
|
||||
const val LOGIN_MODE_LIBRUS_JST = 2
|
||||
const val LOGIN_MODE_MOBIDZIENNIK_WEB = 0
|
||||
const val LOGIN_MODE_IDZIENNIK_WEB = 0
|
||||
const val LOGIN_MODE_VULCAN_WEB = 0
|
||||
|
||||
// LOGIN METHODS
|
||||
const val LOGIN_METHOD_NOT_NEEDED = -1
|
||||
const val LOGIN_METHOD_LIBRUS_PORTAL = 0
|
||||
const val LOGIN_METHOD_LIBRUS_API = 1
|
||||
const val LOGIN_METHOD_LIBRUS_SYNERGIA = 2
|
||||
const val LOGIN_METHOD_LIBRUS_MESSAGES = 3
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_API = 0
|
||||
const val LOGIN_METHOD_IDZIENNIK_WEB = 0
|
||||
const val LOGIN_METHOD_IDZIENNIK_API = 1
|
||||
const val LOGIN_METHOD_VULCAN_WEB = 0
|
||||
const val LOGIN_METHOD_VULCAN_API = 1
|
||||
|
||||
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 LIBRUS_CLIENT_ID = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv"
|
||||
const val LIBRUS_REDIRECT_URL = "http://localhost/bar"
|
||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
||||
@ -51,3 +26,19 @@ const val LIBRUS_TOKEN_URL = "https://portal.librus.pl/oauth2/access_token"
|
||||
|
||||
const val LIBRUS_ACCOUNT_URL = "https://portal.librus.pl/api/v2/SynergiaAccounts/fresh/" // + login
|
||||
const val LIBRUS_ACCOUNTS_URL = "https://portal.librus.pl/api/v2/SynergiaAccounts"
|
||||
|
||||
const val LIBRUS_API_URL = "https://api.librus.pl/2.0/"
|
||||
const val LIBRUS_API_TOKEN_URL = "https://api.librus.pl/OAuth/Token"
|
||||
const val LIBRUS_API_TOKEN_JST_URL = "https://api.librus.pl/OAuth/TokenJST"
|
||||
const val LIBRUS_API_AUTHORIZATION = "Mjg6ODRmZGQzYTg3YjAzZDNlYTZmZmU3NzdiNThiMzMyYjE="
|
||||
const val LIBRUS_API_SECRET_JST = "18b7c1ee08216f636a1b1a2440e68398"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "49"
|
||||
//const val LIBRUS_API_CLIENT_ID_JST_REFRESH = "42"
|
||||
|
||||
const val LIBRUS_JST_DEMO_CODE = "68656A21"
|
||||
const val LIBRUS_JST_DEMO_PIN = "1290"
|
||||
|
||||
const val LIBRUS_SYNERGIA_TOKEN_LOGIN_URL = "https://synergia.librus.pl/loguj/token/\$token/przenies/"
|
||||
|
||||
const val LIBRUS_MESSAGES_URL = "https://wiadomosci.librus.pl/module/"
|
||||
const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.util.Log
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApiGrades
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApiMe
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergiaGrades
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Endpoint
|
||||
|
||||
@ -13,7 +14,8 @@ const val ENDPOINT_LIBRUS_API_ME = 0
|
||||
const val ENDPOINT_LIBRUS_API_GRADES = 0
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 0
|
||||
|
||||
val librusEndpoints = listOf(
|
||||
val endpoints = listOf(
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, ENDPOINT_LIBRUS_API_ME, null, LibrusApiMe::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_API},
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, 1, listOf(), LibrusSynergiaGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_SYNERGIA },
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, 1, listOf(), LibrusApiGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_API }
|
||||
)
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
/*const val CODE_OTHER = 0
|
||||
const val CODE_OK = 1
|
||||
const val CODE_NO_INTERNET = 10
|
||||
const val CODE_SSL_ERROR = 13
|
||||
const val CODE_ARCHIVED = 5
|
||||
const val CODE_MAINTENANCE = 6
|
||||
const val CODE_LOGIN_ERROR = 7
|
||||
const val CODE_ACCOUNT_MISMATCH = 8
|
||||
const val CODE_APP_SERVER_ERROR = 9
|
||||
const val CODE_MULTIACCOUNT_SETUP = 12
|
||||
const val CODE_TIMEOUT = 11
|
||||
const val CODE_PROFILE_NOT_FOUND = 14
|
||||
const val CODE_ATTACHMENT_NOT_AVAILABLE = 28
|
||||
const val CODE_INVALID_LOGIN = 2
|
||||
const val CODE_INVALID_SERVER_ADDRESS = 21
|
||||
const val CODE_INVALID_SCHOOL_NAME = 22
|
||||
const val CODE_INVALID_DEVICE = 23
|
||||
const val CODE_OLD_PASSWORD = 4
|
||||
const val CODE_INVALID_TOKEN = 24
|
||||
const val CODE_EXPIRED_TOKEN = 27
|
||||
const val CODE_INVALID_SYMBOL = 25
|
||||
const val CODE_INVALID_PIN = 26
|
||||
const val CODE_LIBRUS_NOT_ACTIVATED = 29
|
||||
const val CODE_SYNERGIA_NOT_ACTIVATED = 32
|
||||
const val CODE_LIBRUS_DISCONNECTED = 31
|
||||
const val CODE_PROFILE_ARCHIVED = 30*/
|
||||
const val CODE_INVALID_LOGIN_MODE = 130
|
||||
const val CODE_INTERNAL_MISSING_DATA = 100
|
||||
const val CODE_INTERNAL_LIBRUS_ACCOUNT_410 = 120
|
||||
const val CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED = 121
|
||||
const val CODE_LOGIN_METHOD_NOT_SATISFIED = 122
|
||||
const val CODE_LIBRUS_PROFILE_NULL = 123
|
||||
const val ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED = 124
|
||||
|
||||
const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
|
@ -4,3 +4,47 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusMessages
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
|
||||
const val LOGIN_TYPE_MOBIDZIENNIK = 1
|
||||
const val LOGIN_TYPE_LIBRUS = 2
|
||||
const val LOGIN_TYPE_IUCZNIOWIE = 3
|
||||
const val LOGIN_TYPE_VULCAN = 4
|
||||
const val LOGIN_TYPE_DEMO = 20
|
||||
|
||||
// LOGIN MODES
|
||||
const val LOGIN_MODE_LIBRUS_EMAIL = 0
|
||||
const val LOGIN_MODE_LIBRUS_SYNERGIA = 1
|
||||
const val LOGIN_MODE_LIBRUS_JST = 2
|
||||
const val LOGIN_MODE_MOBIDZIENNIK_WEB = 0
|
||||
const val LOGIN_MODE_IDZIENNIK_WEB = 0
|
||||
const val LOGIN_MODE_VULCAN_WEB = 0
|
||||
|
||||
// LOGIN METHODS
|
||||
const val LOGIN_METHOD_NOT_NEEDED = -1
|
||||
const val LOGIN_METHOD_LIBRUS_PORTAL = 100// 0
|
||||
const val LOGIN_METHOD_LIBRUS_API = 200// 1
|
||||
const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300 // 2
|
||||
const val LOGIN_METHOD_LIBRUS_MESSAGES = 400
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_API = 100
|
||||
const val LOGIN_METHOD_IDZIENNIK_WEB = 100
|
||||
const val LOGIN_METHOD_IDZIENNIK_API = 200
|
||||
const val LOGIN_METHOD_VULCAN_WEB = 100
|
||||
const val LOGIN_METHOD_VULCAN_API = 200
|
||||
|
||||
val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, null, LoginLibrusPortal::class.java) { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, null, LoginLibrusApi::class.java) { _, loginStore ->
|
||||
if (loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) LOGIN_METHOD_LIBRUS_PORTAL else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, listOf(FEATURE_GRADES, FEATURE_HOMEWORKS, FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX), LoginLibrusSynergia::class.java) { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX), LoginLibrusMessages::class.java) { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
@ -1,111 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_EMAIL
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_JST
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginJst
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.SynergiaTokenExtractor
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataStore
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesComposeInfo
|
||||
import pl.szczodrzynski.edziennik.models.Endpoint
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.lang.Exception
|
||||
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore) : EdziennikInterface {
|
||||
private val TAG = "librus.Librus"
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: SyncCallback) {
|
||||
|
||||
lateinit var syncCallback: SyncCallback
|
||||
lateinit var featureList: ArrayList<Int>
|
||||
lateinit var dataStore: DataStore
|
||||
var onLogin: (() -> Unit)? = null
|
||||
val internalErrorList = ArrayList<Int>()
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
lateinit var data: DataLibrus
|
||||
|
||||
init {
|
||||
data = DataLibrus(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Librus.callback)
|
||||
}
|
||||
|
||||
fun isError(error: AppError?): Boolean {
|
||||
if (error == null)
|
||||
return false
|
||||
syncCallback.onError(null, error)
|
||||
return true
|
||||
}
|
||||
|
||||
/* _ _ _
|
||||
| | (_) |
|
||||
| | _| |__ _ __ _ _ ___
|
||||
| | | | '_ \| '__| | | / __|
|
||||
| |____| | |_) | | | |_| \__ \
|
||||
|______|_|_.__/|_| \__,_|__*/
|
||||
private fun loginLibrus() {
|
||||
LoginLibrus(app, loginStore, syncCallback) {
|
||||
if (profile == null) {
|
||||
firstLoginLibrus()
|
||||
return@LoginLibrus
|
||||
}
|
||||
synergiaTokenExtractor()
|
||||
}
|
||||
}
|
||||
private fun firstLoginLibrus() {
|
||||
FirstLoginLibrus(app, loginStore, syncCallback) { profileList ->
|
||||
syncCallback.onLoginFirst(profileList, loginStore)
|
||||
}
|
||||
}
|
||||
private fun synergiaTokenExtractor() {
|
||||
if (profile == null) {
|
||||
throw Exception("Profile may not be null")
|
||||
}
|
||||
SynergiaTokenExtractor(app, profile, loginStore, syncCallback) {
|
||||
d(TAG, "Profile $profile")
|
||||
d(TAG, "LoginStore $loginStore")
|
||||
onLogin?.invoke()
|
||||
}
|
||||
}
|
||||
/* _____ _
|
||||
/ ____| (_)
|
||||
| (___ _ _ _ __ ___ _ __ __ _ _ __ _
|
||||
\___ \| | | | '_ \ / _ \ '__/ _` | |/ _` |
|
||||
____) | |_| | | | | __/ | | (_| | | (_| |
|
||||
|_____/ \__, |_| |_|\___|_| \__, |_|\__,_|
|
||||
__/ | __/ |
|
||||
|___/ |__*/
|
||||
private fun loginSynergia() {
|
||||
LoginSynergia(app, loginStore, syncCallback) {
|
||||
if (profile == null) {
|
||||
firstLoginSynergia()
|
||||
return@LoginSynergia
|
||||
}
|
||||
onLogin?.invoke()
|
||||
}
|
||||
}
|
||||
private fun firstLoginSynergia() {
|
||||
FirstLoginSynergia(app, loginStore, syncCallback) { profileList ->
|
||||
syncCallback.onLoginFirst(profileList, loginStore)
|
||||
}
|
||||
}
|
||||
/* _ _____ _______
|
||||
| |/ ____|__ __|
|
||||
| | (___ | |
|
||||
_ | |\___ \ | |
|
||||
| |__| |____) | | |
|
||||
\____/|_____/ |*/
|
||||
private fun loginJst() {
|
||||
LoginJst(app, null, loginStore, syncCallback) {
|
||||
if (profile == null) {
|
||||
firstLoginSynergia()
|
||||
return@LoginJst
|
||||
}
|
||||
onLogin?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: SyncCallback): SyncCallback {
|
||||
@ -135,67 +55,11 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore) :
|
||||
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||
internalErrorList.add(error.errorCode)
|
||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
||||
loginLibrus()
|
||||
//loginLibrus()
|
||||
}
|
||||
else -> callback.onError(activityContext, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun login(callback: SyncCallback) {
|
||||
this.internalErrorList.clear()
|
||||
this.syncCallback = wrapCallback(callback)
|
||||
when (loginStore.mode) {
|
||||
LOGIN_MODE_LIBRUS_EMAIL -> {
|
||||
loginLibrus()
|
||||
}
|
||||
LOGIN_MODE_LIBRUS_SYNERGIA -> {
|
||||
|
||||
}
|
||||
LOGIN_MODE_LIBRUS_JST -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getData() {
|
||||
|
||||
}
|
||||
|
||||
override fun sync(activityContext: Context, callback: SyncCallback, profileId: Int, profile: Profile?, loginStore: LoginStore) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun syncMessages(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun syncFeature(activityContext: Context, callback: SyncCallback, profile: ProfileFull, vararg featureList: Int) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getMessage(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, message: MessageFull, messageCallback: MessageGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getAttachment(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, message: MessageFull, attachmentId: Long, attachmentCallback: AttachmentGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRecipientList(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, recipientListGetCallback: RecipientListGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getComposeInfo(profile: ProfileFull): MessagesComposeInfo {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getConfigurableEndpoints(profile: Profile?): MutableMap<String, Endpoint> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEndpointEnabled(profile: Profile?, defaultActive: Boolean, name: String?): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
@ -0,0 +1,172 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.SynergiaTokenExtractor
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesComposeInfo
|
||||
import pl.szczodrzynski.edziennik.models.Endpoint
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.lang.Exception
|
||||
|
||||
class LibrusOld(val app: App, val profile: Profile?, val loginStore: LoginStore) : EdziennikInterface {
|
||||
private val TAG = "librus.Librus"
|
||||
|
||||
lateinit var syncCallback: SyncCallback
|
||||
lateinit var featureList: ArrayList<Int>
|
||||
lateinit var data: Data
|
||||
var onLogin: (() -> Unit)? = null
|
||||
val internalErrorList = ArrayList<Int>()
|
||||
|
||||
fun isError(error: AppError?): Boolean {
|
||||
if (error == null)
|
||||
return false
|
||||
syncCallback.onError(null, error)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
/* _ _ _
|
||||
| | (_) |
|
||||
| | _| |__ _ __ _ _ ___
|
||||
| | | | '_ \| '__| | | / __|
|
||||
| |____| | |_) | | | |_| \__ \
|
||||
|______|_|_.__/|_| \__,_|__*/
|
||||
|
||||
private fun firstLoginLibrus() {
|
||||
FirstLoginLibrus(app, loginStore, syncCallback) { profileList ->
|
||||
syncCallback.onLoginFirst(profileList, loginStore)
|
||||
}
|
||||
}
|
||||
private fun synergiaTokenExtractor() {
|
||||
if (profile == null) {
|
||||
throw Exception("Profile may not be null")
|
||||
}
|
||||
|
||||
}
|
||||
/* _____ _
|
||||
/ ____| (_)
|
||||
| (___ _ _ _ __ ___ _ __ __ _ _ __ _
|
||||
\___ \| | | | '_ \ / _ \ '__/ _` | |/ _` |
|
||||
____) | |_| | | | | __/ | | (_| | | (_| |
|
||||
|_____/ \__, |_| |_|\___|_| \__, |_|\__,_|
|
||||
__/ | __/ |
|
||||
|___/ |__*/
|
||||
private fun loginSynergia() {
|
||||
|
||||
}
|
||||
private fun firstLoginSynergia() {
|
||||
FirstLoginSynergia(app, loginStore, syncCallback) { profileList ->
|
||||
syncCallback.onLoginFirst(profileList, loginStore)
|
||||
}
|
||||
}
|
||||
/* _ _____ _______
|
||||
| |/ ____|__ __|
|
||||
| | (___ | |
|
||||
_ | |\___ \ | |
|
||||
| |__| |____) | | |
|
||||
\____/|_____/ |*/
|
||||
private fun loginJst() {
|
||||
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: SyncCallback): SyncCallback {
|
||||
return object : SyncCallback {
|
||||
override fun onSuccess(activityContext: Context?, profileFull: ProfileFull?) {
|
||||
callback.onSuccess(activityContext, profileFull)
|
||||
}
|
||||
|
||||
override fun onProgress(progressStep: Int) {
|
||||
callback.onProgress(progressStep)
|
||||
}
|
||||
|
||||
override fun onActionStarted(stringResId: Int) {
|
||||
callback.onActionStarted(stringResId)
|
||||
}
|
||||
|
||||
override fun onLoginFirst(profileList: MutableList<Profile>?, loginStore: LoginStore?) {
|
||||
callback.onLoginFirst(profileList, loginStore)
|
||||
}
|
||||
|
||||
override fun onError(activityContext: Context?, error: AppError) {
|
||||
when (error.errorCode) {
|
||||
in internalErrorList -> {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(activityContext, error)
|
||||
}
|
||||
/* CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||
internalErrorList.add(error.errorCode)
|
||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
||||
//loginLibrus()
|
||||
}*/
|
||||
else -> callback.onError(activityContext, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun login(callback: SyncCallback) {
|
||||
this.internalErrorList.clear()
|
||||
this.syncCallback = wrapCallback(callback)
|
||||
when (loginStore.mode) {
|
||||
LOGIN_MODE_LIBRUS_EMAIL -> {
|
||||
//loginLibrus()
|
||||
}
|
||||
LOGIN_MODE_LIBRUS_SYNERGIA -> {
|
||||
|
||||
}
|
||||
LOGIN_MODE_LIBRUS_JST -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getData() {
|
||||
|
||||
}
|
||||
|
||||
override fun sync(activityContext: Context, callback: SyncCallback, profileId: Int, profile: Profile?, loginStore: LoginStore) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun syncMessages(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun syncFeature(activityContext: Context, callback: SyncCallback, profile: ProfileFull, vararg featureList: Int) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getMessage(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, message: MessageFull, messageCallback: MessageGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getAttachment(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, message: MessageFull, attachmentId: Long, attachmentCallback: AttachmentGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRecipientList(activityContext: Context, errorCallback: SyncCallback, profile: ProfileFull, recipientListGetCallback: RecipientListGetCallback) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getComposeInfo(profile: ProfileFull): MessagesComposeInfo {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getConfigurableEndpoints(profile: Profile?): MutableMap<String, Endpoint> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun isEndpointEnabled(profile: Profile?, defaultActive: Boolean, name: String?): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
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.LoginLibrusPortal
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class LibrusTest(val app: App) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusTest"
|
||||
}
|
||||
|
||||
val profile = Profile(1, "Profil", "xd", 1).apply {
|
||||
//putStudentData("accountLogin", "1234567")
|
||||
//putStudentData("accountPassword", "zaq1@WSX")
|
||||
|
||||
putStudentData("accountCode", LIBRUS_JST_DEMO_CODE)
|
||||
putStudentData("accountPin", LIBRUS_JST_DEMO_PIN)
|
||||
}
|
||||
val loginStore = LoginStore(1, LOGIN_TYPE_LIBRUS, JsonObject().apply {
|
||||
addProperty("email", "test@example.com")
|
||||
addProperty("password", "zaq1@WSX")
|
||||
}).also {
|
||||
it.mode = LOGIN_MODE_LIBRUS_JST
|
||||
}
|
||||
|
||||
fun go() {
|
||||
val data = DataLibrus(app, profile, loginStore).apply {
|
||||
callback = object : ProgressCallback {
|
||||
override fun onProgress(progressStep: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActionStarted(stringResId: Int) {
|
||||
d(TAG, app.getString(stringResId))
|
||||
}
|
||||
|
||||
override fun onError(activityContext: Context?, error: AppError) {
|
||||
error.changeIfCodeOther()
|
||||
d(TAG, "Error "+error.getDetails(app))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoginLibrus(data, LOGIN_METHOD_LIBRUS_API) {
|
||||
d(TAG, "Login succeeded.")
|
||||
d(TAG, "Profile data: ${data.profile?.studentData?.toString()}")
|
||||
d(TAG, "LoginStore data: ${data.loginStore.data}")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
class DataLibrus(val app: App, val profile: Profile, val loginStore: LoginStore, val callback: ProgressCallback, val onSuccess: () -> Unit) {
|
||||
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
}
|
||||
/* _____ _ _
|
||||
| __ \ | | | |
|
||||
| |__) |__ _ __| |_ __ _| |
|
||||
| ___/ _ \| '__| __/ _` | |
|
||||
| | | (_) | | | || (_| | |
|
||||
|_| \___/|_| \__\__,_|*/
|
||||
private var mPortalEmail: String? = null
|
||||
var portalEmail: String?
|
||||
get() { mPortalEmail = mPortalEmail ?: loginStore.getLoginData("email", null); return mPortalEmail }
|
||||
set(value) { loginStore.putLoginData("email", value); mPortalEmail = value }
|
||||
private var mPortalPassword: String? = null
|
||||
var portalPassword: String?
|
||||
get() { mPortalPassword = mPortalPassword ?: loginStore.getLoginData("password", null); return mPortalPassword }
|
||||
set(value) { loginStore.putLoginData("password", value); mPortalPassword = value }
|
||||
|
||||
private var mPortalAccessToken: String? = null
|
||||
var portalAccessToken: String?
|
||||
get() { mPortalAccessToken = mPortalAccessToken ?: loginStore.getLoginData("accessToken", null); return mPortalAccessToken }
|
||||
set(value) { loginStore.putLoginData("accessToken", value); mPortalAccessToken = value }
|
||||
private var mPortalRefreshToken: String? = null
|
||||
var portalRefreshToken: String?
|
||||
get() { mPortalRefreshToken = mPortalRefreshToken ?: loginStore.getLoginData("refreshToken", null); return mPortalRefreshToken }
|
||||
set(value) { loginStore.putLoginData("refreshToken", value); mPortalRefreshToken = value }
|
||||
private var mPortalTokenExpiryTime: Long? = null
|
||||
var portalTokenExpiryTime: Long
|
||||
get() { mPortalTokenExpiryTime = mPortalTokenExpiryTime ?: loginStore.getLoginData("tokenExpiryTime", 0L); return mPortalTokenExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("tokenExpiryTime", value); mPortalTokenExpiryTime = value }
|
||||
|
||||
/* _____ _____
|
||||
/\ | __ \_ _|
|
||||
/ \ | |__) || |
|
||||
/ /\ \ | ___/ | |
|
||||
/ ____ \| | _| |_
|
||||
/_/ \_\_| |____*/
|
||||
/**
|
||||
* A Synergia login, like 1234567u.
|
||||
* Used: for login (API Login Method) in Synergia mode.
|
||||
* And also in various places in [pl.szczodrzynski.edziennik.api.v2.models.Endpoint]s
|
||||
*/
|
||||
private var mApiLogin: String? = null
|
||||
var apiLogin: String?
|
||||
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
|
||||
set(value) { profile?.putStudentData("accountLogin", value) ?: return; mApiLogin = value }
|
||||
/**
|
||||
* A Synergia password.
|
||||
* Used: for login (API Login Method) in Synergia mode.
|
||||
*/
|
||||
private var mApiPassword: String? = null
|
||||
var apiPassword: String?
|
||||
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
|
||||
set(value) { profile?.putStudentData("accountPassword", value) ?: return; mApiPassword = value }
|
||||
|
||||
/**
|
||||
* A JST login Code.
|
||||
* Used only during first login in JST mode.
|
||||
*/
|
||||
private var mApiCode: String? = null
|
||||
var apiCode: String?
|
||||
get() { mApiCode = mApiCode ?: profile?.getStudentData("accountCode", null); return mApiCode }
|
||||
set(value) { profile?.putStudentData("accountCode", value) ?: return; mApiCode = value }
|
||||
/**
|
||||
* A JST login PIN.
|
||||
* Used only during first login in JST mode.
|
||||
*/
|
||||
private var mApiPin: String? = null
|
||||
var apiPin: String?
|
||||
get() { mApiPin = mApiPin ?: profile?.getStudentData("accountPin", null); return mApiPin }
|
||||
set(value) { profile?.putStudentData("accountPin", value) ?: return; mApiPin = value }
|
||||
|
||||
/**
|
||||
* A Synergia API access token.
|
||||
* Used in all Api Endpoints.
|
||||
* Created in Login Method Api.
|
||||
* Applicable for all login modes.
|
||||
*/
|
||||
private var mApiAccessToken: String? = null
|
||||
var apiAccessToken: String?
|
||||
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
|
||||
set(value) { profile?.putStudentData("accountToken", value) ?: return; mApiAccessToken = value }
|
||||
/**
|
||||
* A Synergia API refresh token.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
*/
|
||||
private var mApiRefreshToken: String? = null
|
||||
var apiRefreshToken: String?
|
||||
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
|
||||
set(value) { profile?.putStudentData("accountRefreshToken", value) ?: return; mApiRefreshToken = value }
|
||||
/**
|
||||
* The expiry time for [apiAccessToken], as a UNIX timestamp.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
* Used when refreshing the [apiAccessToken] in Portal mode ([pl.szczodrzynski.edziennik.api.v2.librus.login.SynergiaTokenExtractor])
|
||||
*/
|
||||
private var mApiTokenExpiryTime: Long? = null
|
||||
var apiTokenExpiryTime: Long
|
||||
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
|
||||
set(value) { profile?.putStudentData("accountTokenTime", value) ?: return; mApiTokenExpiryTime = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
| | | | |_| |__ ___ _ __
|
||||
| | | | __| '_ \ / _ \ '__|
|
||||
| |__| | |_| | | | __/ |
|
||||
\____/ \__|_| |_|\___|*/
|
||||
var isPremium
|
||||
get() = profile?.getStudentData("isPremium", false) ?: false
|
||||
set(value) { profile?.putStudentData("isPremium", value) }
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.CODE_MAINTENANCE
|
||||
import pl.szczodrzynski.edziennik.api.AppError.CODE_OTHER
|
||||
import pl.szczodrzynski.edziennik.api.v2.Api
|
||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED
|
||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_API_URL
|
||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_USER_AGENT
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
open class LibrusApi(override val data: DataLibrus) : Api(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApi"
|
||||
}
|
||||
fun apiRequest(endpoint: String, callback: (json: JsonObject?) -> Unit) {
|
||||
d(TAG, "Requesting $LIBRUS_API_URL$endpoint")
|
||||
Request.builder()
|
||||
.url(if (data.fakeLogin) "http://szkolny.eu/librus/api/$endpoint" else LIBRUS_API_URL + endpoint)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addHeader("Authorization", "Bearer ${data.apiAccessToken}")
|
||||
.get()
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.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()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -2,19 +2,16 @@ package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataStore
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
class LibrusApiGrades(val app: App,
|
||||
val profile: Profile,
|
||||
val loginStore: LoginStore,
|
||||
val dataStore: DataStore,
|
||||
val data: Data,
|
||||
val callback: ProgressCallback,
|
||||
val onSuccess: () -> Unit) : EndpointInterface {
|
||||
override fun sync() {
|
||||
|
||||
}
|
||||
val onSuccess: () -> Unit) {
|
||||
|
||||
|
||||
init {
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
class LibrusApiMe(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
init {
|
||||
apiRequest("Me") { json ->
|
||||
val me = json?.getJsonObject("Me")
|
||||
val account = me?.getJsonObject("Account")
|
||||
val user = me?.getJsonObject("User")
|
||||
|
||||
data.isPremium = account?.getBoolean("isPremium") == true || account?.getBoolean("isPremiumDemo") == true
|
||||
|
||||
val isParent = account?.getInt("GroupId") == 5
|
||||
data.profile?.accountNameLong =
|
||||
if (isParent)
|
||||
buildFullName(account?.getString("FirstName"), account?.getString("LastName"))
|
||||
else null
|
||||
|
||||
data.profile?.studentNameLong =
|
||||
buildFullName(user?.getString("FirstName"), user?.getString("LastName"))
|
||||
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -2,16 +2,16 @@ package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataStore
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
class LibrusSynergiaGrades(val app: App,
|
||||
val profile: Profile,
|
||||
val loginStore: LoginStore,
|
||||
val dataStore: DataStore,
|
||||
val callback: ProgressCallback,
|
||||
val onSuccess: () -> Unit) {
|
||||
val profile: Profile,
|
||||
val loginStore: LoginStore,
|
||||
val data: Data,
|
||||
val callback: ProgressCallback,
|
||||
val onSuccess: () -> Unit) {
|
||||
|
||||
init {
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.ILoginMethod
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
class LoginJst(
|
||||
app: App,
|
||||
profile: Profile?,
|
||||
loginStore: LoginStore,
|
||||
callback: ProgressCallback,
|
||||
onSuccess: () -> Unit
|
||||
): ILoginMethod(app, profile, loginStore, callback, onSuccess) {
|
||||
companion object {
|
||||
private const val TAG = "librus.LoginJst"
|
||||
}
|
||||
|
||||
}
|
@ -1,183 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import android.util.Pair
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.c
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
import java.util.ArrayList
|
||||
import java.util.regex.Pattern
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.log
|
||||
|
||||
class LoginLibrus(val app: App, val loginStore: LoginStore, val callback: ProgressCallback, val onSuccess: () -> Unit) {
|
||||
class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "librus.LoginLibrus"
|
||||
private const val TAG = "LoginLibrus"
|
||||
}
|
||||
|
||||
private var loginMethodList = mutableListOf<Int>()
|
||||
|
||||
init {
|
||||
// ustawiamy tokeny, generujemy itp
|
||||
// nic nie robimy z dostępem do api.librus.pl
|
||||
// to będzie później
|
||||
val accessToken = loginStore.getLoginData("accessToken", null)
|
||||
val refreshToken = loginStore.getLoginData("refreshToken", null)
|
||||
val tokenExpiryTime = loginStore.getLoginData("tokenExpiryTime", 0L)
|
||||
for (loginMethodId in loginMethodIds) {
|
||||
var requiredLoginMethod = loginMethodId
|
||||
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||
librusLoginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod ->
|
||||
loginMethodList.add(requiredLoginMethod)
|
||||
requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore)
|
||||
}
|
||||
}
|
||||
}
|
||||
loginMethodList = loginMethodList.toHashSet().toMutableList()
|
||||
loginMethodList.sort()
|
||||
|
||||
// succeed having a non-expired access token and a refresh token
|
||||
if (tokenExpiryTime-30 > System.currentTimeMillis() / 1000 && refreshToken != null && accessToken != null) {
|
||||
nextLoginMethod()
|
||||
}
|
||||
|
||||
private fun nextLoginMethod() {
|
||||
if (loginMethodList.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
else if (refreshToken != null) {
|
||||
app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
accessToken(null, refreshToken)
|
||||
}
|
||||
else {
|
||||
app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
useLoginMethod(loginMethodList.removeAt(0)) {
|
||||
nextLoginMethod()
|
||||
}
|
||||
}
|
||||
|
||||
private fun authorize(url: String?) {
|
||||
callback.onActionStarted(R.string.sync_action_authorizing)
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.withClient(app.httpLazy)
|
||||
.callback(object : TextCallbackHandler() {
|
||||
override fun onSuccess(data: String, response: Response) {
|
||||
//d("headers "+response.headers().toString());
|
||||
val location = response.headers().get("Location")
|
||||
if (location != null) {
|
||||
val authMatcher = Pattern.compile("http://localhost/bar\\?code=([A-z0-9]+?)$", Pattern.DOTALL or Pattern.MULTILINE).matcher(location)
|
||||
if (authMatcher.find()) {
|
||||
accessToken(authMatcher.group(1), null)
|
||||
} else {
|
||||
//callback.onError(activityContext, Edziennik.CODE_OTHER, "Auth code not found: "+location);
|
||||
authorize(location)
|
||||
}
|
||||
} else {
|
||||
val csrfMatcher = Pattern.compile("name=\"csrf-token\" content=\"([A-z0-9=+/\\-_]+?)\"", Pattern.DOTALL).matcher(data)
|
||||
if (csrfMatcher.find()) {
|
||||
login(csrfMatcher.group(1))
|
||||
} else {
|
||||
callback.onError(null, AppError(TAG, 463, CODE_OTHER, "CSRF token not found.", response, data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
callback.onError(null, AppError(TAG, 207, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun login(csrfToken: String) {
|
||||
callback.onActionStarted(R.string.sync_action_logging_in)
|
||||
val email = loginStore.getLoginData("email", "")
|
||||
val password = loginStore.getLoginData("password", "")
|
||||
Request.builder()
|
||||
.url(LIBRUS_LOGIN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("email", email)
|
||||
.addParameter("password", password)
|
||||
.addHeader("X-CSRF-TOKEN", csrfToken)
|
||||
.contentType(MediaTypeUtils.APPLICATION_JSON)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(data: JsonObject?, response: Response) {
|
||||
if (data == null) {
|
||||
if (response.parserErrorBody != null && response.parserErrorBody.contains("wciąż nieaktywne")) {
|
||||
callback.onError(null, AppError(TAG, 487, CODE_LIBRUS_NOT_ACTIVATED, response))
|
||||
}
|
||||
callback.onError(null, AppError(TAG, 489, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
if (data.get("errors") != null) {
|
||||
callback.onError(null, AppError(TAG, 490, CODE_OTHER, data.get("errors").asJsonArray.get(0).asString, response, data))
|
||||
return
|
||||
}
|
||||
authorize(data.getString("redirect") ?: LIBRUS_AUTHORIZE_URL)
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
if (response.code() == 403 || response.code() == 401) {
|
||||
callback.onError(null, AppError(TAG, 248, CODE_INVALID_LOGIN, response, throwable))
|
||||
return
|
||||
}
|
||||
callback.onError(null, AppError(TAG, 251, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private var refreshTokenFailed = false
|
||||
private fun accessToken(code: String?, refreshToken: String?) {
|
||||
callback.onActionStarted(R.string.sync_action_getting_token)
|
||||
val params = ArrayList<Pair<String, Any>>()
|
||||
params.add(Pair("client_id", LIBRUS_CLIENT_ID))
|
||||
if (code != null) {
|
||||
params.add(Pair("grant_type", "authorization_code"))
|
||||
params.add(Pair("code", code))
|
||||
params.add(Pair("redirect_uri", LIBRUS_REDIRECT_URL))
|
||||
} else if (refreshToken != null) {
|
||||
params.add(Pair("grant_type", "refresh_token"))
|
||||
params.add(Pair("refresh_token", refreshToken))
|
||||
private fun useLoginMethod(loginMethodId: Int, onSuccess: () -> Unit) {
|
||||
if (data.loginMethods.contains(loginMethodId)) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
d(TAG, "Using login method $loginMethodId")
|
||||
when (loginMethodId) {
|
||||
LOGIN_METHOD_LIBRUS_PORTAL -> {
|
||||
LoginLibrusPortal(data) {
|
||||
data.loginMethods.add(loginMethodId)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_API -> {
|
||||
LoginLibrusApi(data) {
|
||||
data.loginMethods.add(loginMethodId)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_SYNERGIA -> {
|
||||
LoginLibrusApi(data) {
|
||||
data.loginMethods.add(loginMethodId)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_MESSAGES -> {
|
||||
LoginLibrusApi(data) {
|
||||
data.loginMethods.add(loginMethodId)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
Request.builder()
|
||||
.url(LIBRUS_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParams(params)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(data: JsonObject?, response: Response) {
|
||||
if (data == null) {
|
||||
callback.onError(null, AppError(TAG, 539, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
if (data.get("error") != null) {
|
||||
val hint = data.getString("hint")
|
||||
if (!refreshTokenFailed && refreshToken != null && (hint == "Token has been revoked" || hint == "Token has expired")) {
|
||||
c(TAG, "refreshing the token failed. Trying to log in again.")
|
||||
refreshTokenFailed = true
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
return
|
||||
}
|
||||
val errorText = data.getString("error") + " " + (data.getString("message") ?: "") + " " + (hint ?: "")
|
||||
callback.onError(null, AppError(TAG, 552, CODE_OTHER, errorText, response, data))
|
||||
return
|
||||
}
|
||||
try {
|
||||
loginStore.putLoginData("tokenType", data.getString("token_type"))
|
||||
loginStore.putLoginData("accessToken", data.getString("access_token"))
|
||||
loginStore.putLoginData("refreshToken", data.getString("refresh_token"))
|
||||
loginStore.putLoginData("tokenExpiryTime", System.currentTimeMillis() / 1000 + (data.getInt("expires_in") ?: 86400))
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
callback.onError(null, AppError(TAG, 311, CODE_OTHER, response, e, data))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
callback.onError(null, AppError(TAG, 317, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
class LoginLibrusApi {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusApi"
|
||||
}
|
||||
|
||||
private lateinit var data: DataLibrus
|
||||
private lateinit var onSuccess: () -> Unit
|
||||
|
||||
constructor(data: DataLibrus, onSuccess: () -> Unit) {
|
||||
this.data = data
|
||||
this.onSuccess = onSuccess
|
||||
|
||||
if (data.profile == null) {
|
||||
data.callback.onError(null, AppError(TAG, 19, CODE_LIBRUS_PROFILE_NULL))
|
||||
return
|
||||
}
|
||||
|
||||
if (data.apiTokenExpiryTime-30 > currentTimeUnix() && data.apiAccessToken.isNotNullNorEmpty()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
when (data.loginStore.mode) {
|
||||
LOGIN_MODE_LIBRUS_EMAIL -> loginWithPortal()
|
||||
LOGIN_MODE_LIBRUS_SYNERGIA -> loginWithSynergia()
|
||||
LOGIN_MODE_LIBRUS_JST -> loginWithJst()
|
||||
else -> {
|
||||
data.callback.onError(null, AppError(TAG, 25, CODE_INVALID_LOGIN_MODE))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithPortal() {
|
||||
if (!data.loginMethods.contains(LOGIN_METHOD_LIBRUS_PORTAL)) {
|
||||
data.callback.onError(null, AppError(TAG, 26, CODE_LOGIN_METHOD_NOT_SATISFIED))
|
||||
return
|
||||
}
|
||||
SynergiaTokenExtractor(data) {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFromLoginStore() {
|
||||
data.loginStore.data?.apply {
|
||||
if (has("accountLogin")) {
|
||||
data.apiLogin = getString("accountLogin")
|
||||
remove("accountLogin")
|
||||
}
|
||||
if (has("accountPassword")) {
|
||||
data.apiPassword = getString("accountPassword")
|
||||
remove("accountPassword")
|
||||
}
|
||||
if (has("accountCode")) {
|
||||
data.apiCode = getString("accountCode")
|
||||
remove("accountCode")
|
||||
}
|
||||
if (has("accountPin")) {
|
||||
data.apiPin = getString("accountPin")
|
||||
remove("accountPin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithSynergia() {
|
||||
copyFromLoginStore()
|
||||
if (data.apiRefreshToken != null) {
|
||||
// refresh a Synergia token
|
||||
synergiaRefreshToken()
|
||||
}
|
||||
else if (data.apiLogin != null && data.apiPassword != null) {
|
||||
synergiaGetToken()
|
||||
}
|
||||
else {
|
||||
// cannot log in: token expired, no login data present
|
||||
data.callback.onError(null, AppError(TAG, 91, CODE_INVALID_LOGIN))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithJst() {
|
||||
copyFromLoginStore()
|
||||
|
||||
if (data.apiRefreshToken != null) {
|
||||
// refresh a JST token
|
||||
jstRefreshToken()
|
||||
}
|
||||
else if (data.apiCode != null && data.apiPin != null) {
|
||||
// get a JST token from Code and PIN
|
||||
jstGetToken()
|
||||
}
|
||||
else {
|
||||
// cannot log in: token expired, no login data present
|
||||
data.callback.onError(null, AppError(TAG, 110, CODE_INVALID_LOGIN))
|
||||
}
|
||||
}
|
||||
|
||||
private val tokenCallback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.callback.onError(null, AppError(TAG, 117, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
json.getString("error")?.let { error ->
|
||||
when (error) {
|
||||
"librus_captcha_needed" -> {
|
||||
|
||||
}
|
||||
"connection_problems" -> {
|
||||
|
||||
}
|
||||
"invalid_client" -> {
|
||||
|
||||
}
|
||||
"librus_reg_accept_needed" -> {
|
||||
|
||||
}
|
||||
"librus_change_password_error" -> {
|
||||
|
||||
}
|
||||
"librus_password_change_required" -> {
|
||||
|
||||
}
|
||||
"invalid_grant" -> {
|
||||
|
||||
}
|
||||
else -> {
|
||||
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
data.apiAccessToken = json.getString("access_token")
|
||||
data.apiRefreshToken = json.getString("refresh_token")
|
||||
data.apiTokenExpiryTime = currentTimeUnix() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
data.callback.onError(null, AppError(TAG, 154, EXCEPTION_LOGIN_LIBRUS_API_TOKEN, response, e, json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.callback.onError(null, AppError(TAG, 159, CODE_OTHER, response, throwable))
|
||||
}
|
||||
}
|
||||
|
||||
private fun synergiaGetToken() {
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "password")
|
||||
.addParameter("username", data.apiLogin)
|
||||
.addParameter("password", data.apiPassword)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addHeader("Authorization", "Basic $LIBRUS_API_AUTHORIZATION")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun synergiaRefreshToken() {
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "refresh_token")
|
||||
.addParameter("refresh_token", data.apiRefreshToken)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addHeader("Authorization", "Basic $LIBRUS_API_AUTHORIZATION")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun jstGetToken() {
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_JST_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "implicit_grant")
|
||||
.addParameter("client_id", LIBRUS_API_CLIENT_ID_JST)
|
||||
.addParameter("secret", LIBRUS_API_SECRET_JST)
|
||||
.addParameter("code", data.apiCode)
|
||||
.addParameter("pin", data.apiPin)
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addParameter("librus_mobile_rules_accepted", "1")
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun jstRefreshToken() {
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_JST_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "refresh_token")
|
||||
.addParameter("client_id", LIBRUS_API_CLIENT_ID_JST)
|
||||
.addParameter("refresh_token", data.apiRefreshToken)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("mobile_app_accept_rules", "1")
|
||||
.addParameter("synergy_accept_rules", "1")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
class LoginLibrusMessages {
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import android.util.Pair
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.c
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
import java.util.ArrayList
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusPortal"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
|
||||
data.callback.onError(null, AppError(TAG, 27, CODE_INVALID_LOGIN_MODE))
|
||||
return@run
|
||||
}
|
||||
if (data.portalEmail == null || data.portalPassword == null) {
|
||||
data.callback.onError(null, AppError(TAG, 31, CODE_INVALID_LOGIN))
|
||||
return@run
|
||||
}
|
||||
|
||||
// succeed having a non-expired access token and a refresh token
|
||||
if (data.portalTokenExpiryTime-30 > currentTimeUnix() && data.portalRefreshToken.isNotNullNorEmpty() && data.portalAccessToken.isNotNullNorEmpty()) {
|
||||
onSuccess()
|
||||
}
|
||||
else if (data.portalRefreshToken != null) {
|
||||
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
accessToken(null, data.portalRefreshToken)
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
}
|
||||
}}
|
||||
|
||||
private fun authorize(url: String?) {
|
||||
data.callback.onActionStarted(R.string.sync_action_authorizing)
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.withClient(data.app.httpLazy)
|
||||
.callback(object : TextCallbackHandler() {
|
||||
override fun onSuccess(json: String, response: Response) {
|
||||
val location = response.headers().get("Location")
|
||||
if (location != null) {
|
||||
val authMatcher = Pattern.compile("http://localhost/bar\\?code=([A-z0-9]+?)$", Pattern.DOTALL or Pattern.MULTILINE).matcher(location)
|
||||
if (authMatcher.find()) {
|
||||
accessToken(authMatcher.group(1), null)
|
||||
} else {
|
||||
authorize(location)
|
||||
}
|
||||
} else {
|
||||
val csrfMatcher = Pattern.compile("name=\"csrf-token\" content=\"([A-z0-9=+/\\-_]+?)\"", Pattern.DOTALL).matcher(json)
|
||||
if (csrfMatcher.find()) {
|
||||
login(csrfMatcher.group(1))
|
||||
} else {
|
||||
data.callback.onError(null, AppError(TAG, 463, CODE_OTHER, "CSRF token not found.", response, json))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
data.callback.onError(null, AppError(TAG, 207, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun login(csrfToken: String) {
|
||||
data.callback.onActionStarted(R.string.sync_action_logging_in)
|
||||
Request.builder()
|
||||
.url(LIBRUS_LOGIN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("email", data.portalEmail)
|
||||
.addParameter("password", data.portalPassword)
|
||||
.addHeader("X-CSRF-TOKEN", csrfToken)
|
||||
.contentType(MediaTypeUtils.APPLICATION_JSON)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
||||
data.callback.onError(null, AppError(TAG, 487, CODE_LIBRUS_NOT_ACTIVATED, response))
|
||||
return
|
||||
}
|
||||
data.callback.onError(null, AppError(TAG, 489, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
if (json.get("errors") != null) {
|
||||
data.callback.onError(null, AppError(TAG, 490, CODE_OTHER, json.getJsonArray("errors")?.get(0)?.asString, response, json))
|
||||
return
|
||||
}
|
||||
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
if (response.code() == 403 || response.code() == 401) {
|
||||
data.callback.onError(null, AppError(TAG, 248, CODE_INVALID_LOGIN, response, throwable))
|
||||
return
|
||||
}
|
||||
data.callback.onError(null, AppError(TAG, 251, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private var refreshTokenFailed = false
|
||||
private fun accessToken(code: String?, refreshToken: String?) {
|
||||
data.callback.onActionStarted(R.string.sync_action_getting_token)
|
||||
val params = ArrayList<Pair<String, Any>>()
|
||||
params.add(Pair("client_id", LIBRUS_CLIENT_ID))
|
||||
if (code != null) {
|
||||
params.add(Pair("grant_type", "authorization_code"))
|
||||
params.add(Pair("code", code))
|
||||
params.add(Pair("redirect_uri", LIBRUS_REDIRECT_URL))
|
||||
} else if (refreshToken != null) {
|
||||
params.add(Pair("grant_type", "refresh_token"))
|
||||
params.add(Pair("refresh_token", refreshToken))
|
||||
}
|
||||
Request.builder()
|
||||
.url(LIBRUS_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParams(params)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
data.callback.onError(null, AppError(TAG, 539, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
json.getString("error")?.let { error ->
|
||||
val hint = json.getString("hint", "")
|
||||
val message = json.getString("message", "")
|
||||
if (!refreshTokenFailed && refreshToken != null && (hint == "Token has been revoked" || hint == "Token has expired")) {
|
||||
c(TAG, "refreshing the token failed. Trying to log in again.")
|
||||
refreshTokenFailed = true
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
return
|
||||
}
|
||||
val errorText = "$error $message $hint"
|
||||
data.callback.onError(null, AppError(TAG, 552, CODE_OTHER, errorText, response, json))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
data.portalAccessToken = json.getString("access_token")
|
||||
data.portalRefreshToken = json.getString("refresh_token")
|
||||
data.portalTokenExpiryTime = currentTimeUnix() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
data.callback.onError(null, AppError(TAG, 311, CODE_OTHER, response, e, json))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
data.callback.onError(null, AppError(TAG, 317, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
class LoginLibrusSynergia {
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
|
||||
class LoginSynergia(val app: App, val loginStore: LoginStore, val callback: ProgressCallback, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "librus.LoginSynergia"
|
||||
}
|
||||
|
||||
}
|
@ -8,41 +8,43 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_USER_AGENT
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_ACCOUNT_URL
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
class SynergiaTokenExtractor(val app: App, val profile: Profile, val loginStore: LoginStore, val callback: ProgressCallback, val onSuccess: () -> Unit) {
|
||||
class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "librus.SynergiaToken"
|
||||
}
|
||||
|
||||
init {
|
||||
val accountToken = profile.getStudentData("accountToken", null)
|
||||
val accountTokenTime = profile.getStudentData("accountTokenTime", 0L)
|
||||
if (accountToken.isNotNullNorEmpty() && currentTimeUnix() - accountTokenTime < 3 * 60 * 60) {
|
||||
init { run {
|
||||
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
|
||||
data.callback.onError(null, AppError(TAG, 23, CODE_INVALID_LOGIN_MODE))
|
||||
return@run
|
||||
}
|
||||
if (data.profile == null) {
|
||||
data.callback.onError(null, AppError(TAG, 28, CODE_LIBRUS_PROFILE_NULL))
|
||||
return@run
|
||||
}
|
||||
|
||||
if (data.apiTokenExpiryTime-30 > currentTimeUnix() && data.apiAccessToken.isNotNullNorEmpty()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
if (!synergiaAccount())
|
||||
callback.onError(null, AppError(TAG, 33, CODE_INTERNAL_MISSING_DATA))
|
||||
synergiaAccount()
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
private fun synergiaAccount(): Boolean {
|
||||
val accountLogin = profile.getStudentData("accountLogin", null) ?: return false
|
||||
val tokenType = loginStore.getLoginData("tokenType", null) ?: return false
|
||||
val accessToken = loginStore.getLoginData("accessToken", null) ?: return false
|
||||
callback.onActionStarted(R.string.sync_action_getting_account)
|
||||
val accountLogin = data.apiLogin ?: return false
|
||||
val accessToken = data.portalAccessToken ?: return false
|
||||
data.callback.onActionStarted(R.string.sync_action_getting_account)
|
||||
d(TAG, "Requesting " + (LIBRUS_ACCOUNT_URL + accountLogin))
|
||||
Request.builder()
|
||||
.url(LIBRUS_ACCOUNT_URL + accountLogin)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addHeader("Authorization", "$tokenType $accessToken")
|
||||
.addHeader("Authorization", "Bearer $accessToken")
|
||||
.get()
|
||||
.allowErrorCode(HTTP_NOT_FOUND)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
@ -50,57 +52,56 @@ class SynergiaTokenExtractor(val app: App, val profile: Profile, val loginStore:
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_GONE)
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(data: JsonObject?, response: Response) {
|
||||
if (data == null) {
|
||||
callback.onError(null, AppError(TAG, 641, CODE_MAINTENANCE, response))
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
data.callback.onError(null, AppError(TAG, 641, CODE_MAINTENANCE, response))
|
||||
return
|
||||
}
|
||||
if (response.code() == 410) {
|
||||
val reason = data.get("reason")
|
||||
val reason = json.get("reason")
|
||||
if (reason != null && reason !is JsonNull && reason.asString == "requires_an_action") {
|
||||
callback.onError(null, AppError(TAG, 1078, CODE_LIBRUS_DISCONNECTED, response, data))
|
||||
data.callback.onError(null, AppError(TAG, 1078, CODE_LIBRUS_DISCONNECTED, response, json))
|
||||
return
|
||||
}
|
||||
callback.onError(null, AppError(TAG, 70, CODE_INTERNAL_LIBRUS_ACCOUNT_410))
|
||||
data.callback.onError(null, AppError(TAG, 70, CODE_INTERNAL_LIBRUS_ACCOUNT_410))
|
||||
return
|
||||
}
|
||||
if (data.get("message") != null) {
|
||||
val message = data.get("message").asString
|
||||
if (json.get("message") != null) {
|
||||
val message = json.get("message").asString
|
||||
if (message == "Account not found") {
|
||||
callback.onError(null, AppError(TAG, 651, CODE_OTHER, app.getString(R.string.sync_error_register_student_not_associated_format, profile.studentNameLong, accountLogin), response, data))
|
||||
data.callback.onError(null, AppError(TAG, 651, CODE_OTHER, data.app.getString(R.string.sync_error_register_student_not_associated_format, data.profile?.studentNameLong ?: "", accountLogin), response, json))
|
||||
return
|
||||
}
|
||||
callback.onError(null, AppError(TAG, 654, CODE_OTHER, message + "\n\n" + accountLogin, response, data))
|
||||
data.callback.onError(null, AppError(TAG, 654, CODE_OTHER, message + "\n\n" + accountLogin, response, json))
|
||||
return
|
||||
}
|
||||
if (response.code() == HTTP_OK) {
|
||||
try {
|
||||
// synergiaAccount is executed when a synergia token needs a refresh
|
||||
val accountId = data.getInt("id")
|
||||
val accountToken = data.getString("accessToken")
|
||||
val accountId = json.getInt("id")
|
||||
val accountToken = json.getString("accessToken")
|
||||
if (accountId == null || accountToken == null) {
|
||||
callback.onError(null, AppError(TAG, 1284, CODE_OTHER, data))
|
||||
data.callback.onError(null, AppError(TAG, 1284, CODE_OTHER, json))
|
||||
return
|
||||
}
|
||||
profile.putStudentData("accountId", accountId)
|
||||
profile.putStudentData("accountToken", accountToken)
|
||||
profile.putStudentData("accountTokenTime", System.currentTimeMillis() / 1000)
|
||||
profile.studentNameLong = data.getString("studentName")
|
||||
val nameParts = data.getString("studentName")?.split(" ")?.toTypedArray()
|
||||
profile.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
data.apiAccessToken = accountToken
|
||||
data.apiTokenExpiryTime = currentTimeUnix() + 6*60*60
|
||||
data.profile?.studentNameLong = json.getString("studentName")
|
||||
val nameParts = json.getString("studentName")?.split(" ")?.toTypedArray()
|
||||
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
e.printStackTrace()
|
||||
callback.onError(null, AppError(TAG, 662, CODE_OTHER, response, e, data))
|
||||
data.callback.onError(null, AppError(TAG, 662, CODE_OTHER, response, e, json))
|
||||
}
|
||||
|
||||
} else {
|
||||
callback.onError(null, AppError(TAG, 425, CODE_OTHER, response, data))
|
||||
data.callback.onError(null, AppError(TAG, 425, CODE_OTHER, response, json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
callback.onError(null, AppError(TAG, 432, CODE_OTHER, response, throwable))
|
||||
data.callback.onError(null, AppError(TAG, 432, CODE_OTHER, response, throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
|
@ -3,15 +3,21 @@ package pl.szczodrzynski.edziennik.api.v2.models
|
||||
import android.util.LongSparseArray
|
||||
import androidx.core.util.forEach
|
||||
import androidx.core.util.isNotEmpty
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.datamodels.*
|
||||
import pl.szczodrzynski.edziennik.models.Date
|
||||
|
||||
data class DataStore(private val appDb: AppDb, val profileId: Int) {
|
||||
open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) {
|
||||
|
||||
var fakeLogin = false
|
||||
|
||||
lateinit var callback: ProgressCallback
|
||||
|
||||
val loginMethods = mutableListOf<Int>()
|
||||
|
||||
val teacherList: LongSparseArray<Teacher> = LongSparseArray()
|
||||
val subjectList: LongSparseArray<Subject> = LongSparseArray()
|
||||
val teacherList = LongSparseArray<Teacher>()
|
||||
val subjectList = LongSparseArray<Subject>()
|
||||
val teamList = mutableListOf<Team>()
|
||||
val lessonList = mutableListOf<Lesson>()
|
||||
val lessonChangeList = mutableListOf<LessonChange>()
|
||||
@ -28,15 +34,19 @@ data class DataStore(private val appDb: AppDb, val profileId: Int) {
|
||||
val metadataList = mutableListOf<Metadata>()
|
||||
val messageMetadataList = mutableListOf<Metadata>()
|
||||
|
||||
private val db by lazy { app.db }
|
||||
|
||||
init {
|
||||
|
||||
clear()
|
||||
|
||||
appDb.teacherDao().getAllNow(profileId).forEach { teacher ->
|
||||
teacherList.put(teacher.id, teacher)
|
||||
}
|
||||
appDb.subjectDao().getAllNow(profileId).forEach { subject ->
|
||||
subjectList.put(subject.id, subject)
|
||||
|
||||
if (profile != null) {
|
||||
db.teacherDao().getAllNow(profile.id).forEach { teacher ->
|
||||
teacherList.put(teacher.id, teacher)
|
||||
}
|
||||
db.subjectDao().getAllNow(profile.id).forEach { subject ->
|
||||
subjectList.put(subject.id, subject)
|
||||
}
|
||||
}
|
||||
|
||||
/*val teacher = teachers.byNameFirstLast("Jan Kowalski") ?: Teacher(1, 1, "", "").let {
|
||||
@ -67,57 +77,60 @@ data class DataStore(private val appDb: AppDb, val profileId: Int) {
|
||||
}
|
||||
|
||||
fun saveData() {
|
||||
if (profile == null)
|
||||
return
|
||||
|
||||
if (teacherList.isNotEmpty()) {
|
||||
val tempList: ArrayList<Teacher> = ArrayList()
|
||||
teacherList.forEach { _, teacher ->
|
||||
tempList.add(teacher)
|
||||
}
|
||||
appDb.teacherDao().addAll(tempList)
|
||||
db.teacherDao().addAll(tempList)
|
||||
}
|
||||
if (subjectList.isNotEmpty()) {
|
||||
val tempList: ArrayList<Subject> = ArrayList()
|
||||
subjectList.forEach { _, subject ->
|
||||
tempList.add(subject)
|
||||
}
|
||||
appDb.subjectDao().addAll(tempList)
|
||||
db.subjectDao().addAll(tempList)
|
||||
}
|
||||
if (teamList.isNotEmpty())
|
||||
appDb.teamDao().addAll(teamList)
|
||||
db.teamDao().addAll(teamList)
|
||||
if (lessonList.isNotEmpty()) {
|
||||
appDb.lessonDao().clear(profileId)
|
||||
appDb.lessonDao().addAll(lessonList)
|
||||
db.lessonDao().clear(profile.id)
|
||||
db.lessonDao().addAll(lessonList)
|
||||
}
|
||||
if (lessonChangeList.isNotEmpty())
|
||||
appDb.lessonChangeDao().addAll(lessonChangeList)
|
||||
db.lessonChangeDao().addAll(lessonChangeList)
|
||||
if (gradeCategoryList.isNotEmpty())
|
||||
appDb.gradeCategoryDao().addAll(gradeCategoryList)
|
||||
db.gradeCategoryDao().addAll(gradeCategoryList)
|
||||
if (gradeList.isNotEmpty()) {
|
||||
appDb.gradeDao().clear(profileId)
|
||||
appDb.gradeDao().addAll(gradeList)
|
||||
db.gradeDao().clear(profile.id)
|
||||
db.gradeDao().addAll(gradeList)
|
||||
}
|
||||
if (eventList.isNotEmpty()) {
|
||||
appDb.eventDao().removeFuture(profileId, Date.getToday())
|
||||
appDb.eventDao().addAll(eventList)
|
||||
db.eventDao().removeFuture(profile.id, Date.getToday())
|
||||
db.eventDao().addAll(eventList)
|
||||
}
|
||||
if (eventTypeList.isNotEmpty())
|
||||
appDb.eventTypeDao().addAll(eventTypeList)
|
||||
db.eventTypeDao().addAll(eventTypeList)
|
||||
if (noticeList.isNotEmpty()) {
|
||||
appDb.noticeDao().clear(profileId)
|
||||
appDb.noticeDao().addAll(noticeList)
|
||||
db.noticeDao().clear(profile.id)
|
||||
db.noticeDao().addAll(noticeList)
|
||||
}
|
||||
if (attendanceList.isNotEmpty())
|
||||
appDb.attendanceDao().addAll(attendanceList)
|
||||
db.attendanceDao().addAll(attendanceList)
|
||||
if (announcementList.isNotEmpty())
|
||||
appDb.announcementDao().addAll(announcementList)
|
||||
db.announcementDao().addAll(announcementList)
|
||||
if (messageList.isNotEmpty())
|
||||
appDb.messageDao().addAllIgnore(messageList)
|
||||
db.messageDao().addAllIgnore(messageList)
|
||||
if (messageRecipientList.isNotEmpty())
|
||||
appDb.messageRecipientDao().addAll(messageRecipientList)
|
||||
db.messageRecipientDao().addAll(messageRecipientList)
|
||||
if (messageRecipientIgnoreList.isNotEmpty())
|
||||
appDb.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
||||
db.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
||||
if (metadataList.isNotEmpty())
|
||||
appDb.metadataDao().addAllIgnore(metadataList)
|
||||
db.metadataDao().addAllIgnore(metadataList)
|
||||
if (messageMetadataList.isNotEmpty())
|
||||
appDb.metadataDao().setSeen(messageMetadataList)
|
||||
db.metadataDao().setSeen(messageMetadataList)
|
||||
}
|
||||
}
|
@ -14,13 +14,14 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
* @param loginType type of the e-register this endpoint handles
|
||||
* @param endpointId a unique ID of this endpoint
|
||||
* @param featureIds a [List] of [Feature]s (their IDs) this endpoint can download
|
||||
* May be null if no strict feature set is associated with this method.
|
||||
* @param endpointClass a [Class] which constructor will be invoked when a data download is needed
|
||||
* @param requiredLoginMethod a lambda returning a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore].
|
||||
*/
|
||||
class Endpoint(
|
||||
val loginType: Int,
|
||||
val endpointId: Int,
|
||||
val featureIds: List<Int>,
|
||||
val featureIds: List<Int>?,
|
||||
val endpointClass: Class<*>,
|
||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
||||
)
|
@ -1,6 +1,5 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.endpoint
|
||||
|
||||
|
||||
data class Feature(val featureId: Int, val loginOptions: Map<Int, List<Int>>) {
|
||||
|
@ -17,13 +17,14 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
* @param loginType type of the e-register this login method handles
|
||||
* @param loginMethodId a unique ID of this login method
|
||||
* @param featureIds a [List] of [Feature]s (their IDs) this login method can provide access to
|
||||
* May be null if no strict feature set is associated with this method.
|
||||
* @param loginMethodClass a [Class] which constructor will be invoked when a log in is needed
|
||||
* @param requiredLoginMethod a lambda returning a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore].
|
||||
*/
|
||||
class LoginMethod(
|
||||
val loginType: Int,
|
||||
val loginMethodId: Int,
|
||||
val featureIds: List<Int>,
|
||||
val featureIds: List<Int>?,
|
||||
val loginMethodClass: Class<*>,
|
||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
||||
)
|
@ -44,7 +44,8 @@ import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.Librus;
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.LibrusOld;
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.LibrusTest;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardLuckyNumberBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardUpdateBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding;
|
||||
@ -115,45 +116,18 @@ public class HomeFragment extends Fragment {
|
||||
return true;
|
||||
});*/
|
||||
|
||||
b.testButton.setOnClickListener((v -> {
|
||||
LoginStore loginStore = new LoginStore(1, LOGIN_TYPE_LIBRUS, new JsonObject());
|
||||
loginStore.putLoginData("email", "example@example.com");
|
||||
loginStore.putLoginData("password", "zaq1@WSX");
|
||||
Profile profile = new Profile(1, "test", "testsubname", 1);
|
||||
profile.putStudentData("accountLogin", "1234567");
|
||||
new Librus(app, profile, loginStore).login(new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, @NonNull AppError error) {
|
||||
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
b.composeButton.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.composeButton.setOnClickListener((v -> {
|
||||
startActivity(new Intent(activity, MessagesComposeActivity.class));
|
||||
}));
|
||||
|
||||
LibrusTest test = new LibrusTest(app);
|
||||
|
||||
b.testButton.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.testButton.setOnClickListener((v -> {
|
||||
test.go();
|
||||
}));
|
||||
|
||||
//((TextView)v.findViewById(R.id.nextSync)).setText(getString(R.string.next_sync_format,Time.fromMillis(app.appJobs.syncJobTime).getStringHMS()));
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user