forked from github/szkolny
[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_LIBRUS_DISCONNECTED = 31;
|
||||||
public static final int CODE_PROFILE_ARCHIVED = 30;
|
public static final int CODE_PROFILE_ARCHIVED = 30;
|
||||||
|
|
||||||
|
|
||||||
public static final int CODE_INTERNAL_MISSING_DATA = 100;
|
public static final int CODE_INTERNAL_MISSING_DATA = 100;
|
||||||
// internal errors - not for user's information.
|
// internal errors - not for user's information.
|
||||||
// these error codes are processed in API main classes
|
// 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 String TAG;
|
||||||
public int line;
|
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.MessageGetCallback;
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
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.Announcement;
|
||||||
import pl.szczodrzynski.edziennik.datamodels.Attendance;
|
import pl.szczodrzynski.edziennik.datamodels.Attendance;
|
||||||
import pl.szczodrzynski.edziennik.datamodels.Event;
|
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.fullSync = profile == null || profile.getEmpty() || profile.shouldFullSync(activityContext);
|
||||||
this.today = Date.getToday();
|
this.today = Date.getToday();
|
||||||
|
|
||||||
DataStore ds = new DataStore(app.db, profileId);
|
|
||||||
|
|
||||||
this.librusEmail = loginStore.getLoginData("email", "");
|
this.librusEmail = loginStore.getLoginData("email", "");
|
||||||
this.librusPassword = loginStore.getLoginData("password", "");
|
this.librusPassword = loginStore.getLoginData("password", "");
|
||||||
if (profile == null) {
|
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_MESSAGES_OUTBOX = 8
|
||||||
const val FEATURE_ANNOUNCEMENTS = 9
|
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 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_CLIENT_ID = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv"
|
||||||
const val LIBRUS_REDIRECT_URL = "http://localhost/bar"
|
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"
|
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_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_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 android.util.Log
|
||||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApiGrades
|
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.librus.data.LibrusSynergiaGrades
|
||||||
import pl.szczodrzynski.edziennik.api.v2.models.Endpoint
|
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_API_GRADES = 0
|
||||||
const val ENDPOINT_LIBRUS_SYNERGIA_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(), LibrusSynergiaGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_SYNERGIA },
|
||||||
Endpoint(LOGIN_TYPE_LIBRUS, 1, listOf(), LibrusApiGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_API }
|
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
|
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
|
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
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.AppError.*
|
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.*
|
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_EMAIL
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_JST
|
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||||
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.datamodels.LoginStore
|
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull
|
|
||||||
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 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 {
|
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: SyncCallback) {
|
||||||
private val TAG = "librus.Librus"
|
|
||||||
|
|
||||||
lateinit var syncCallback: SyncCallback
|
val internalErrorList = mutableListOf<Int>()
|
||||||
lateinit var featureList: ArrayList<Int>
|
lateinit var data: DataLibrus
|
||||||
lateinit var dataStore: DataStore
|
|
||||||
var onLogin: (() -> Unit)? = null
|
|
||||||
val internalErrorList = ArrayList<Int>()
|
|
||||||
|
|
||||||
fun isError(error: AppError?): Boolean {
|
init {
|
||||||
if (error == null)
|
data = DataLibrus(app, profile, loginStore).apply {
|
||||||
return false
|
callback = wrapCallback(this@Librus.callback)
|
||||||
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 {
|
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 -> {
|
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||||
internalErrorList.add(error.errorCode)
|
internalErrorList.add(error.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(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
|
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
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.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
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.App
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
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.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||||
|
|
||||||
class LibrusApiGrades(val app: App,
|
class LibrusApiGrades(val app: App,
|
||||||
val profile: Profile,
|
val profile: Profile,
|
||||||
val loginStore: LoginStore,
|
val loginStore: LoginStore,
|
||||||
val dataStore: DataStore,
|
val data: Data,
|
||||||
val callback: ProgressCallback,
|
val callback: ProgressCallback,
|
||||||
val onSuccess: () -> Unit) : EndpointInterface {
|
val onSuccess: () -> Unit) {
|
||||||
override fun sync() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
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,14 +2,14 @@ package pl.szczodrzynski.edziennik.api.v2.librus.data
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
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.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||||
|
|
||||||
class LibrusSynergiaGrades(val app: App,
|
class LibrusSynergiaGrades(val app: App,
|
||||||
val profile: Profile,
|
val profile: Profile,
|
||||||
val loginStore: LoginStore,
|
val loginStore: LoginStore,
|
||||||
val dataStore: DataStore,
|
val data: Data,
|
||||||
val callback: ProgressCallback,
|
val callback: ProgressCallback,
|
||||||
val onSuccess: () -> Unit) {
|
val onSuccess: () -> Unit) {
|
||||||
|
|
||||||
|
@ -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
|
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.api.v2.*
|
||||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.getInt
|
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||||
import pl.szczodrzynski.edziennik.getString
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.c
|
import kotlin.math.log
|
||||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
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 {
|
companion object {
|
||||||
private const val TAG = "librus.LoginLibrus"
|
private const val TAG = "LoginLibrus"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var loginMethodList = mutableListOf<Int>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// ustawiamy tokeny, generujemy itp
|
for (loginMethodId in loginMethodIds) {
|
||||||
// nic nie robimy z dostępem do api.librus.pl
|
var requiredLoginMethod = loginMethodId
|
||||||
// to będzie później
|
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||||
val accessToken = loginStore.getLoginData("accessToken", null)
|
librusLoginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod ->
|
||||||
val refreshToken = loginStore.getLoginData("refreshToken", null)
|
loginMethodList.add(requiredLoginMethod)
|
||||||
val tokenExpiryTime = loginStore.getLoginData("tokenExpiryTime", 0L)
|
requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loginMethodList = loginMethodList.toHashSet().toMutableList()
|
||||||
|
loginMethodList.sort()
|
||||||
|
|
||||||
// succeed having a non-expired access token and a refresh token
|
nextLoginMethod()
|
||||||
if (tokenExpiryTime-30 > System.currentTimeMillis() / 1000 && refreshToken != null && accessToken != null) {
|
}
|
||||||
|
|
||||||
|
private fun nextLoginMethod() {
|
||||||
|
if (loginMethodList.isEmpty()) {
|
||||||
|
onSuccess()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
useLoginMethod(loginMethodList.removeAt(0)) {
|
||||||
|
nextLoginMethod()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
onSuccess()
|
||||||
}
|
}
|
||||||
else if (refreshToken != null) {
|
|
||||||
app.cookieJar.clearForDomain("portal.librus.pl")
|
|
||||||
accessToken(null, refreshToken)
|
|
||||||
}
|
}
|
||||||
else {
|
LOGIN_METHOD_LIBRUS_API -> {
|
||||||
app.cookieJar.clearForDomain("portal.librus.pl")
|
LoginLibrusApi(data) {
|
||||||
authorize(LIBRUS_AUTHORIZE_URL)
|
data.loginMethods.add(loginMethodId)
|
||||||
}
|
onSuccess()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private fun authorize(url: String?) {
|
LOGIN_METHOD_LIBRUS_SYNERGIA -> {
|
||||||
callback.onActionStarted(R.string.sync_action_authorizing)
|
LoginLibrusApi(data) {
|
||||||
Request.builder()
|
data.loginMethods.add(loginMethodId)
|
||||||
.url(url)
|
onSuccess()
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
}
|
||||||
.withClient(app.httpLazy)
|
}
|
||||||
.callback(object : TextCallbackHandler() {
|
LOGIN_METHOD_LIBRUS_MESSAGES -> {
|
||||||
override fun onSuccess(data: String, response: Response) {
|
LoginLibrusApi(data) {
|
||||||
//d("headers "+response.headers().toString());
|
data.loginMethods.add(loginMethodId)
|
||||||
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))
|
|
||||||
}
|
|
||||||
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()
|
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.*
|
||||||
import pl.szczodrzynski.edziennik.api.AppError
|
import pl.szczodrzynski.edziennik.api.AppError
|
||||||
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.v2.*
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||||
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.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection.*
|
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 {
|
companion object {
|
||||||
private const val TAG = "librus.SynergiaToken"
|
private const val TAG = "librus.SynergiaToken"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init { run {
|
||||||
val accountToken = profile.getStudentData("accountToken", null)
|
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
|
||||||
val accountTokenTime = profile.getStudentData("accountTokenTime", 0L)
|
data.callback.onError(null, AppError(TAG, 23, CODE_INVALID_LOGIN_MODE))
|
||||||
if (accountToken.isNotNullNorEmpty() && currentTimeUnix() - accountTokenTime < 3 * 60 * 60) {
|
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()
|
onSuccess()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!synergiaAccount())
|
synergiaAccount()
|
||||||
callback.onError(null, AppError(TAG, 33, CODE_INTERNAL_MISSING_DATA))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
private fun synergiaAccount(): Boolean {
|
private fun synergiaAccount(): Boolean {
|
||||||
val accountLogin = profile.getStudentData("accountLogin", null) ?: return false
|
val accountLogin = data.apiLogin ?: return false
|
||||||
val tokenType = loginStore.getLoginData("tokenType", null) ?: return false
|
val accessToken = data.portalAccessToken ?: return false
|
||||||
val accessToken = loginStore.getLoginData("accessToken", null) ?: return false
|
data.callback.onActionStarted(R.string.sync_action_getting_account)
|
||||||
callback.onActionStarted(R.string.sync_action_getting_account)
|
|
||||||
d(TAG, "Requesting " + (LIBRUS_ACCOUNT_URL + accountLogin))
|
d(TAG, "Requesting " + (LIBRUS_ACCOUNT_URL + accountLogin))
|
||||||
Request.builder()
|
Request.builder()
|
||||||
.url(LIBRUS_ACCOUNT_URL + accountLogin)
|
.url(LIBRUS_ACCOUNT_URL + accountLogin)
|
||||||
.userAgent(LIBRUS_USER_AGENT)
|
.userAgent(LIBRUS_USER_AGENT)
|
||||||
.addHeader("Authorization", "$tokenType $accessToken")
|
.addHeader("Authorization", "Bearer $accessToken")
|
||||||
.get()
|
.get()
|
||||||
.allowErrorCode(HTTP_NOT_FOUND)
|
.allowErrorCode(HTTP_NOT_FOUND)
|
||||||
.allowErrorCode(HTTP_FORBIDDEN)
|
.allowErrorCode(HTTP_FORBIDDEN)
|
||||||
@ -50,57 +52,56 @@ class SynergiaTokenExtractor(val app: App, val profile: Profile, val loginStore:
|
|||||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
.allowErrorCode(HTTP_GONE)
|
.allowErrorCode(HTTP_GONE)
|
||||||
.callback(object : JsonCallbackHandler() {
|
.callback(object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(data: JsonObject?, response: Response) {
|
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||||
if (data == null) {
|
if (json == null) {
|
||||||
callback.onError(null, AppError(TAG, 641, CODE_MAINTENANCE, response))
|
data.callback.onError(null, AppError(TAG, 641, CODE_MAINTENANCE, response))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (response.code() == 410) {
|
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") {
|
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
|
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
|
return
|
||||||
}
|
}
|
||||||
if (data.get("message") != null) {
|
if (json.get("message") != null) {
|
||||||
val message = data.get("message").asString
|
val message = json.get("message").asString
|
||||||
if (message == "Account not found") {
|
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
|
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
|
return
|
||||||
}
|
}
|
||||||
if (response.code() == HTTP_OK) {
|
if (response.code() == HTTP_OK) {
|
||||||
try {
|
try {
|
||||||
// synergiaAccount is executed when a synergia token needs a refresh
|
// synergiaAccount is executed when a synergia token needs a refresh
|
||||||
val accountId = data.getInt("id")
|
val accountId = json.getInt("id")
|
||||||
val accountToken = data.getString("accessToken")
|
val accountToken = json.getString("accessToken")
|
||||||
if (accountId == null || accountToken == null) {
|
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
|
return
|
||||||
}
|
}
|
||||||
profile.putStudentData("accountId", accountId)
|
data.apiAccessToken = accountToken
|
||||||
profile.putStudentData("accountToken", accountToken)
|
data.apiTokenExpiryTime = currentTimeUnix() + 6*60*60
|
||||||
profile.putStudentData("accountTokenTime", System.currentTimeMillis() / 1000)
|
data.profile?.studentNameLong = json.getString("studentName")
|
||||||
profile.studentNameLong = data.getString("studentName")
|
val nameParts = json.getString("studentName")?.split(" ")?.toTypedArray()
|
||||||
val nameParts = data.getString("studentName")?.split(" ")?.toTypedArray()
|
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||||
profile.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
|
||||||
onSuccess()
|
onSuccess()
|
||||||
} catch (e: NullPointerException) {
|
} catch (e: NullPointerException) {
|
||||||
e.printStackTrace()
|
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 {
|
} 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) {
|
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()
|
.build()
|
||||||
|
@ -3,15 +3,21 @@ package pl.szczodrzynski.edziennik.api.v2.models
|
|||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.core.util.isNotEmpty
|
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.datamodels.*
|
||||||
import pl.szczodrzynski.edziennik.models.Date
|
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 loginMethods = mutableListOf<Int>()
|
||||||
|
|
||||||
val teacherList: LongSparseArray<Teacher> = LongSparseArray()
|
val teacherList = LongSparseArray<Teacher>()
|
||||||
val subjectList: LongSparseArray<Subject> = LongSparseArray()
|
val subjectList = LongSparseArray<Subject>()
|
||||||
val teamList = mutableListOf<Team>()
|
val teamList = mutableListOf<Team>()
|
||||||
val lessonList = mutableListOf<Lesson>()
|
val lessonList = mutableListOf<Lesson>()
|
||||||
val lessonChangeList = mutableListOf<LessonChange>()
|
val lessonChangeList = mutableListOf<LessonChange>()
|
||||||
@ -28,16 +34,20 @@ data class DataStore(private val appDb: AppDb, val profileId: Int) {
|
|||||||
val metadataList = mutableListOf<Metadata>()
|
val metadataList = mutableListOf<Metadata>()
|
||||||
val messageMetadataList = mutableListOf<Metadata>()
|
val messageMetadataList = mutableListOf<Metadata>()
|
||||||
|
|
||||||
|
private val db by lazy { app.db }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
|
|
||||||
appDb.teacherDao().getAllNow(profileId).forEach { teacher ->
|
if (profile != null) {
|
||||||
|
db.teacherDao().getAllNow(profile.id).forEach { teacher ->
|
||||||
teacherList.put(teacher.id, teacher)
|
teacherList.put(teacher.id, teacher)
|
||||||
}
|
}
|
||||||
appDb.subjectDao().getAllNow(profileId).forEach { subject ->
|
db.subjectDao().getAllNow(profile.id).forEach { subject ->
|
||||||
subjectList.put(subject.id, subject)
|
subjectList.put(subject.id, subject)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*val teacher = teachers.byNameFirstLast("Jan Kowalski") ?: Teacher(1, 1, "", "").let {
|
/*val teacher = teachers.byNameFirstLast("Jan Kowalski") ?: Teacher(1, 1, "", "").let {
|
||||||
teachers.add(it)
|
teachers.add(it)
|
||||||
@ -67,57 +77,60 @@ data class DataStore(private val appDb: AppDb, val profileId: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveData() {
|
fun saveData() {
|
||||||
|
if (profile == null)
|
||||||
|
return
|
||||||
|
|
||||||
if (teacherList.isNotEmpty()) {
|
if (teacherList.isNotEmpty()) {
|
||||||
val tempList: ArrayList<Teacher> = ArrayList()
|
val tempList: ArrayList<Teacher> = ArrayList()
|
||||||
teacherList.forEach { _, teacher ->
|
teacherList.forEach { _, teacher ->
|
||||||
tempList.add(teacher)
|
tempList.add(teacher)
|
||||||
}
|
}
|
||||||
appDb.teacherDao().addAll(tempList)
|
db.teacherDao().addAll(tempList)
|
||||||
}
|
}
|
||||||
if (subjectList.isNotEmpty()) {
|
if (subjectList.isNotEmpty()) {
|
||||||
val tempList: ArrayList<Subject> = ArrayList()
|
val tempList: ArrayList<Subject> = ArrayList()
|
||||||
subjectList.forEach { _, subject ->
|
subjectList.forEach { _, subject ->
|
||||||
tempList.add(subject)
|
tempList.add(subject)
|
||||||
}
|
}
|
||||||
appDb.subjectDao().addAll(tempList)
|
db.subjectDao().addAll(tempList)
|
||||||
}
|
}
|
||||||
if (teamList.isNotEmpty())
|
if (teamList.isNotEmpty())
|
||||||
appDb.teamDao().addAll(teamList)
|
db.teamDao().addAll(teamList)
|
||||||
if (lessonList.isNotEmpty()) {
|
if (lessonList.isNotEmpty()) {
|
||||||
appDb.lessonDao().clear(profileId)
|
db.lessonDao().clear(profile.id)
|
||||||
appDb.lessonDao().addAll(lessonList)
|
db.lessonDao().addAll(lessonList)
|
||||||
}
|
}
|
||||||
if (lessonChangeList.isNotEmpty())
|
if (lessonChangeList.isNotEmpty())
|
||||||
appDb.lessonChangeDao().addAll(lessonChangeList)
|
db.lessonChangeDao().addAll(lessonChangeList)
|
||||||
if (gradeCategoryList.isNotEmpty())
|
if (gradeCategoryList.isNotEmpty())
|
||||||
appDb.gradeCategoryDao().addAll(gradeCategoryList)
|
db.gradeCategoryDao().addAll(gradeCategoryList)
|
||||||
if (gradeList.isNotEmpty()) {
|
if (gradeList.isNotEmpty()) {
|
||||||
appDb.gradeDao().clear(profileId)
|
db.gradeDao().clear(profile.id)
|
||||||
appDb.gradeDao().addAll(gradeList)
|
db.gradeDao().addAll(gradeList)
|
||||||
}
|
}
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
appDb.eventDao().removeFuture(profileId, Date.getToday())
|
db.eventDao().removeFuture(profile.id, Date.getToday())
|
||||||
appDb.eventDao().addAll(eventList)
|
db.eventDao().addAll(eventList)
|
||||||
}
|
}
|
||||||
if (eventTypeList.isNotEmpty())
|
if (eventTypeList.isNotEmpty())
|
||||||
appDb.eventTypeDao().addAll(eventTypeList)
|
db.eventTypeDao().addAll(eventTypeList)
|
||||||
if (noticeList.isNotEmpty()) {
|
if (noticeList.isNotEmpty()) {
|
||||||
appDb.noticeDao().clear(profileId)
|
db.noticeDao().clear(profile.id)
|
||||||
appDb.noticeDao().addAll(noticeList)
|
db.noticeDao().addAll(noticeList)
|
||||||
}
|
}
|
||||||
if (attendanceList.isNotEmpty())
|
if (attendanceList.isNotEmpty())
|
||||||
appDb.attendanceDao().addAll(attendanceList)
|
db.attendanceDao().addAll(attendanceList)
|
||||||
if (announcementList.isNotEmpty())
|
if (announcementList.isNotEmpty())
|
||||||
appDb.announcementDao().addAll(announcementList)
|
db.announcementDao().addAll(announcementList)
|
||||||
if (messageList.isNotEmpty())
|
if (messageList.isNotEmpty())
|
||||||
appDb.messageDao().addAllIgnore(messageList)
|
db.messageDao().addAllIgnore(messageList)
|
||||||
if (messageRecipientList.isNotEmpty())
|
if (messageRecipientList.isNotEmpty())
|
||||||
appDb.messageRecipientDao().addAll(messageRecipientList)
|
db.messageRecipientDao().addAll(messageRecipientList)
|
||||||
if (messageRecipientIgnoreList.isNotEmpty())
|
if (messageRecipientIgnoreList.isNotEmpty())
|
||||||
appDb.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
db.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
||||||
if (metadataList.isNotEmpty())
|
if (metadataList.isNotEmpty())
|
||||||
appDb.metadataDao().addAllIgnore(metadataList)
|
db.metadataDao().addAllIgnore(metadataList)
|
||||||
if (messageMetadataList.isNotEmpty())
|
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 loginType type of the e-register this endpoint handles
|
||||||
* @param endpointId a unique ID of this endpoint
|
* @param endpointId a unique ID of this endpoint
|
||||||
* @param featureIds a [List] of [Feature]s (their IDs) this endpoint can download
|
* @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 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].
|
* @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(
|
class Endpoint(
|
||||||
val loginType: Int,
|
val loginType: Int,
|
||||||
val endpointId: Int,
|
val endpointId: Int,
|
||||||
val featureIds: List<Int>,
|
val featureIds: List<Int>?,
|
||||||
val endpointClass: Class<*>,
|
val endpointClass: Class<*>,
|
||||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
||||||
)
|
)
|
@ -1,6 +1,5 @@
|
|||||||
package pl.szczodrzynski.edziennik.api.v2.models
|
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>>) {
|
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 loginType type of the e-register this login method handles
|
||||||
* @param loginMethodId a unique ID of this login method
|
* @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
|
* @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 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].
|
* @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(
|
class LoginMethod(
|
||||||
val loginType: Int,
|
val loginType: Int,
|
||||||
val loginMethodId: Int,
|
val loginMethodId: Int,
|
||||||
val featureIds: List<Int>,
|
val featureIds: List<Int>?,
|
||||||
val loginMethodClass: Class<*>,
|
val loginMethodClass: Class<*>,
|
||||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
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.MainActivity;
|
||||||
import pl.szczodrzynski.edziennik.api.AppError;
|
import pl.szczodrzynski.edziennik.api.AppError;
|
||||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
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.CardLuckyNumberBinding;
|
||||||
import pl.szczodrzynski.edziennik.databinding.CardUpdateBinding;
|
import pl.szczodrzynski.edziennik.databinding.CardUpdateBinding;
|
||||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding;
|
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding;
|
||||||
@ -115,45 +116,18 @@ public class HomeFragment extends Fragment {
|
|||||||
return true;
|
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.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||||
b.composeButton.setOnClickListener((v -> {
|
b.composeButton.setOnClickListener((v -> {
|
||||||
startActivity(new Intent(activity, MessagesComposeActivity.class));
|
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()));
|
//((TextView)v.findViewById(R.id.nextSync)).setText(getString(R.string.next_sync_format,Time.fromMillis(app.appJobs.syncJobTime).getStringHMS()));
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user